Binary Clock, Part 2

Atoms, Electrons, Photons
[vc_row][vc_column][vc_column_text]

The long awaited part 2 of this blog post has finally arrived! Though I’ve been tinkering on this project for the past two years, I decided to write it up to coincide with the outrageous arrest of 14 year old tinkerer Ahmed Mohamed who was hand cuffed because his teacher thought his electronic clock project looked like a bomb. This binary clock project of mine ended up being a personal electronic circuit design introduction course. You can download all the relevant files here if you want to make your own.<br />I forgot what the original inspiration was but what I’m ending up with is a working binary clock on a custom printed circuit board. Ultimately, this project will involve fiber optics inside polished cement for a unique time piece but we’re not there yet… Here’s what I learned so far:

Bit shifters

A binary clock needs 20 individual blinky things and the arduino has less than that, so I needed to figure out a way to create more individually addressable outputs. The solution I found is a the 74HC595N chip that can turn two inputs into 8. In fact, you can wire them in series and they can provide you with any number of outputs in multiples of 8. I decided to use one to drive the hours display, one for the minutes, and one for the seconds.

There are tons of tutorials for them so it was fairly straight forward to get it working.

Keeping time

While you can make a timer with just an arduino, it is not very accurate and it has no way to keep the clock going if you unplug the power. I used a rtc1307 chip which is designed for just this purpose. It keeps time accurately and uses a small battery to continue keeping time when the power is disconnected.

Again, there is an arduino library available and a good amount of tutorials out there so it wasn’t too hard to test it and incorporate it in the build.

Removing the arduino

Eventually, since I wanted to end up with a single circuit board, I didn’t want to have to plug anyting into an arduino. Once again, the internet is a wonderful resource which allowed me to figure out how put only the arduino components I needed onto a bread board. I can upload the code onto the chip by putting it on an arduino, and then pull it off of there to mount it directly onto the breadboard.

Code

The clock can be set to one of 4 modes: display time, set hours, set minutes or set seconds. There are two buttons. One button toggles between all the different modes, while the other increments the count of the hours, minutes, and seconds when they are in their respective mode.

#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>

//Pin connected to ST_CP of 74HC595
const int latchPin = 8;
//Pin connected to SH_CP of 74HC595
const int clockPin = 12;
////Pin connected to DS of 74HC595
const int dataPin = 11;

//Pins for setting the time
const int button0Pin = 5;
const int button1Pin = 6;

// Variables for debounce
int button0State;
int button1State;
int previousButton0State = LOW;
int previousButton1State = LOW;

long lastDebounce0Time = 0; // the last time the output pin was toggled
long lastDebounce1Time = 0; // the last time the output pin was toggled
long debounceDelay = 50; // the debounce time; increase if the output flickers
int button0Mode = 0;

// object to communicate with RTC
tmElements_t tm;

void setup() {
// Setup pins for the shift register
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);

// Setup pins for manual time setting
pinMode(button0Pin, INPUT);
pinMode(button1Pin, INPUT);
}

void loop() {

RTC.read(tm);
// button 0 can be in display time, hour set, minute set, and second set modes.
//
if( button0Mode == 0){
timeDisplayMode();
}
else if( button0Mode == 1){
setHourMode();
}
else if( button0Mode == 2){
setMinuteMode();
}
else if( button0Mode == 3){
setSecondMode();
}

//
// mode switching
//
// Just after a button is pushed or released, there is noise where the value returned is 0/1 random.
// debouncing consists of reading the incomming value and, if it has changed, storing the time the change was noticed.
// It then continues to check and if after a certain amount of time (delay), it reads the input value and it is still the changed value
// noticed before, then it means that an actual state change happened.
int reading0 = digitalRead(button0Pin);
// this only happens when the input value is different from the last time the value was read
if (reading0 != previousButton0State) {
lastDebounce0Time = millis();
}
// we only enter this loop if the returned value hasn’t changed in a while, which means we are not in the noisy transition
if ((millis() – lastDebounce0Time) > debounceDelay) {
// if we are in here, it means we got two similar readings.
if (reading0 != button0State) {
// if the two similar readings we got are different from the stored state, we must have changed
button0State = reading0;
if(reading0 == HIGH){
button0Mode = (button0Mode+1)%4;
}
}
}
previousButton0State = reading0;

delay(100);

}

void timeDisplayMode(){
int sc = tm.Second;
int mn = tm.Minute;
int hr = tm.Hour;
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, setTimeBits(sc,3));
shiftOut(dataPin, clockPin, MSBFIRST, setTimeBits(mn,3));
shiftOut(dataPin, clockPin, MSBFIRST, setTimeBits(hr,2));
digitalWrite(latchPin, HIGH);
}

void setHourMode(){
int reading1 = digitalRead(button1Pin);
if (reading1 != previousButton1State) {
// reset the debouncing timer
lastDebounce1Time = millis();
}
if ((millis() – lastDebounce1Time) > debounceDelay) {
if (reading1 != button1State) {
button1State = reading1;
if(reading1 == HIGH){
tm.Hour = (tm.Hour+1)%24;
RTC.write(tm);
}
}
}
previousButton1State = reading1;

digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, setTimeBits(0,3));
shiftOut(dataPin, clockPin, MSBFIRST, setTimeBits(0,3));
shiftOut(dataPin, clockPin, MSBFIRST, setTimeBits(tm.Hour,2));
digitalWrite(latchPin, HIGH);
}

void setMinuteMode(){
int reading1 = digitalRead(button1Pin);
if (reading1 != previousButton1State) {
// reset the debouncing timer
lastDebounce1Time = millis();
}
if ((millis() – lastDebounce1Time) > debounceDelay) {
if (reading1 != button1State) {
button1State = reading1;
if(reading1 == HIGH){
tm.Minute = (tm.Minute+1)%60;
RTC.write(tm);
}
}
}
previousButton1State = reading1;

digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, setTimeBits(0,3));
shiftOut(dataPin, clockPin, MSBFIRST, setTimeBits(tm.Minute,3));
shiftOut(dataPin, clockPin, MSBFIRST, setTimeBits(0,2));
digitalWrite(latchPin, HIGH);
}

void setSecondMode(){
int reading1 = digitalRead(button1Pin);
if (reading1 != previousButton1State) {
// reset the debouncing timer
lastDebounce1Time = millis();
}
if ((millis() – lastDebounce1Time) > debounceDelay) {
if (reading1 != button1State) {
button1State = reading1;
if(reading1 == HIGH){
tm.Second = (tm.Second+1)%60;
RTC.write(tm);
}
}
}
previousButton1State = reading1;

digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, setTimeBits(tm.Second,3));
shiftOut(dataPin, clockPin, MSBFIRST, setTimeBits(0,3));
shiftOut(dataPin, clockPin, MSBFIRST, setTimeBits(0,2));
digitalWrite(latchPin, HIGH);
}

// create binary value for each digit of the hour/minute/second number
// offset represents how many bits are used for the tens.
int setTimeBits(int n, int offset){
int n1 = n%10;
int n0 = (n-n1)/10;
return n0 | n1<<offset;
}

Schematic and board

Once the breadboard was working, I set out to sketch the circuit in Fritzing. While it’s not quite as intimidating as EAGLE cad, I ended up using the latter after running into some limitations with the former (I don’t remember what they were). There was a lot for me to learn there but, in the end, it’s conceptually pretty simple: all the pieces have to be connected together correctly. It’s just another way to represent the circuit. Once that was done, I started with the board. I laid out all the components and let the software automatically figure out how to create the correct traces.
One cool thing is that if you choose the correct electronic components in the software, all the size and shapes are properly represented when you are designing the board. It’s a huge pain in the ass to sort through all the libraries of components, though, specially when you don’t know what all the specs mean.

 

The eagle cad files are included in the download file at the top of this page.

Manufacturing the board

Super simple: just go online and find a service that will manufacture them. For this project, I used oshpark.com and dirtypcbs.com, which allow you to upload your designs right out of EAGLE cad. After a few weeks, you get your board in the mail, ready for you to solder the components on. I order my components from mouser.com, which allows you to save a collection of various components into a project specific list. Again, finding the right components amongst the tens of thousands they have available is really time consuming and annoying. But now, I have my parts list so I never have to go through that again if I want to solder up new versions of the board. The list of parts in included in the download file at the top of this page.

The ugly truth

If you were paying attention, you no doubt noticed in the preceding paragraph that I used two board manufacturers. That is because the first board layouts I had printed actually had shorts. I suppose it’s probably not that uncommon, but it’s really frustrating to upload your designs, order the boards, wait for them to be delivered, spend all this time soldering the board to find out it doesn’t work, and then it can be challenging to figure out where the wires are getting crossed. In the end, I spent about $150 on boards and parts that ended up not working. I guess that’s the cost of learning… My first two board designs were ordered through Oshpark, and the minimum order was 3, for about $50. The third order was done on dirtypcbs and was $25 for 10 boards. They feel cheaper and took forever to get delivered but you sure can’t beat the price.

 

Flashing Arduino bootloader with Teensy 2.0

Electrons

What

If, like me, you want to flash the arduino bootloader onto some blank ATMEGA328 chips on a breadboard and only have a teensy 2.0 on hand (because you’ve short circuited all the working ATMEGA chips you had and so can’t use your arduino), and, unlike me, you don’t have hours to spare trying all freaking possible software/hardware/wiring combination to get it working, here’s what worked for me. Also, since I didn’t want to bother with the crystal, capacitors and resistor, I went for the minimal setup.

Why

Because a chip with the bootloader already loaded costs $5 and a chip without costs $2. And also, really, just because…

How

  • I used arduino 1.0.6 on a macbook running osX 10.6 (For those running Yosemite, there are documented issues recognizing the USB port)
  • I downloaded Breadboard1-0-x.zip and installed the contained breadboard directory in the “hardware” folder of my sketches.
  • In arduino, load the ArduinoISP sketch from the examples, change the LED pin to 11 (#define LED_HB 11), select Teensy 2.0 as you board and upload the sketch
  • Wire up the ATMEGA as follows.
  • Relaunch arduino and for your board, select Tools > Boards > “ATmega328 on a breadboard (8 MHz internal clock)” and Tools > Programmer > “Arduino as ISP”
  • Select Tools > Burn Bootloader
  • Done!
  • This is basically the steps outlined in the official Arduino website, except for changing the LED pin to 11 in the ArduinoISP sketch and wiring the ATMEGA to the proper pins on the Teensy 2.0. (Note that you don’t even have to change the code to reflect the different pin numbers since they are referred to by their function rather than their number).

There

Here’s a picture and a schematic…

June’s pot harvest

Art, Atoms

This month, I am deciding to make bigger and heavier pots, but still keeping with the monolithic shapes. I was spurred into creative action by a cardboard tube I saw in a trash pile at work. I noticed it and a lightbulb flashed in my head; I immediately grabbed it, knowing exactly what I was going to do with it. The world is full of gifts indeed and I love the process of finding sudden and unexpected inspiration at random time. All you have to do is remain open, hone your discernment skills, and channel whatever comes your way. Also, I’m experimenting with black cement coloring and black river rocks on my old 6 inch round model.

Video Triptych

Uncategorized
[vc_row][vc_column][vc_column_text]

Building a synced video triptych from raspberry pi computers and laptop screens

A filmmaker friend, Natasha Maidoff, approached me to design a display device that would allow her to display a video triptych at the 2015 Venice Art Walk. The idea was to create a frame that would contain all the components necessary to play three different videos on three separate screens in perfect sync. It should be simple and should not need to be connected to a bunch of cables or computers. The goal was to hang it, plug it, turn it on and forget it… Oh, and did I mention it should not cost an arm and a leg?
Based on my previous tinkering activities, I felt that this project was within my reach and so I started researching parts. My first order was for 3 Raspberry Pi 2 mini computers, 3 replacement laptop LCD screens and the 3 driver boards they needed to be connected to the Pi’s HDMI output. Along with that, I got the various necessary AC adapters to power all this mess.

Framing and mounting the electronics

The first order of business was to create an aluminum frame to mount the screens to. I got some standard aluminum rods from home depot and cut them to size. I drilled some small holes in the vertical aluminum studs and mounted the screens by using the small screw holes along their edges that are designed for them to be mounted in the laptop. Next, I cut two horizontal struts that I screwed the vertical studs to and ended up with a nice sturdy frame that the screens were securely mounted to. For the top strut, I used an angle piece, and for the bottom strut, I used a plat piece that was wide enough to mount the electronics. A few holes, and 18 small bolts, nuts and screws later later, the electronics were on! I plugged everything in and it all lit up just fine…

 

[/vc_column_text][vc_column_text]

Networking the three Raspberry Pi

[/vc_column_text][vc_column_text] The next order of business was figuring out how to get the machines to talk to each other. The raspberry Pi comes with a set of GPIO pins that I could have wired to send signals back and forth between the machines, but it would have required a fair amount of coding and wiring to get the control I needed. Also, since I quickly realized I would need ethernet to log in and customize the raspbian operating system on each individual machine, I decided to piggy back on this and use OSC for communication over TCP/IP. I got a small USB hub, pried open the cheap plastic case, liberated the small electronic circuit housed therein and proceeded to mount it to the frame itself. I connected ethernet cables between the hub and the three machines, and also connected the hub to my home router which allowed me to connect to and set up the Raspberry Pies from my laptop.
For this to work reliably and predictably, I changed the Pies’ IP address to be static, and while I was there, I changed the hostnames, and set it up to automatically log in to the command line without loading the desktop interface.
To set up the static IP to 192.168.11.45, edit /etc/network/interfaces and replace:
iface wlan0 inet dhcp
with:

 

iface wlan0 inet static
address 192.168.11.45
netmask 255.255.255.0
gateway 192.168.11.1
network 192.168.11.1
broadcast 192.168.11.255

To setup the hostname, replace it to your desired name in /etc/hostname, and also list all the other hostnames with their static IPs in /etc/hosts.
Lastly, to log directly into the command line interface without having to enter a username and password, edit the file /etc/inittab and replace the line:
1:2345:respawn:/sbin/getty 115200 tty1
with:
1:2345:respawn:/bin/login -f pi tty1 /dev/tty1 2>&1

[/vc_column_text][vc_row_inner][vc_column_inner width=”1/2″][vc_column_text]

Getting rid of warts

All this electronickery runs on 12V and 5V DC, and typically, you use one of these a lovely black boxy power adapter for each component. At this point in the build, I had everything working but I was relying on 7 of these wall warts plugged into a power strip to get it all powered. I didn’t have room on the frame itself to mount all this crap and I didn’t want 7 wires coming out of it so I started looking into a better way to supply power. The monitors needed 12V and each seemed to be running along fine with a 2A supply. The Raspberry Pies and the ethernet hub each used 5V and 1A each at most. I searched on ebay and found 12V power supplies usually used for home LED lighting, and figured that getting one rated for 10 amps would be more than enough to cover the requirements of the frame. I also got a step down converter for the pieces that required 5V.
Wire time… AC power cord into 12V power supply, 3 sets of wires with DC power barrel jacks connecting the 12V output to each of the monitors, 1 set of wires connecting to the 12V to 5V step down converter. 5V output of the down converter to the raspberry pies and the ethernet hub. One of the challenges here was trying to solder wire to the micro USB plugs I had bought. It’s all way too small and I ended up with an ugly heap, kind f like Jeff Goldblum and the fly in “The Fly”, except with melted lead and plastic. In the end, I just bought some USB cables with the proper connection, cut them and rewired them to fit my need

[/vc_column_text][/vc_column_inner][vc_column_inner width=”1/2″][vc_column_text] [/vc_column_text][/vc_column_inner][/vc_row_inner][vc_column_text]

The Software

Auto start

I needed the movies to start automatically when the machines were done booting, so I modified the /home/pi/.bashrc file to run my main script whenever it was being accessed at the end of a boot sequence (I didn’t want to launch my movie playback script every time I logged in from another machine). I look for the $L1 environment variable that gets to “tty1” only when logging to the console from the boot sequence. I added the following at the top of .bashrc:

 

if [ “$L1” == “tty1” ]then
sudo /home/pi/video_player.py
fi
Movie playback

For movie playback, I made the obvious choice and used omxplayer which is custom written for the Raspberry Pi hardware and can play full 30fps HD video from the GPU, and there’s even a crude little library called pyomxplayer that allows control from python. In order to get the pyomxplayer library to run, I had to install the pexpect python library which allows it script to spawn and control the omxplayer process. Also, pyomxplayer tries to parse the text output by omxplayer but it seems like that part of the code has changed and causes the script to fail and exit so I had to remove that part of the code. I also added a function to allow me to rewind the movie. As soon as my script starts, omxplayer loads the appropriate movie file and pauses at the beginning.

 

Syncing the movies

As for syncing the start of the three movies, I used pyOSC to have the machines automatically establish a connection when they boot up and unpause the movies at the same instant when all three machines are ready. The basic process goes like this: I designate one machine to be the master and the two others to be slaves. When the master boots up, it first listens for a signal from each the slaves, and stays in this mode until it has heard from both. On their end, the slaves’ first action during launch is to send a signal to the master. As soon as the master has heard from both slaves, it tells the slaves to switch to a state where they listen to the master for commands. At this point, the master unpauses the movie it previously loaded and tells the slaves to do the same with theirs. Since omxplayer has no looping function I could find that worked for me, I have the master wait for the length of the movie and then rewind to movies to the beginning and start them playing over again.

 

Playing back from the RAM disk

In order to avoid continually reading from the SD card, I created a ram disk so my script could copy the movie file to it and allow omxplayer to play back from there.
I created the directory for the ram disk’s mount point:
sudo mkdir /var/ramdisk
and added the following to the /etc/fstab file:
ramdisk /var/ramdisk tmpfs nodev,nosuid,size=500M 0 0
The Raspberry Pi 2 comes with 1 GB of ram so I used half of it for the drive, which left plenty for the OS to run.

 

Timing issues

Fundamentally, pyomxplayer and the pexpect approach it uses is an ingenious but somewhat hacky way to control the process and it took me a long time to get everything to work properly. I found that if my script sent commands to omxplayer too fast, omxplayer would miss the command. I had to put a bunch of sleep statements in my code to pause and allow enough time for commands to get properly “heard” by the omxplayer process. Also, I added a long pause right after the movie is first loaded into omxplayer to make sure any residual and proc intensive boot process has a chance to finish and does not interfere with the responsiveness of each machine. It’s far from a robust setup; It’s basically a script that tells three machines to press the “play” button at the same time. Ultimately, though, I seemed to be able to get the movies to sync well enough across all three machines. Not guaranteed to be frame perfect every time but probably within one or two frames on a reliable basis. Ultimately, I would love for someone to write a true python API for omxplayer.

 

Powering off and rebooting through GPIO

Since the frame will be fully autonomous, it will not have a keyboard to allow an operator to properly power off the Raspberry Pies. This is a challenge because if you directly unplug the power to turn them off, the SD card will most likely get corrupted and you will not be able to reboot the machine. So, I needed to setup a simple way to cleanly shutdown the machines before turning the power off. I also wanted to be able to reboot if somehow something unexpected happened that threw the machine out of sync. So, I connected the master machine to a couple of switches and set the script up to power off or reboot if the GPIO interface detects a specific button press.

 

The code

Here is the code. You will need to install pyomxplayer, pexpect, and pyOSC. Also, depending on your version of omxplayer, you may need to modify pyomxplayer because of the way it attempts to parse omxplayer’s output. This script works for both the master and the slave based on the hostname. Here is the basic process:

When all machines boot up, they copy the relevant media to the ram drive, and launch it in omxplayer in a paused state
The slaves then go into a startup loop sending a “ready” address to the master until they hear back.
The master goes into a loop to check if both slaves are ready, listening for a “ready” address from each.
When the master determines that both slaves are ready, it sends a “listen” address to the slaves and the slaves come out of their startup loop.
From here on out, the master controls the slaves through OSC to unpause/pause/rewind the movies indefinitely.
The machines either reboot or shut down when the specific GPIO pin gets set on the master.

[/vc_column_text][/vc_column][/vc_row][vc_row][vc_column][vc_tta_accordion active_section=”1″ collapsible_all=”true”][vc_tta_section title=”CODE” tab_id=”1648521753811-8e2834d5-9e5d”][vc_raw_html]JTNDcHJlJTNFJTBBJTBBJTIzJTIxJTJGdXNyJTJGYmluJTJGcHl0aG9uJTBBJTBBaW1wb3J0JTIwT1NDJTBBaW1wb3J0JTIwdGhyZWFkaW5nJTJDJTIwc29ja2V0JTJDJTIwc2h1dGlsJTIwJTBBZnJvbSUyMHB5b214cGxheWVyJTIwaW1wb3J0JTIwT01YUGxheWVyJTBBZnJvbSUyMHRpbWUlMjBpbXBvcnQlMjBzbGVlcCUwQSUwQSUyNyUyNyUyNyUwQSUwQSUwQSUyNyUyNyUyNyUwQSUwQWhvc3RzJTIwJTNEJTIwJTdCJTI3bWFzdGVyJTI3JTNBJTI3MTkyLjE2OC4xMS40NSUyNyUyQyUyMCUyN3NsYXZlMSUyNyUzQSUyNzE5Mi4xNjguMTEuNDYlMjclMkMlMjAlMjdzbGF2ZTIlMjclM0ElMjcxOTIuMTY4LjExLjQ3JTI3JTdEJTBBbW92aWVzJTIwJTNEJTIwJTdCJTI3bWFzdGVyJTI3JTNBJTI3JTJGaG9tZSUyRnBpJTJGbWVkaWElMkZtb3ZpZV9sZi5tb3YlMjclMkMlMjAlMjdzbGF2ZTElMjclM0ElMjclMkZob21lJTJGcGklMkZtZWRpYSUyRm1vdmllX2NuLm1vdiUyNyUyQyUyMCUyN3NsYXZlMiUyNyUzQSUyNyUyRmhvbWUlMkZwaSUyRm1lZGlhJTJGbW92aWVfcnQubW92JTI3JTdEJTBBbW92aWVMZW5ndGglMjAlM0QlMjA2MCUyQTUlMEElMEFob3N0bmFtZSUyMCUzRCUyMHNvY2tldC5nZXRob3N0bmFtZSUyOCUyOSUwQSUwQXByaW50JTIwJTIyY29weWluZyUyMCUyNXMlMjB0byUyMCUyRnZhciUyRnJhbWRpc2slMjIlMjAlMjUlMjBtb3ZpZXMlNUJob3N0bmFtZSU1RCUwQXNodXRpbC5jb3B5JTI4bW92aWVzJTVCaG9zdG5hbWUlNUQlMkMlMjAlMjIlMkZ2YXIlMkZyYW1kaXNrJTJGJTIyJTI5JTBBbW92aWVzJTVCaG9zdG5hbWUlNUQlMjAlM0QlMjBtb3ZpZXMlNUJob3N0bmFtZSU1RC5yZXBsYWNlJTI4JTI3JTJGaG9tZSUyRnBpJTJGbWVkaWElMjclMkMlMjAlMjclMkZ2YXIlMkZyYW1kaXNrJTI3JTI5JTBBJTBBcHJpbnQlMjAlMjJwbGF5aW5nJTIwbW92aWUlMjBmcm9tJTIwJTI1cyUyMiUyMCUyNSUyMG1vdmllcyU1Qmhvc3RuYW1lJTVEJTBBb214JTIwJTNEJTIwT01YUGxheWVyJTI4bW92aWVzJTVCaG9zdG5hbWUlNUQlMjklMEFzbGVlcCUyODUlMjklMEFvbXgudG9nZ2xlX3BhdXNlJTI4JTI5JTBBc2xlZXAlMjgxJTI5JTBBb214LnJld2luZCUyOCUyOSUwQXNsZWVwJTI4MSUyOSUwQSUwQSUwQWRlZiUyMHJlYm9vdCUyOCUyOSUzQSUwQSUyMCUyMCUyMCUyMGNvbW1hbmQlMjAlM0QlMjAlMjIlMkZ1c3IlMkZiaW4lMkZzdWRvJTIwJTJGc2JpbiUyRnNodXRkb3duJTIwLXIlMjBub3clMjIlMEElMjAlMjAlMjAlMjBpbXBvcnQlMjBzdWJwcm9jZXNzJTBBJTIwJTIwJTIwJTIwcHJvY2VzcyUyMCUzRCUyMHN1YnByb2Nlc3MuUG9wZW4lMjhjb21tYW5kLnNwbGl0JTI4JTI5JTJDJTIwc3Rkb3V0JTNEc3VicHJvY2Vzcy5QSVBFJTI5JTBBJTIwJTIwJTIwJTIwb3V0cHV0JTIwJTNEJTIwcHJvY2Vzcy5jb21tdW5pY2F0ZSUyOCUyOSU1QjAlNUQlMEElMjAlMjAlMjAlMjBwcmludCUyMG91dHB1dCUwQSUwQWRlZiUyMHBvd2Vyb2ZmJTI4JTI5JTNBJTBBJTIwJTIwJTIwJTIwY29tbWFuZCUyMCUzRCUyMCUyMiUyRnVzciUyRmJpbiUyRnN1ZG8lMjAlMkZzYmluJTJGc2h1dGRvd24lMjAtaCUyMG5vdyUyMiUwQSUyMCUyMCUyMCUyMGltcG9ydCUyMHN1YnByb2Nlc3MlMEElMjAlMjAlMjAlMjBwcm9jZXNzJTIwJTNEJTIwc3VicHJvY2Vzcy5Qb3BlbiUyOGNvbW1hbmQuc3BsaXQlMjglMjklMkMlMjBzdGRvdXQlM0RzdWJwcm9jZXNzLlBJUEUlMjklMEElMjAlMjAlMjAlMjBvdXRwdXQlMjAlM0QlMjBwcm9jZXNzLmNvbW11bmljYXRlJTI4JTI5JTVCMCU1RCUwQSUyMCUyMCUyMCUyMHByaW50JTIwb3V0cHV0JTBBJTBBJTBBaWYlMjBob3N0bmFtZSUyMCUzRCUzRCUyMCUyN21hc3RlciUyNyUzQSUwQSUwOWRlZiUyMGdwaW9fY2hlY2slMjglMjklM0ElMEElMDklMDlpbXBvcnQlMjBSUGkuR1BJTyUyMGFzJTIwR1BJTyUwQSUwOSUwOUdQSU8uc2V0bW9kZSUyOEdQSU8uQkNNJTI5JTBBJTBBJTA5JTA5R1BJTy5zZXR1cCUyODIzJTJDJTIwR1BJTy5JTiUyQyUyMHB1bGxfdXBfZG93biUzREdQSU8uUFVEX1VQJTI5JTBBJTA5JTA5R1BJTy5zZXR1cCUyODI0JTJDJTIwR1BJTy5JTiUyQyUyMHB1bGxfdXBfZG93biUzREdQSU8uUFVEX1VQJTI5JTBBJTA5JTA5d2hpbGUlMjBUcnVlJTNBJTBBJTA5JTA5JTIwJTIwJTIwJTIwaW5wdXRfc3RhdGUlMjAlM0QlMjBHUElPLmlucHV0JTI4MjMlMjklMEElMDklMDklMjAlMjAlMjAlMjBpZiUyMGlucHV0X3N0YXRlJTIwJTNEJTNEJTIwRmFsc2UlM0ElMEElMDklMDklMDlwcmludCUyOCUyN0RldGVjdGVkJTIwYSUyMHJlYm9vdCUyMHJlcXVlc3QlM0ElMjBCdXR0b24lMjAyMyUyMFByZXNzZWQlMjclMjklMEElMDklMDklMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBzZW5kX3JlYm9vdCUyOHNsYXZlcyU1QiUyN3NsYXZlMSUyNyU1RCU1QjIlNUQlMjklMEElMDklMDklMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBzZW5kX3JlYm9vdCUyOHNsYXZlcyU1QiUyN3NsYXZlMiUyNyU1RCU1QjIlNUQlMjklMEElMDklMDklMDlzbGVlcCUyOC4zJTI5JTBBJTA5JTA5JTA5cmVib290JTI4JTI5JTBBJTBBJTA5JTA5JTIwJTIwJTIwJTIwaW5wdXRfc3RhdGUlMjAlM0QlMjBHUElPLmlucHV0JTI4MjQlMjklMEElMDklMDklMjAlMjAlMjAlMjBpZiUyMGlucHV0X3N0YXRlJTIwJTNEJTNEJTIwRmFsc2UlM0ElMEElMDklMDklMDlwcmludCUyOCUyN0RldGVjdGVkJTIwYSUyMHBvd2Vyb2ZmJTIwcmVxdWVzdCUzQSUyMEJ1dHRvbiUyMDI0JTIwUHJlc3NlZCUyNyUyOSUwQSUwOSUwOSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMHNlbmRfcG93ZXJvZmYlMjhzbGF2ZXMlNUIlMjdzbGF2ZTElMjclNUQlNUIyJTVEJTI5JTBBJTA5JTA5JTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwc2VuZF9wb3dlcm9mZiUyOHNsYXZlcyU1QiUyN3NsYXZlMiUyNyU1RCU1QjIlNUQlMjklMEElMDklMDklMDlwcmludCUyOCUyN0J1dHRvbiUyMDI0JTIwUHJlc3NlZCUyNyUyOSUwQSUwOSUwOSUwOXNsZWVwJTI4LjMlMjklMEElMDklMDklMDlwb3dlcm9mZiUyOCUyOSUwQSUwOSUwOSUyMCUyMCUyMCUyMHNsZWVwJTI4LjElMjklMEElMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBncGlvX3RocmVhZCUyMCUzRCUyMHRocmVhZGluZy5UaHJlYWQlMjh0YXJnZXQlM0RncGlvX2NoZWNrJTI5JTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwZ3Bpb190aHJlYWQuc3RhcnQlMjglMjklMEElMEElMDklMjMlMjBzZW5kJTIwbGlzdGVuJTBBJTA5ZGVmJTIwc2VuZF9saXN0ZW4lMjhzbGF2ZVNlcnZlciUyOSUzQSUwQSUwOSUwOXByaW50JTIwJTIycXVlcnlpbmclMjBzbGF2ZSUyMiUyQyUyMHNsYXZlU2VydmVyJTBBJTA5JTA5bXNnJTIwJTNEJTIwT1NDLk9TQ01lc3NhZ2UlMjglMjklMEElMDklMDltc2cuc2V0QWRkcmVzcyUyOCUyMiUyRmxpc3RlbiUyMiUyOSUyMCUyMyUyMHNldCUyME9TQyUyMGFkZHJlc3MlMEElMDklMDltc2cuYXBwZW5kJTI4JTIyJTIwdGhlJTIwbWFzdGVyLiU1Q25UaGUlMjBtYXN0ZXIlMjBpcyUyMHBhdXNpbmclMjBmb3IlMjAyMCUyMHNlY29uZHMuJTIyJTI5JTIwJTIzJTIwaW50JTBBJTA5JTA5c2xhdmVTZXJ2ZXIuc2VuZCUyOG1zZyUyOSUyMCUyMyUyMHNlbmQlMjBpdCUyMSUwQSUwQSUwOSUyMyUyMHNlbmQlMjBwbGF5JTIwY29tbWFuZCUwQSUwOWRlZiUyMHNlbmRfcGxheSUyOHNsYXZlU2VydmVyJTI5JTNBJTBBJTA5JTA5cHJpbnQlMjAlMjJzZW5kaW5nJTIwcGxheSUyMHRvJTIyJTJDJTIwc2xhdmVTZXJ2ZXIlMEElMDklMDltc2clMjAlM0QlMjBPU0MuT1NDTWVzc2FnZSUyOCUyOSUwQSUwOSUwOW1zZy5zZXRBZGRyZXNzJTI4JTIyJTJGcGxheSUyMiUyOSUyMCUyMyUyMHNldCUyME9TQyUyMGFkZHJlc3MlMEElMDklMDltc2cuYXBwZW5kJTI4JTIydGhlJTIwbWFzdGVyJTIyJTI5JTIwJTIzJTIwaW50JTBBJTA5JTA5c2xhdmVTZXJ2ZXIuc2VuZCUyOG1zZyUyOSUyMCUyMyUyMHNlbmQlMjBpdCUyMSUwQSUwQSUwOSUyMyUyMHNlbmQlMjB0b2dnbGVfcGF1c2UlMjBjb21tYW5kJTBBJTA5ZGVmJTIwc2VuZF90b2dnbGVfcGF1c2UlMjhzbGF2ZVNlcnZlciUyOSUzQSUwQSUwOSUwOXByaW50JTIwJTIyc2VuZGluZyUyMHRvZ2dsZV9wYXVzZSUyMHRvJTIyJTJDJTIwc2xhdmVTZXJ2ZXIlMEElMDklMDltc2clMjAlM0QlMjBPU0MuT1NDTWVzc2FnZSUyOCUyOSUwQSUwOSUwOW1zZy5zZXRBZGRyZXNzJTI4JTIyJTJGdG9nZ2xlX3BhdXNlJTIyJTI5JTIwJTIzJTIwc2V0JTIwT1NDJTIwYWRkcmVzcyUwQSUwOSUwOW1zZy5hcHBlbmQlMjglMjJ0aGUlMjBtYXN0ZXIlMjIlMjklMjAlMjMlMjBpbnQlMEElMDklMDlzbGF2ZVNlcnZlci5zZW5kJTI4bXNnJTI5JTIwJTIzJTIwc2VuZCUyMGl0JTIxJTBBJTBBJTA5JTIzJTIwc2VuZCUyMHJld2luZCUyMGNvbW1hbmQlMEElMDlkZWYlMjBzZW5kX3Jld2luZCUyOHNsYXZlU2VydmVyJTI5JTNBJTBBJTA5JTA5cHJpbnQlMjAlMjJzZW5kaW5nJTIwcmV3aW5kJTIwdG8lMjIlMkMlMjBzbGF2ZVNlcnZlciUwQSUwOSUwOW1zZyUyMCUzRCUyME9TQy5PU0NNZXNzYWdlJTI4JTI5JTBBJTA5JTA5bXNnLnNldEFkZHJlc3MlMjglMjIlMkZyZXdpbmQlMjIlMjklMjAlMjMlMjBzZXQlMjBPU0MlMjBhZGRyZXNzJTBBJTA5JTA5bXNnLmFwcGVuZCUyOCUyMnRoZSUyMG1hc3RlciUyMiUyOSUyMCUyMyUyMGludCUwQSUwOSUwOXNsYXZlU2VydmVyLnNlbmQlMjhtc2clMjklMjAlMjMlMjBzZW5kJTIwaXQlMjElMEElMEElMDklMjMlMjBzZW5kJTIwcmVib290JTIwY29tbWFuZCUwQSUwOWRlZiUyMHNlbmRfcmVib290JTI4c2xhdmVTZXJ2ZXIlMjklM0ElMEElMDklMDlwcmludCUyMCUyMnNlbmRpbmclMjByZWJvb3QlMjB0byUyMiUyQyUyMHNsYXZlU2VydmVyJTBBJTA5JTA5bXNnJTIwJTNEJTIwT1NDLk9TQ01lc3NhZ2UlMjglMjklMEElMDklMDltc2cuc2V0QWRkcmVzcyUyOCUyMiUyRnJlYm9vdCUyMiUyOSUyMCUyMyUyMHNldCUyME9TQyUyMGFkZHJlc3MlMEElMDklMDltc2cuYXBwZW5kJTI4JTIydGhlJTIwbWFzdGVyJTIyJTI5JTIwJTIzJTIwaW50JTBBJTA5JTA5c2xhdmVTZXJ2ZXIuc2VuZCUyOG1zZyUyOSUyMCUyMyUyMHNlbmQlMjBpdCUyMSUwQSUwQSUwOSUyMyUyMHNlbmQlMjBwb3dlcm9mZiUyMGNvbW1hbmQlMEElMDlkZWYlMjBzZW5kX3Bvd2Vyb2ZmJTI4c2xhdmVTZXJ2ZXIlMjklM0ElMEElMDklMDlwcmludCUyMCUyMnNlbmRpbmclMjBwb3dlcm9mZiUyMHRvJTIyJTJDJTIwc2xhdmVTZXJ2ZXIlMEElMDklMDltc2clMjAlM0QlMjBPU0MuT1NDTWVzc2FnZSUyOCUyOSUwQSUwOSUwOW1zZy5zZXRBZGRyZXNzJTI4JTIyJTJGcG93ZXJvZmYlMjIlMjklMjAlMjMlMjBzZXQlMjBPU0MlMjBhZGRyZXNzJTBBJTA5JTA5bXNnLmFwcGVuZCUyOCUyMnRoZSUyMG1hc3RlciUyMiUyOSUyMCUyMyUyMGludCUwQSUwOSUwOXNsYXZlU2VydmVyLnNlbmQlMjhtc2clMjklMjAlMjMlMjBzZW5kJTIwaXQlMjElMEElMEElMDklMjMlMjBoYW5kbGVyJTIwZm9yJTIwcmVhZHklMjBhZGRyZXNzJTBBJTA5ZGVmJTIwcmVhZHlfaGFuZGxlciUyOGFkZHIlMkMlMjB0YWdzJTJDJTIwc3R1ZmYlMkMlMjBzb3VyY2UlMjklM0ElMEElMDklMDlpZiUyMG5vdCUyMHNsYXZlcyU1QnN0dWZmJTVCMCU1RCU1RCU1QjAlNUQlM0ElMEElMDklMDklMDlzbGF2ZXMlNUJzdHVmZiU1QjAlNUQlNUQlNUIwJTVEJTIwJTNEJTIwVHJ1ZSUwQSUwOSUwOSUwOXByaW50JTIwJTIyc2V0dGluZyUyMCUyNXMlMjB0byUyMHJlYWR5JTIyJTIwJTI1JTIwc3R1ZmYlNUIwJTVEJTBBJTBBJTA5JTIzJTIwc2V0dXAlMjBjbGllbnRzJTIwdG8lMjBzZW5kJTIwbWVzc2FnZXMlMjB0byUwQSUwOXNsYXZlc1JlYWR5JTIwJTNEJTIwRmFsc2UlMEElMDljMSUyMCUzRCUyME9TQy5PU0NDbGllbnQlMjglMjklMEElMDljMiUyMCUzRCUyME9TQy5PU0NDbGllbnQlMjglMjklMEElMDlzbGF2ZXMlMjAlM0QlMjAlN0IlMjdzbGF2ZTElMjclM0ElNUJGYWxzZSUyQyUyMCUyOGhvc3RzJTVCJTI3c2xhdmUxJTI3JTVEJTJDJTIwOTAwMCUyOSUyQyUyMGMxJTVEJTIwJTJDJTIwJTI3c2xhdmUyJTI3JTNBJTVCRmFsc2UlMkMlMjAlMjhob3N0cyU1QiUyN3NsYXZlMiUyNyU1RCUyQyUyMDkwMDAlMjklMkMlMjBjMiU1RCUyMCU3RCUwQSUwQSUwOSUyMyUyMHNldCUyMHVwJTIwc2VsZiUyMHRvJTIwcmVjZWl2ZSUyMG1lc3NhZ2VzJTBBJTA5cmVjZWl2ZV9hZGRyZXNzJTIwJTNEJTIwaG9zdHMlNUIlMjdtYXN0ZXIlMjclNUQlMkMlMjA5MDAwJTBBJTA5cyUyMCUzRCUyME9TQy5PU0NTZXJ2ZXIlMjhyZWNlaXZlX2FkZHJlc3MlMjklMjAlMjMlMjBiYXNpYyUwQSUwOXMuYWRkRGVmYXVsdEhhbmRsZXJzJTI4JTI5JTBBJTA5cy5hZGRNc2dIYW5kbGVyJTI4JTIyJTJGcmVhZHklMjIlMkMlMjByZWFkeV9oYW5kbGVyJTI5JTIwJTIzJTIwYWRkaW5nJTIwb3VyJTIwZnVuY3Rpb24lMEElMEElMDklMjMlMjBTdGFydCUyME9TQ1NlcnZlciUwQSUwOXByaW50JTIwJTIyJTVDblN0YXJ0aW5nJTIwT1NDU2VydmVyLiUyMFVzZSUyMGN0cmwtQyUyMHRvJTIwcXVpdC4lMjIlMEElMDlzdCUyMCUzRCUyMHRocmVhZGluZy5UaHJlYWQlMjglMjB0YXJnZXQlMjAlM0QlMjBzLnNlcnZlX2ZvcmV2ZXIlMjAlMjklMEElMDlzdC5zdGFydCUyOCUyOSUwQSUwQSUwOSUyMyUyMHNldCUyMHVwJTIwY2xpZW50cyUyMHRvJTIwc2VuZCUyMG1lc3NhZ2VzJTIwdG8lMEElMDlzbGF2ZXMlNUIlMjdzbGF2ZTElMjclNUQlNUIyJTVELmNvbm5lY3QlMjglMjBzbGF2ZXMlNUIlMjdzbGF2ZTElMjclNUQlNUIxJTVEJTIwJTI5JTIwJTIzJTIwc2V0JTIwdGhlJTIwYWRkcmVzcyUyMGZvciUyMGFsbCUyMGZvbGxvd2luZyUyMG1lc3NhZ2VzJTBBJTA5c2xhdmVzJTVCJTI3c2xhdmUyJTI3JTVEJTVCMiU1RC5jb25uZWN0JTI4JTIwc2xhdmVzJTVCJTI3c2xhdmUyJTI3JTVEJTVCMSU1RCUyMCUyOSUyMCUyMyUyMHNldCUyMHRoZSUyMGFkZHJlc3MlMjBmb3IlMjBhbGwlMjBmb2xsb3dpbmclMjBtZXNzYWdlcyUwQSUwQSUwOSUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUwQSUwOSUyMyUyMGVzdGFibGlzaCUyMGNvbW11bmljYXRpb24lMEElMDklMEElMDlwcmludCUyMCUyMk1hc3RlciUyMGlzJTIwd2FpdGluZyUyMHRvJTIwaGVhciUyMGZyb20lMjB0aGUlMjBzbGF2ZXMuJTIyJTBBJTA5JTIzJTIwVGhlJTIwbWFzdGVyJTIwd2FpdHMlMjB1bnRpbCUyMGJvdGglMjBzbGF2ZXMlMjBhcmUlMjByZWFkeSUwQSUwOXdoaWxlJTIwbm90JTIwc2xhdmVzUmVhZHklM0ElMEElMDklMDlzbGVlcCUyOC4wMSUyOSUwQSUwOSUwOWlmJTIwc2xhdmVzJTVCJTI3c2xhdmUxJTI3JTVEJTVCMCU1RCUyMGFuZCUyMHNsYXZlcyU1QiUyN3NsYXZlMiUyNyU1RCU1QjAlNUQlM0ElMEElMDklMDklMDlzbGF2ZXNSZWFkeSUyMCUzRCUyMFRydWUlMEElMDlwcmludCUyMCUyMlRoZSUyMG1hc3RlciUyMGhhcyUyMGhlYXJkJTIwZnJvbSUyMGJvdGglMjBzbGF2ZXMlMjIlMEElMEElMDklMjMlMjBUaGUlMjBtYXN0ZXIlMjB0ZWxscyUyMHRoZSUyMHNsYXZlcyUyMHRvJTIwbGlzdGVuJTBBJTA5c2VuZF9saXN0ZW4lMjhzbGF2ZXMlNUIlMjdzbGF2ZTElMjclNUQlNUIyJTVEJTI5JTBBJTA5c2VuZF9saXN0ZW4lMjhzbGF2ZXMlNUIlMjdzbGF2ZTIlMjclNUQlNUIyJTVEJTI5JTBBJTA5cHJpbnQlMjAlMjJUaGUlMjBtYXN0ZXIlMjBoYXMlMjB0b2xkJTIwdGhlJTIwc2xhdmVzJTIwdG8lMjBsaXN0ZW4lMjIlMEElMDlwcmludCUyMCUyMlBhdXNpbmclMjBmb3IlMjAyMCUyMHNlY29uZHMlMjIlMEElMEElMDklMjMlMjBjYXRjaCUyMG91ciUyMGJyZWF0aCUwQSUwOXNsZWVwJTI4MjAlMjklMEElMEElMDklMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMEElMDklMjMlMjBtZWRpYSUyMGNvbnRyb2wlMEElMEElMDklMjMlMjB3ZSUyMGdvJTIwaW50byUyMGFuJTIwaW5maW5pdGUlMjBsb29wJTIwd2hlcmUlMjB3ZSUwQSUwOSUyMyUyMHVucGF1c2UlMkMlMjB3YWl0JTIwZm9yJTIwdGhlJTIwbW92aWUlMjBsZW5ndGglMEElMDklMjMlMjBwYXVzZSUyQyUyMHdhaXQlMkMlMjByZXdpbmQlMkMlMjB3YWl0JTJDJTIwdW5wYXVzZSUwQSUwOXByaW50JTIwJTIyZW50ZXJpbmclMjBtYWluJTIwbG9vcCUyMiUwQSUwOXdoaWxlJTIwVHJ1ZSUzQSUwQSUwOSUwOXNlbmRfdG9nZ2xlX3BhdXNlJTI4c2xhdmVzJTVCJTI3c2xhdmUxJTI3JTVEJTVCMiU1RCUyOSUwQSUwOSUwOXNlbmRfdG9nZ2xlX3BhdXNlJTI4c2xhdmVzJTVCJTI3c2xhdmUyJTI3JTVEJTVCMiU1RCUyOSUwQSUwOSUwOW9teC50b2dnbGVfcGF1c2UlMjglMjklMEElMDklMDlzbGVlcCUyOG1vdmllTGVuZ3RoJTI5JTBBJTA5JTA5c2VuZF90b2dnbGVfcGF1c2UlMjhzbGF2ZXMlNUIlMjdzbGF2ZTElMjclNUQlNUIyJTVEJTI5JTBBJTA5JTA5c2VuZF90b2dnbGVfcGF1c2UlMjhzbGF2ZXMlNUIlMjdzbGF2ZTIlMjclNUQlNUIyJTVEJTI5JTBBJTA5JTA5b214LnRvZ2dsZV9wYXVzZSUyOCUyOSUwQSUwOSUwOXNsZWVwJTI4MiUyOSUwQSUwOSUwOXNlbmRfcmV3aW5kJTI4c2xhdmVzJTVCJTI3c2xhdmUxJTI3JTVEJTVCMiU1RCUyOSUwQSUwOSUwOXNlbmRfcmV3aW5kJTI4c2xhdmVzJTVCJTI3c2xhdmUyJTI3JTVEJTVCMiU1RCUyOSUwQSUwOSUwOW9teC5yZXdpbmQlMjglMjklMEElMDklMDlzbGVlcCUyODIlMjklMEElMEFlbHNlJTNBJTBBJTA5dGhpc05hbWUlMjAlM0QlMjBob3N0bmFtZSUwQSUwOXRoaXNJUCUyMCUzRCUyMGhvc3RzJTVCaG9zdG5hbWUlNUQlMkMlMjA5MDAwJTBBJTA5bWFzdGVyU3RhdHVzJTIwJTNEJTIwJTdCJTI3YXdha2UlMjclM0ElNUJGYWxzZSU1RCUyQyUyMCUyN3BsYXklMjclM0ElNUJGYWxzZSU1RCU3RCUwQSUwOW1hc3RlckFkZHJlc3MlMjAlM0QlMjBob3N0cyU1QiUyN21hc3RlciUyNyU1RCUyQyUyMDkwMDAlMEElMEElMDlkZWYlMjBzZW5kX3JlYWR5JTI4YyUyOSUzQSUwQSUwOSUwOW1zZyUyMCUzRCUyME9TQy5PU0NNZXNzYWdlJTI4JTI5JTBBJTA5JTA5bXNnLnNldEFkZHJlc3MlMjglMjIlMkZyZWFkeSUyMiUyOSUyMCUyMyUyMHNldCUyME9TQyUyMGFkZHJlc3MlMEElMDklMDltc2cuYXBwZW5kJTI4dGhpc05hbWUlMjklMjAlMjMlMjBpbnQlMEElMDklMDl0cnklM0ElMEElMDklMDklMDljLnNlbmQlMjhtc2clMjklMEElMDklMDlleGNlcHQlM0ElMEElMDklMDklMDlwYXNzJTBBJTBBJTA5ZGVmJTIwbGlzdGVuX2hhbmRsZXIlMjhhZGQlMkMlMjB0YWdzJTJDJTIwc3R1ZmYlMkMlMjBzb3VyY2UlMjklM0ElMEElMDklMDlwcmludCUyMCUyMkklMjB3YXMlMjB0b2xkJTIwdG8lMjBsaXN0ZW4lMjBieSUyNXMlMjIlMjAlMjUlMjBzdHVmZiU1QjAlNUQlMEElMDklMDltYXN0ZXJTdGF0dXMlNUIlMjdhd2FrZSUyNyU1RCU1QjAlNUQlMjAlM0QlMjBUcnVlJTBBJTBBJTA5ZGVmJTIwcGxheV9oYW5kbGVyJTI4YWRkJTJDJTIwdGFncyUyQyUyMHN0dWZmJTJDJTIwc291cmNlJTI5JTNBJTBBJTA5JTA5cHJpbnQlMjAlMjJJJTIwd2FzJTIwdG9sZCUyMHRvJTIwcGxheSUyMGJ5JTIwJTI1cyUyMiUyMCUyNSUyMHN0dWZmJTVCMCU1RCUwQSUwOSUwOW1hc3RlclN0YXR1cyU1QiUyN3BsYXklMjclNUQlNUIwJTVEJTIwJTNEJTIwVHJ1ZSUwQSUwOSUwOSUwOSUwQSUwOWRlZiUyMHRvZ2dsZV9wYXVzZV9oYW5kbGVyJTI4YWRkJTJDJTIwdGFncyUyQyUyMHN0dWZmJTJDJTIwc291cmNlJTI5JTNBJTBBJTA5JTA5cHJpbnQlMjAlMjJJJTIwd2FzJTIwdG9sZCUyMHRvJTIwdG9nZ2xlX3BhdXNlJTIwYnklMjAlMjVzJTIyJTIwJTI1JTIwc3R1ZmYlNUIwJTVEJTBBJTA5JTA5b214LnRvZ2dsZV9wYXVzZSUyOCUyOSUwQSUwOSUwQSUwOWRlZiUyMHJld2luZF9oYW5kbGVyJTI4YWRkJTJDJTIwdGFncyUyQyUyMHN0dWZmJTJDJTIwc291cmNlJTI5JTNBJTBBJTA5JTA5cHJpbnQlMjAlMjJJJTIwd2FzJTIwdG9sZCUyMHRvJTIwcmV3aW5kJTIwYnklMjAlMjVzJTIyJTIwJTI1JTIwc3R1ZmYlNUIwJTVEJTBBJTA5JTA5b214LnJld2luZCUyOCUyOSUwQSUwOSUwOW1hc3RlclN0YXR1cyU1QiUyN2F3YWtlJTI3JTVEJTNERmFsc2UlMEElMEElMDlkZWYlMjByZWJvb3RfaGFuZGxlciUyOGFkZCUyQyUyMHRhZ3MlMkMlMjBzdHVmZiUyQyUyMHNvdXJjZSUyOSUzQSUwQSUwOSUwOXByaW50JTIwJTIySSUyMHdhcyUyMHRvbGQlMjB0byUyMHJlYm9vdCUyMGJ5JTIwJTI1cyUyMiUyMCUyNSUyMHN0dWZmJTVCMCU1RCUwQSUwOSUwOXJlYm9vdCUyOCUyOSUwQSUwOSUwQSUwOWRlZiUyMHBvd2Vyb2ZmX2hhbmRsZXIlMjhhZGQlMkMlMjB0YWdzJTJDJTIwc3R1ZmYlMkMlMjBzb3VyY2UlMjklM0ElMEElMDklMDlwcmludCUyMCUyMkklMjB3YXMlMjB0b2xkJTIwdG8lMjBwb3dlcm9mZiUyMGJ5JTIwJTI1cyUyMiUyMCUyNSUyMHN0dWZmJTVCMCU1RCUwQSUwOSUwOXBvd2Vyb2ZmJTI4JTI5JTBBJTBBJTBBJTA5JTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTBBJTA5JTIzJTIwY3JlYXRlJTIwYSUyMGNsaWVudCUyMHRvJTIwc2VuZCUyMG1lc3NhZ2VzJTIwdG8lMjBtYXN0ZXIlMEElMDljJTIwJTNEJTIwT1NDLk9TQ0NsaWVudCUyOCUyOSUwQSUwOWMuY29ubmVjdCUyOCUyMG1hc3RlckFkZHJlc3MlMjAlMjklMEElMEElMDklMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMEElMDklMjMlMjBsaXN0ZW4lMjB0byUyMG1lc3NhZ2VzJTIwZnJvbSUyMG1hc3RlciUwQSUwOXJlY2VpdmVfYWRkcmVzcyUyMCUzRCUyMHRoaXNJUCUwQSUwOXMlMjAlM0QlMjBPU0MuT1NDU2VydmVyJTI4cmVjZWl2ZV9hZGRyZXNzJTI5JTIwJTIzJTIwYmFzaWMlMEElMEElMDklMjMlMjBkZWZpbmUlMjBoYW5kbGVycyUwQSUwOXMuYWRkRGVmYXVsdEhhbmRsZXJzJTI4JTI5JTBBJTA5cy5hZGRNc2dIYW5kbGVyJTI4JTIyJTJGbGlzdGVuJTIyJTJDJTIwbGlzdGVuX2hhbmRsZXIlMjklMEElMDlzLmFkZE1zZ0hhbmRsZXIlMjglMjIlMkZwbGF5JTIyJTJDJTIwcGxheV9oYW5kbGVyJTI5JTBBJTA5cy5hZGRNc2dIYW5kbGVyJTI4JTIyJTJGdG9nZ2xlX3BhdXNlJTIyJTJDJTIwdG9nZ2xlX3BhdXNlX2hhbmRsZXIlMjklMEElMDlzLmFkZE1zZ0hhbmRsZXIlMjglMjIlMkZyZXdpbmQlMjIlMkMlMjByZXdpbmRfaGFuZGxlciUyOSUwQSUwOXMuYWRkTXNnSGFuZGxlciUyOCUyMiUyRnJlYm9vdCUyMiUyQyUyMHJlYm9vdF9oYW5kbGVyJTI5JTBBJTA5cy5hZGRNc2dIYW5kbGVyJTI4JTIyJTJGcG93ZXJvZmYlMjIlMkMlMjBwb3dlcm9mZl9oYW5kbGVyJTI5JTBBJTBBJTA5JTIzJTIwU3RhcnQlMjBPU0NTZXJ2ZXIlMEElMDlwcmludCUyMCUyMiU1Q25TdGFydGluZyUyME9TQ1NlcnZlci4lMjBVc2UlMjBjdHJsLUMlMjB0byUyMHF1aXQuJTIyJTBBJTA5c3QlMjAlM0QlMjB0aHJlYWRpbmcuVGhyZWFkJTI4JTIwdGFyZ2V0JTIwJTNEJTIwcy5zZXJ2ZV9mb3JldmVyJTIwJTI5JTBBJTA5c3Quc3RhcnQlMjglMjklMEElMEElMDlwcmludCUyMCUyMiUyNXMlMjBjb25uZWN0aW5nJTIwdG8lMjBtYXN0ZXIuJTIyJTIwJTI1JTIwaG9zdG5hbWUlMEElMDl3aGlsZSUyMFRydWUlM0ElMEElMDklMDklMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjNpJTIzJTIzJTBBJTA5JTA5JTIzJTIwa2VlcCUyMHNlbmRpbmclMjByZWFkeSUyMHNpZ25hbHMlMjB1bnRpbCUyMG1hc3RlciUyMHNlbmRzJTIwYSUyMG1lc3NhZ2UlMjAlMEElMDklMDklMjMlMjBvbiUyMHRoZSUyMCUyRmxpc3RlbiUyMGFkZHJlc3MlMjB3aGljaCUyMGdldHMlMjB1cyUyMG91dCUyMG9mJTIwdGhpcyUyMGxvb3AlMEElMDklMDl3aGlsZSUyMG5vdCUyMG1hc3RlclN0YXR1cyU1QiUyN2F3YWtlJTI3JTVEJTVCMCU1RCUzQSUwQSUwOSUwOSUwOXNsZWVwJTI4LjAxJTI5JTBBJTA5JTA5JTA5c2VuZF9yZWFkeSUyOGMlMjklMEElMEElMDklMDklMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMEElMDklMDklMjMlMjBvbmNlJTIwdGhlJTIwbWFzdGVyJTIwaGFzJTIwdGFrZW4lMjBjb250cm9sJTJDJTIwd2UlMjBkbyUyMG5vdGhpbmclMjAlMEElMDklMDklMjMlMjBhbmQlMjBsZXQlMjB0aGUlMjBtYXN0ZXIlMjBkcml2ZSUyMHBsYXliYWNrJTIwdGhyb3VnaCUyMGhhbmRsZXJzJTBBJTNDJTJGcHJlJTNF[/vc_raw_html][/vc_tta_section][/vc_tta_accordion][/vc_column][/vc_row][vc_row][vc_column][vc_column_text]

Framing

Pretty quickly in the process, I realized that with the amount of work I had on my plate, as well as my day job, I would not have the time to build a frame that would do justice to the project. Natasha brought in Hugo Garcia to help. We went back and forth between modern designs that would let you see through to the electronics and the more traditional framing approach we ended up settling on. Since the screens and computers were all mounted to the central aluminum structure, the process was not too difficult; it was just a matter of hanging a skin on it. Hugo came up with a cool Arts and Craft inspired box frame and an ingenious setup of brackets that sandwiched the electronics in place. The most sensitive part was getting precise measurements of the screens to make sure the CNC’d matte fit perfectly on the screens.
The last few details consisted of mounting the tactile switches connected to the GPIO pins for shutting down or rebooting the machines, soldering on a mini jack connected to the master Raspberry Pi and provide audio from the outside, and lastly, installing a main power switch for the whole unit.

[/vc_column_text][vc_column_text]

Hanging

Here it is… We’re very happy! The work looks great. After seeing Natasha’s piece running on it in perfect sync, we’re all very inspired to work with this tryptic format. There are so many ideas to explore. Since we’re hoping for this to sell at the auction for the Venice Family Clinic, we’re already planning to build another one for us to play with.

Parts list

3 raspberry pi 2
3 LTN156AT02-D02 Samsung 15.6″ WXGA replacement screens (ebay)
3 HDMI+DVI+VGA+Audio Controller Board Driver Kit for LTN156AT02 (ebay)
1 D-Link – 5-Port 10/100 Mbps Fast Ethernet Switch
DC 12V 10A Regulated Transformer Power Supply (typically used for LED strips)
DC-DC 12V/ 24V to 5V 10A Converter Step Down Regulator Module
Aluminum, mini usb cables, 3 ethernet cables, 3 ethernet cables, nuts and bolts, tactile switch, power switch, wire…

[/vc_column_text][/vc_column][/vc_row]

I’m a pot dealer in Venice Beach

Art, Atoms

These pots, or ones that look like it, are available for sale, ranging from $30 to $100. I hand polish them myself to a nice smooth finish with a cement grinder that reveals the pattern of the aggregate, and for the amount of labor I put in them, I really can’t afford to have you buy them, but hey: my house can only accommodate so many of them so I have to somehow get rid of them. I do not have a store set up but leave a message or email me and I’m sure we can figure out something.

Three raspberry pies talking to each other

Uncategorized

My current project involves three raspberry pies playing video in sync. For this to work, they need to communicate with each other so one of them can trigger the others. Using pyosc, they can do so over ethernet in a python script.

"""
For detailed info on pyOSC functionality check the OSC.py file
or run pydoc pyOSC.py. you can also get the docs by opening a python shell and doing
>>> import OSC
>>> help(OSC)

This is a simple setup for 3 machines to communicate together.

"""

import OSC
import time, threading, socket


ip = socket.gethostbyname(socket.gethostname())
if ip == '192.777.0.0':
    receive_address = '192.777.0.0', 9000
    send_address1 = '192.777.0.1', 9000
    send_address2 = '192.777.0.2', 9000
elif ip == '192.777.0.1':
    send_address1 = '192.777.0.0', 9000
    receive_address = '192.777.0.1', 9000
    send_address2 = '192.777.0.2', 9000
elif ip == '192.777.0.2':
    send_address1 = '192.777.0.0', 9000
    send_address2 = '192.777.0.1', 9000
    receive_address = '192.777.0.2', 9000



### OSC clients
# this sets up clients for this machine to send messages to
clients = []
clients.append(OSC.OSCClient())
clients.append(OSC.OSCClient())
clients[0].connect( send_address1 ) # set the address for all following messages
clients[1].connect( send_address2 ) # set the address for all following messages


### OSC recieve
# this sets up this machine to recieve messages
s = OSC.OSCServer(receive_address) # basic
s.addDefaultHandlers()

# define a message-handler function for the server to call.
def printing_handler(addr, tags, stuff, source):
    print "---"
    print "received new osc msg from %s" % OSC.getUrlStr(source)
    print "with addr : %s" % addr
    print "typetags %s" % tags
    print "data %s" % stuff
    print "---"

s.addMsgHandler("/print", printing_handler) # adding our function

# Start OSCServer
print "\nStarting OSCServer. Use ctrl-C to quit."
st = threading.Thread( target = s.serve_forever )
st.start()


# single message
msg = OSC.OSCMessage()
msg.setAddress("/print") # set OSC address
msg.append(44) # int
msg.append(4.5233) # float
msg.append( "the white cliffs of dover" ) # string
[c.send(msg) for c in clients] # send it!

# bundle : few messages sent together
# use them to send many different messages on every loop for instance in a game. saves CPU and it is faster
bundle = OSC.OSCBundle()
bundle.append(msg) # append prev mgs
bundle.append( {'addr':"/print", 'args':["bundled messages:", 2]} ) # and some more stuff ...
bundle.setAddress("/*print")
bundle.append( ("no,", 3, "actually.") )
[c.send(msg) for c in clients] # send it!

Hey! What happened to the giant camera?

Atoms

Good question. Yeah, yeah… I know: I said I was building a big 20×24 camera but I have written nothing about it in the last 4 months. Was I just a tease? Was I showing off before actually delivering the goods?
In a word: yes. I got to a place where “Things Got Complicated” and I wasn’t sure what the next smart step was. Solving the building challenges started to feel like work. So I did what sane people do when faced with challenges: I walked away… I’m sure it is an affront to some notion of puritanical work ethic dictating that one doggedly apply oneself to a problem until finally overcoming it. Cue in the inspirational music celebrating triumph over adversity, drink the cool-aid, master your id, pay your taxes.
Except we’re talking about Relentless Play, not Relentless Work. It’s about engaging in what feels good rather than bowing to some flawed abstract concept of what should be.


I am still very determined to see the project through; I just don’t feel it right now. I need to let it sit for a while and let the correct path forward bubble up into my consciousness on its own, specially since it will end up costing a a fair amount of time and money to make. Basically, my problem is I don’t know what the hell I’m doing. I bought some 80/20 extrusion to serve as a base and some linear bearing carriages for the lens mount and the film back to slide on but they are pretty heavy and I need to figure out a way to keep them steady. Also, I need to figure out what we are going to do about bellows. Whatever it is, it needs to be built well enough to not bleed a bunch of light in the camera and onto the plate.
Some people like to have a project fully planned out before they go into action. Me, I typically like to figure it out as I go along. In fact, once I’ve done something and have a clear idea on how to go from A to Z, I’m not really that interested anymore.
Anyway, I have a lot of other similarly on hold projects and I picked a few back up in the meantime so it’s not like I’m giving up.

From broken laptop to cool utility monitor

Art, Atoms, Electrons

Broken things are solutions looking for problems. They hold magic undiscovered potential. I hate throwing away broken things because I’m never sure I won’t be able to later re-purpose some part of them into something else. On a seemingly unrelated note, I’m often in need of plugging some random computer or video device in to a screen for testing and, up until now, I have had to swap cables on my desktop monitors or pull out some bulky crappy old monitor from the garage and find some temporary place for it while I use it. What I really want is a small lightweight monitor I can easily access and occasionally plug a Raspberry Pi or my linux server into, something that’s closer in size to a laptop screen than a big bulky desktop monitor and that will not take up desk space.

Cue in broken hardware

As luck would have it, my stupid cat likes to sleep on laptops. They provide a nice warm place and a soothing fan sound. Usually, the only repercussion of this fact is that I sometimes wake up in the morning with hair on the keyboard and the Google helpfully informing me that
thanks_google
In one particular instance however, I was using a hackintoshed Asus 1201N that was clearly not designed to support the weight of a house cat; I know because it never woke up from its night of feline suffocation. I took it apart to see what I could find but never did find the needle in that haystack; probably a shorted motherboard… In the closet of broken stuff it went.

A killer and his victim

Displays

I’m always thinking about creating different displays. I’m pretty bored with the standard monitor design and I’m always interested in challenges to the rectangle-in-a-sleek-shiny-enclosure status-quo which led me to learn that I could probably find hardware compatible with my broken laptop’s LCD panel. I took the laptop apart, got the part number of the LCD panel and eventually found the right board on ebay for about $30 (I searched for “HSD121PHW1 controller”, HSD121PHW1 being the panel’s model number). Two weeks later, the padded envelope with the telltale Chinese characters on it showed up in my mail mailbox and I immediately plugged it in to test it. Lo and behold, it worked!

From parts to a thing

Okay, so now, I actually have the parts I need to make that small monitor I’ve been wanting: a small LCD panel and a driver board I can plug any HDMI or DVI display into. The next step is putting it together in a cool, cheap and convenient way. I had been peripherally interested by Plexiglas for another project so I decided to try it as a mounting surface for this. I measured the width of the screen and driver board, as well as the height of the screen with and without the adjustment buttons, and got a couple pieces cut at my local plastic store (Santa Monica Plastics). I drilled some holes, mounted the various parts on the back using standoffs, and sandwiched them by screwing in the smaller piece of plexi in the front using longer standoffs.

Binary Clock, Part 1

Art, Electrons



Binary clocks are a family of ubiquitous geek toys which display each digit of the time using binary notation. If you do a search for "binary clock" in Google, you will see a nearly infinite number of implementations. The reason I like the whole genre is that a binary clock is an electronic system that claims to exist for the purpose of conveying information when in fact it's all about finding an obtuse excuse to make something blink. The delight of it is that it's completely impractical to read but the geeks don't care: the coolness of the blinky lights joyfully trumps any need to be practical.

Speaking of geeks, I've been wanting to look into this whole Angular.js framework thingy all those overly bearded tech-hipsters are talking about (when they are not crafting their own cheese or riding fixed wheeled bikes), and so I'm using this blog post as an excuse to program simple apps that illustrate the process I am talking about using Angular.

Displaying numbers in binary

You can see below how to calculate the value a binary number. It's pretty straight forward: a particular place can only be 0 or 1 and once you increment above that, you loop back to 0, add one onto the digit to the left, and if THAT one is already 1, it also loops back to 0 and the behavior ripples leftward.



binary number {{get8()}} {{get4()}} {{get2()}} {{get1()}}
x x x x
place 8 4 2 1
= = = =
total {{8*get8()}} + {{4*get4()}} + {{2*get2()}} + {{1*get1()}} = {{count}}

Notice that the highest number we can represent a maximum of 16 values with 4 b(inary dig)its. 8 bits can represent 256, 10 bits, 1024, and so on...

Displaying the time in binary

The following table shows how to display the time in binary format, with each digit represented by a four bit binary representation arranged in a column. The current time is {{getTheTime() | date:'mediumTime'}}, which you can see displayed in 24 hour format in the bottom row.

{{d}}

From math to art

Not comfortable with numbers? Replace the 1's with teale and the 0's with burn sienna, on a background of deep emerald. Bam! Suddenly, you've become an artist, conjuring a playful visual dance of colors on an abstract rhythmic canvas. You're a fucking genius!

{{d}}

(Note that since the highest number for the hours is 23, the first column never has to go above 2 and we really only need the bottom two places to represent that number. Similarly, the value of minutes and seconds only goes to 59 so the third and fifth columns only to represent the value 5, which can be done with only 3 bits.)

What's next?

Stay tuned... Part 2 describes how to build your very own binary clock, using LED's, chips, electricity, obsession, and patience.

Mangled Metaphors Medley Mayhem, Maybe?

Giggles

There is nothing that warms my heart more than someone mangling a metaphor during a boring work meeting. It’s the verbal equivalent of slapstick comedy. It’s a sudden and unexpected fail, usually involving a very serious and maybe slightly pompous speaker getting tangled up in fancy rhetorical footwork they clearly were not ready to take on.

The List

We’ll burn that bridge when we get to it.
It’s not rocket surgery.
Does the pope shit in the woods?
It will be a walk in the cake.
For all intensive purposes,…
If you can’t take the heat, spoil the soup.
We will jump off that bridge when we get to it.
You’ve got the tiger by the horns.
Up shit creek without a paddle.
Time wounds all heals.
The cows are coming home to roost.
Does a bear wear a funny hat?
You gotta take the balls by the horn.
Cut me some slacks!
That train has sailed.
The ship has left the station.
That’s a slippery door to open.
Flying by the seat of their tail.
Six of tom-ay-to, half a dozen of tom-ah-to.
You have to just roll with the flow.
Squeeze the lemon till the milk runs dry.
Catch two tigers with one toe.
I’m going to milk that lemon for all its worth.
Half of one, six dozen of another.
You don’t miss your water till hell freezes over.
Don’t count your horses before they hatch.
You’re counting your chickens before the cart.
Straight from the horse’s ass.
It’s more fun than shooting monkeys in a barrel.
You nailed it out of the park.
You gotta reap just what you saw.
You really pulled a rabbit out of your ass.