Category Archives: Projects

Oddtale – Writing with strangers

So to take a break in my writing, I decided to start a new project. It was first supposed to be an Easter project, but it turned out to take a lot more time than I first thought. It’s a game called “Oddtale” where anyone can register with their name and email (no password needed, yet) and write a chapter in the current story. Authors are picked at random from the current pool of registered users, and the one who gets picked can write as little or as much (there are limitations, but they are big enough to write an okay chapter) as they want. Each author, except the first one, gets a hint from the previous chapter, to make things a little easier.

One story has ten chapters, and when the current story finishes, it gets automatically published on the site for everyone to view. A few hours later, the next story starts and people can join and write on that one as well. I’m planning more advanced features like private/public writing groups for people who don’t want to wait to get picked in the main one, as well as more advanced writing tools like a wysiwyg editor with the support for bbcode tags. There are more features planned, but these two are the biggest ones that are currently in the works. I wont publish a new version for a while though as I want to see if the main idea with the site in its current state, can draw any attention. The game is pretty pointless if no one wants to play.

The address for the game is: https://oddtale.net/

Oh, and we also have a mascot (who you will see a lot more of if the game gets an active player base). The mascot was made by Nicole (Bunnico) on Fiverr.

Butterflylabs Single SC 60GH/s miner arrived

So, finally I got my bitcoin miner that I ordered on the 1st of February 2013.
I’m hoping that I will be able to make some profit out of it, but it’s mostly for fun, so even if I don’t, I’m still happy to just play around.

Anyway, so the first thing I did was to unpack the miner and just generally check it out before I plug it in, just to make sure that I don’t miss anything, like an important manual or such.
I could only find one thing, which was a switch between 110V and 220V, which felt pretty important since I live in Europe, so I made sure it was set to 220V.

Not much more than that, so I plugged it into the computer for a test run, and then plugged in the power to the miner, suddenly the power unit for the miner literally exploded into fire and smoke. Shocked and angry at the sight of what is currently happening before my eyes, I quickly unplugged everything and carried the PSU in the cables (carried it at the end of the cable as to not get burned from the fire, although rather small fire, it was mostly smoke) to the bathroom, where I threw it in the bathtub and showered it with water.

So, at that moment a lot of thoughts where running through my mind, one being “fuck” and another one being “maybe the miner is still intact!”.
The apartment smelled like shit from all the smoke, so I opened a window and went back to the miner to see what I could do.

A thing I noticed about the PSU that was comfortably placed in the bathtub, was that the little switched I flipped before, had fallen into the unit, and was no longer visible.
So I’m thinking that the switch being broken might have been the reason for the incident, but meh, I prefer to use my own PSU anyway, so it doesn’t matter much, except for the fact that my apartment almost got threatened there for a second.

Now, I’ve read about the miner a lot on the Butterflylabs forum before I got it, to see what other people where experiencing when they got it, and a lot of them did not get a power unit with the package, and thus had to get their own. So a normal PSU for any computer works, as long as it’s around 550W (actually I tried a 550W but it didn’t work, so not sure about that one, but it’s what I have read) and has two PCIe cables that can be used for the miner.

The PSU in my server is modular, so I went and fetched two PCIe cables from the “dungeon” and plugged it in.
And voila, it started!

So, this doesn’t say much actually, since there still might be damaged parts in it from the little explosion before, so I needed to check that first.
And a quick check at least showed me that the machine detected the miner.

cats@Teresa:~$ lsusb | grep -i ft
Bus 001 Device 002: ID 0403:6014 Future Technology Devices International, Ltd FT232H Single HS USB-UART/FIFO IC

cats@Teresa:~$ dmesg | tail
[ 1317.675589] ftdi_sio 1-6:1.0: device disconnected
[ 1317.677817] ftdi_sio 1-6:1.0: FTDI USB Serial Device converter detected
[ 1317.677859] usb 1-6: Detected FT232H
[ 1317.677863] usb 1-6: Number of endpoints 2
[ 1317.677867] usb 1-6: Endpoint 1 MaxPacketSize 512
[ 1317.677870] usb 1-6: Endpoint 2 MaxPacketSize 512
[ 1317.677873] usb 1-6: Setting MaxPacketSize 512
[ 1317.678303] usb 1-6: FTDI USB Serial Device converter now attached to ttyUSB0
[ 1318.061040] ftdi_sio ttyUSB0: FTDI USB Serial Device converter now disconnected from ttyUSB0
[ 1318.061062] ftdi_sio 1-6:1.0: device disconnected

So from here I had some other trouble with the server, which eventually forced me to reinstall the whole damn machine, but that’s another story.
Now I could try to run cgminer and see if it worked with the bitcoin.cz pool.

./cgminer -o http://stratum.bitcoin.cz:port -u worked.worker -p password

And the output was rather promising 🙂

cgminer version 3.5.0 – Started: [2013-10-05 16:21:03]
——————————————————————————–
(5s):59.06G (avg):58.55Gh/s | A:509454 R:3336 HW:13534 WU:798.0/m
ST: 2 SS: 0 NB: 108 LW: 533339 GF: 0 RF: 0
Connected to stratum.bitcoin.cz diff 51 with stratum as user xxx.xxxx
Block: 000cfd2757615868… Diff:149M Started: [03:06:39] Best share: 347K
——————————————————————————–
[P]ool management [G]PU management [S]ettings [D]isplay options [Q]uit
GPU 0: | OFF /5.592Mh/s | A: 3 R: 0 HW: 0 WU: 0.1/m I: 6
BAS 0: max 69C 3.26V | 58.61G/58.55Gh/s | A:509604 R:3336 HW:13535 WU:798.0/m
——————————————————————————–

So now the miner is nicely placed on the balcony (Not an open balcony, so I’m not worried about placing it there).
And since it’s fall now and winter will come soon, the temperature out there will be just right.

High resolution image of the miner
High resolution image of the miner, back server view

Video showing the miner, mostly to demonstrate the noise level

References:

https://forums.butterflylabs.com/showwiki.php?title=Tutorials:ASIC+Mining+on+Ubuntu+and+other+Linux+distros&redirect=no

https://forums.butterflylabs.com/jalapeno-single-sc-support/5158-been-mining-few-hours-let-me-confirm-if-all-ok.html


https://mining.bitcoin.cz

https://en.bitcoin.it/wiki/CGMiner

Wrote an EAN13 barcode program

I decided to write a barcode generator in Java “for no apparent reason”, that can currently generator EAN13 barcodes. It’s available here in this post, but if you want the latest code then I suggest you check it out on github.

Github repo:
https://github.com/jra89/barcode

Usage:

[code]
java -jar barcode.jar numbers path barwidth barheight
[/code]

Example:

[code]
java -jar barcode.jar 999990000020 /home/user/Desktop/EAN_IMG.png 2 60
[/code]

Main.java

[code lang=”java”]
package barcode;

public class Main
{
public static void main(String[] args)
{
String code;
String path;
int barWidth;
int barHeight;

if(args.length <= 1)
{
System.out.println("Not enough parameters");
}

try
{
code = args[0];
}
catch(NullPointerException e)
{
code = "9999900000207";
}

try
{
path = args[1];
}
catch(NullPointerException e)
{
path = "/tmp/barcode.png";
}

try
{
barWidth = Integer.parseInt(args[2]);
}
catch(NullPointerException e)
{
barWidth = 1;
}

try
{
barHeight = Integer.parseInt(args[3]);
}
catch(NullPointerException e)
{
barHeight = 100;
}

Ean13 ean = new Ean13(code, path, barWidth, barHeight);
ean.createBarcodePNG();

}
}
[/code]

Ean13.java

[code lang=”java”]
package barcode;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class Ean13
{
/**
* -=Structure=-
*
* Fist, First Six, Last Six
* LGR = 012
* 0 LLLLLL RRRRRR
* 1 LLGLGG RRRRRR
* 2 LLGGLG RRRRRR
* 3 LLGGGL RRRRRR
* 4 LGLLGG RRRRRR
* 5 LGGLLG RRRRRR
* 6 LGGGLL RRRRRR
* 7 LGLGLG RRRRRR
* 8 LGLGGL RRRRRR
* 9 LGGLGL RRRRRR
*
* -=Encodings=-
*
* Digit L-code G-code R-code
* 0 0001101 0100111 1110010
* 1 0011001 0110011 1100110
* 2 0010011 0011011 1101100
* 3 0111101 0100001 1000010
* 4 0100011 0011101 1011100
* 5 0110001 0111001 1001110
* 6 0101111 0000101 1010000
* 7 0111011 0010001 1000100
* 8 0110111 0001001 1001000
* 9 0001011 0010111 1110100
**/

private String code;
private String path;
private BufferedImage bi;
private Graphics2D ig2;
private int barPos;
private int barPosBin;
private int imgPixelPos;
private int barWidth;
private int barHeight;
private int imgWidth;
private int imgHeight;
private int[][] barcodeBinary;

private int[][] firstSix = {
{0,0,0,0,0,0}, //LLLLLL
{0,0,1,0,1,1}, //LLGLGG
{0,0,1,1,0,1}, //LLGGLG
{0,0,1,1,1,0}, //LLGGGL
{0,1,0,0,1,1}, //LGLLGG
{0,1,1,0,0,1}, //LGGLLG
{0,1,1,1,0,0}, //LGGGLL
{0,1,0,1,0,1}, //LGLGLG
{0,1,0,1,1,0}, //LGLGGL
{0,1,1,0,1,0} //LGGLGL
};

private int[] lastSix = {2, 2, 2, 2, 2, 2};

private int[][][] encodings = {
{
{0,0,0,1,1,0,1},
{0,1,0,0,1,1,1},
{1,1,1,0,0,1,0}
},
{
{0,0,1,1,0,0,1},
{0,1,1,0,0,1,1},
{1,1,0,0,1,1,0}
},
{
{0,0,1,0,0,1,1},
{0,0,1,1,0,1,1},
{1,1,0,1,1,0,0}
},
{
{0,1,1,1,1,0,1},
{0,1,0,0,0,0,1},
{1,0,0,0,0,1,0}
},
{
{0,1,0,0,0,1,1},
{0,0,1,1,1,0,1},
{1,0,1,1,1,0,0}
},
{
{0,1,1,0,0,0,1},
{0,1,1,1,0,0,1},
{1,0,0,1,1,1,0}
},
{
{0,1,0,1,1,1,1},
{0,0,0,0,1,0,1},
{1,0,1,0,0,0,0}
},
{
{0,1,1,1,0,1,1},
{0,0,1,0,0,0,1},
{1,0,0,0,1,0,0}
},
{
{0,1,1,0,1,1,1},
{0,0,0,1,0,0,1},
{1,0,0,1,0,0,0}
},
{
{0,0,0,1,0,1,1},
{0,0,1,0,1,1,1},
{1,1,1,0,1,0,0}
}
};

Ean13(String code, String path,int barWidth, int barHeight)
{
this.code = code;
this.path = path;
this.barPos = 12;
this.barPosBin = 7;
this.imgPixelPos = 0;
this.barcodeBinary = new int[barPos][barPosBin];
this.barWidth = barWidth;
this.barHeight = barHeight;
this.imgWidth = ((12*7) + (2*9) + (2*3) + (1*5)) * this.barWidth;
this.imgHeight = this.barHeight;
}

public void createBarcodePNG()
{
this.code += Integer.toString(calculateControlDigit(this.code));
generateBinaryMap();
generateBarcodePNG();
}

private void generateBinaryMap()
{
int first = Integer.parseInt(String.valueOf(this.code.charAt(0)));

//i = 1, first digit is not welcome to the bar
for(int i = 1; i < 13; ++i)
{
int current = Integer.parseInt(String.valueOf(this.code.charAt(i)));

if(i < 7)
this.barcodeBinary[i-1] = this.encodings[current][this.firstSix[first][i-1]];
else
this.barcodeBinary[i-1] = this.encodings[current][this.lastSix[i-7]];
}
}

private void generateBarcodePNG()
{
try {
// TYPE_INT_ARGB specifies the image format: 8-bit RGBA packed
// into integer pixels
bi = new BufferedImage(this.imgWidth, this.imgHeight, BufferedImage.TYPE_INT_ARGB);
ig2 = bi.createGraphics();

ig2.setPaint(Color.white);
ig2.fillRect ( 0, 0, bi.getWidth(), bi.getHeight() );

//Draw quiet zone
drawSpecial(0);

//Draw lead
drawSpecial(1);

//Draw first group
drawGroup(1);

//Draw separator
drawSpecial(2);

//Draw second group
drawGroup(2);

//Draw lead
drawSpecial(1);

//Draw quiet zone
drawSpecial(0);

ImageIO.write(bi, "PNG", new File(path));

} catch (IOException ie) {
ie.printStackTrace();
}
}

private void drawGroup(int groupPart)
{
int i = 0, length = 0;
if(groupPart == 1)
{
i = 0;
length = (this.barcodeBinary.length/2);
}
else if(groupPart == 2)
{
i = 6;
length = this.barcodeBinary.length;
}

for(; i < length; ++i)
{
for(int n = 0; n < this.barcodeBinary[i].length; ++n)
{
if(this.barcodeBinary[i][n] == 0)
{
ig2.setPaint(Color.white);
ig2.setStroke(new BasicStroke(this.barWidth));
}
else
{
ig2.setPaint(Color.black);
ig2.setStroke(new BasicStroke(this.barWidth));
}

int pos = this.imgPixelPos;
ig2.drawLine(pos,0,pos,this.barHeight);
this.imgPixelPos += this.barWidth;
}
}
}

private void drawSpecial(int type)
{

/*
Special Symbol Pattern
Quite Zone 000000000
Lead / Trailer 101
Separator 01010
*/

int[] quiteZone = {0,0,0,0,0,0,0,0,0};
int[] leadtrail = {1,0,1};
int[] separator = {0,1,0,1,0};
int binaryArrLength = 0;
int[] arr;

if(type == 0)
{
binaryArrLength = quiteZone.length;
arr = quiteZone;
}
else if(type == 1)
{
binaryArrLength = leadtrail.length;
arr = leadtrail;
}
else
{
binaryArrLength = separator.length;
arr = separator;
}

for(int n = 0; n < binaryArrLength; ++n)
{
if(arr[n] == 0)
ig2.setPaint(Color.white);
else
ig2.setPaint(Color.black);

int pos = this.imgPixelPos;
ig2.drawLine(pos,0,pos,this.barHeight);
this.imgPixelPos += this.barWidth;
}
}

public int calculateControlDigit(String ean)
{
int sum = 0;
for(int i = 0; i < 12; ++i)
{
int val = charToInt(ean.charAt(i));
if((i+1)%2 == 0)
sum += val*3;
else
sum += val*1;
}

return (10 – (sum % 10));
}

private int charToInt(char c)
{
return Integer.parseInt(String.valueOf(c));
}
}
[/code]