"Better safe then sorry". That's my motto. Although I updated my new server with a software RAID1 and using rsync to backup my data to an external hard-disk. One thing I didn't protect it from is hardware failures. So I used an other computer that would be my new backup server. Now I could have installed Debian again and doing some rsyncing but I don't know if that's good enough. What I want is a 1 on 1 clone. So you would probably thinking of:
$ dd if=/dev/sda of=/dev/sdc
To keep thinks short. That was not an option for me. I needed to do it over the network. So I soon figured out the netcat. Which I think you probably already known it's doing by reading it's name. It's using cat over the network. Just what I needed! After reading some posts on the internet I figured out to do some cloning. Here is my result.
I'm using software RAID1 on my Debian server. I will disable one hard-drive and cloning that one over the network. Note that my server can still be used because my other hard-drive is still running. So no downtime! First I need to know something about my RAID1. So I do the following:
$ cat /proc/mdstat Personalities : [raid1] md6 : active raid1 sdb8[1] sda8[0] 441016256 blocks [2/2] [UU] md5 : active raid1 sdb7[1] sda7[0] 2931712 blocks [2/2] [UU] md4 : active raid1 sdb6[1] sda6[0] 4883648 blocks [2/2] [UU] md3 : active raid1 sdb5[1] sda5[0] 19534912 blocks [2/2] [UU] md2 : active raid1 sdb3[1] sda3[0] 19534976 blocks [2/2] [UU] md1 : active raid1 sdb2[1] sda2[0] 289088 blocks [2/2] [UU] md0 : active raid1 sdb1[1] sda1[0] 192640 blocks [2/2] [UU] unused devices:
Note that your mdstat will probably look different. I want to disable the second SATA hard-drive (sdb). First you need to set the faulty bit per partition and then you can remove them. If I see my mdstat output I could use the following commands to disable them.
$ mdadm --manage /dev/md0 --fail /dev/sdb1 $ mdadm --manage /dev/md1 --fail /dev/sdb2 $ mdadm --manage /dev/md2 --fail /dev/sdb3 $ mdadm --manage /dev/md3 --fail /dev/sdb5 $ mdadm --manage /dev/md4 --fail /dev/sdb6 $ mdadm --manage /dev/md5 --fail /dev/sdb7 $ mdadm --manage /dev/md6 --fail /dev/sdb8 $ mdadm --manage /dev/md0 --remove /dev/sdb1 $ mdadm --manage /dev/md1 --remove /dev/sdb2 $ mdadm --manage /dev/md2 --remove /dev/sdb3 $ mdadm --manage /dev/md3 --remove /dev/sdb5 $ mdadm --manage /dev/md4 --remove /dev/sdb6 $ mdadm --manage /dev/md5 --remove /dev/sdb7 $ mdadm --manage /dev/md6 --remove /dev/sdb8
Now I'm ready to clone this drive over the network. For that you need to start a listening server on the backup server. So at this point start your backup server with a LiveCD like SysRescCD. In SysRescCD you need to start your ethernet card. This worked for me:
$ dhcpcd eth0
Write down your local IP. Now start the listening server with netcat. You're gonna pipe the output from netcat to dd which in return writes the bits and pieces to the backup hard-drive (sda).
$ nc -l -p 1983 | dd of=/dev/sda
Now your backup server's waits for the production server to send some data. So lets do that! Go back to your production servers terminal and send the data!
$ dd if=/dev/sdb | nc 192.168.0.110 1983
Note that the 1983 is the port number. You can change that if you like. Now wait a very long time. For me a backup of the 500Gb hard-drive took me a whopping 20 hours! So have a coffee, do some work go to sleep or whatever. Some note. You don't see any progress. When all is gone good you see the production server saying it has send X bytes. At this point you need to CTRL-C in the terminal on the production server. Don't know why but this will close the connection between the two.
Ok! Now first restore our RAID1 array on our production server. The following command's will do:
$ mdadm --manage /dev/md0 --add /dev/sdb1 $ mdadm --manage /dev/md1 --add /dev/sdb2 $ mdadm --manage /dev/md2 --add /dev/sdb3 $ mdadm --manage /dev/md3 --add /dev/sdb5 $ mdadm --manage /dev/md4 --add /dev/sdb6 $ mdadm --manage /dev/md5 --add /dev/sdb7 $ mdadm --manage /dev/md6 --add /dev/sdb8
From this point you got your production server up and running again. You're not far now. I encounter two problems when restarting my backup server. 1: I didn't got any GRUB screen. And 2: My RAID array was messed up. Lucky these are easy to solve. Maybe you don't have these problems. First restore our GRUB: Start your LiveCD again. You need to mount a partition which has the /boot directory. For me it was /dev/md0.
$ mount /dev/md0 /mnt/fred $ /mnt/fred/sbin/grub grub> root (hd0,0) grub> setup (hd0) grub> quit
$ mdadm --stop /dev/md0 $ mdadm --stop /dev/md1 $ mdadm --stop /dev/md2 $ mdadm --stop /dev/md3 $ mdadm --stop /dev/md4 $ mdadm --stop /dev/md5 $ mdadm --stop /dev/md6 $ mdadm --create /dev/md0 --verbose --level=raid1 --raid-devices=2 /dev/sda1 missing $ mdadm --create /dev/md1 --verbose --level=raid1 --raid-devices=2 /dev/sda2 missing $ mdadm --create /dev/md2 --verbose --level=raid1 --raid-devices=2 /dev/sda3 missing $ mdadm --create /dev/md3 --verbose --level=raid1 --raid-devices=2 /dev/sda5 missing $ mdadm --create /dev/md4 --verbose --level=raid1 --raid-devices=2 /dev/sda6 missing $ mdadm --create /dev/md5 --verbose --level=raid1 --raid-devices=2 /dev/sda7 missing $ mdadm --create /dev/md6 --verbose --level=raid1 --raid-devices=2 /dev/sda8 missing
The 'missing' parameter is there because I only have one hard-drive yet. But I create a 'spot' just in case I add a second hard-drive. Which would be natural because that's what's RAID for! The last thing you probably need to do is change your network configuration in case it's has a static IP.
Now you're done! Good luck!
Sources:
http://www.sysresccd.org/
http://linux.die.net/man/8/mdadm
http://arstechnica.com/civis/viewtopic.php?f=16&t=121767
http://kevin.deldycke.com/2007/03/how-to-recover-a-raid-array-after-having-zero-ized-superblocks/
http://www.devil-linux.org/documentation/1.0.x/ch01s05.html
http://sattia.blogspot.com/2010/02/linux-cloning-over-network-using-netcat.html
It's been a while since my last post. The reason of my lack of posting was that I was too busy with other stuff. Also I like to take time posting. Not just a post like lookie-here-what-i've-done post. That's what's Twitter is for. I started this blog because I want to share. Share knowledge to be exactly. Because I have got the most if not all of my knowledge thanks to the internet. I wanted to do something in return. But the main problem is (was?), that I didn't got the time for posting.
Until I've found something interesting! It's got to do with sleeping schedules. I am a night person. I tried waking up in the morning. But then day by day it's getting later and later. I started thinking that 24 hours for me was too short. When I was searching on someone's blog (forgot who it was), I stumbled on this link: http://www.dbeat.com/28/. It's about a schedule where you have 6 days in a week 28 hours each. After reading I was very excited. But the main problem I think is that although you will adept to the 28 hour day. Will others adept to you? For me that was a no-no. My social life will not be as is it is today and I don't want to give up on that.
I was very eager to learn more about these concepts about sleeping schedules. Because they would really help me free some time to do other stuff. Very soon I also found about the Uberman and the Everyman schedule. They are methods for sleeping less hours on a day but more frequently. I talk about 3 and 4 hours sleep per day! That's 5 hours less than I normally do! At first I was very insecure if this will work. We all know that we must at least 8 hours sleep per day. But after reading other peoples experiences I was thinking that it may work?
So, since I like some experimenting from time to time I started the Everyman's schedule. This is my first day and although it started good. I'm sure the following few days will be harder until my body is fully adapted to it's new sleeping schedule. I will keep you informed ;)
Some side thought. This is experiment and I really don't have a clue what the outcome is. For some it works, for other it won't. If it doesn't work for me then I'm ok with that. If it works? Then it's cool for the time being because that means I got 5 hours of time extra per day! We'll see how it goes, and maybe this will create some more time for posting ;)
When you're writing a program in C, C++, Objective C, maybe D?. You come to a point, how do I load my data? If you're making a game it would be nice to save your level data in some sort of file. And you should! You could use XML. It is widely used so why not? Well...did you ever opened the libXML library from xmlsoft.org? The 'parser.c' alone is already 395Kb! Sure, they need to make the code to follow the W3C standard, but come on! 395Kb for a parser?
That's one of the many reasons I wrote Lasanja. The other one is that I like to write my own code. Another is that XML has it flaws like '<a><b></a></b>' is not a valid structure, which in Lasanja you can't. The last and importent reason. I like things to be simple, don't overdo things you will never use.
So, what's Lasanja? Lasanja is a markup language, just like XML. Let say we want to load a level file. We could define a Lasanja file like so:
version{ 1 } level{ width{ 30 } height{ 5 } 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 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 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 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 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 enemy{ x{ 12.12 } y{ 24.24 } } enemy{ x{ 56.34 } y{ 23.95 } } }in XML we would could do it like so:
<data> <version> 1 </version> <level> <width>30</width> <height>5</height> 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 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 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 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 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 <enemy> <x>12.12</x> <y>24.24</y> </enemy> <enemy> <x>56.34</x> <y>23.95</y> </enemy> </level> </data>
You can see that's almost the same. In Lasanja there are two things, nodes and data. In XML you got, nodes, data and attributes. I removed the attributes because for some that's confusing and I don't like people confused. Also note the extra '<data>' tag in the xml file. That is not needed in a Lasanja file.
In short. With tagname{ you create a new node named 'tagname'. With } you close the node. Everyting between { and } is data. That's it! You find more info in the project file.
You may use the code anyway you like. If you vind some bugs, please e-mail me. I would appreciate it.
The project file and sources are here: http://vin.ingine.nl/posts/13/lasanja.v0.4.zip
Lasanja v0.4 does not mean it's not finished or buggy code. It does what it does and it does well. I don't consider this as a beta release. Because this is it's first release I don't want to release it as v1.0 yet.
Did I mentioned that the project executable for reading an example level las file, is only 9Kb! You can store that 163 times on a 1.44 Mb floppy disk :P
UPDATE: Today I use Cairo. Which is not only a font renderer but a full blown vector graphics library. They are now building support for OpenGL. Sweet!
Made me some nice wrapper functions. It's much more readable now. You can use it as a basis for your own font drawing routines.
TODO: Some better error handling.
FT_Face g_ftFace; FT_Library g_ftLib; FT_Matrix g_ftMatrix; FT_Vector g_ftPen; int g_ftBoxWidth; int g_ftBoxHeight; void ftBox( int width, int height ) { g_ftBoxWidth = width; g_ftBoxHeight = height; } void ftInit() { g_ftMatrix.xx = 0x10000; g_ftMatrix.xy = 0; g_ftMatrix.yx = 0; g_ftMatrix.yy = 0x10000; g_ftBoxWidth = 0; g_ftBoxHeight = 0; if( FT_Init_FreeType( &g_ftLib ) ) { printf( "Error: could not initialize FreeType library\n" ); } } void ftFace( char *face ) { FT_Error error = FT_New_Face( g_ftLib, face, 0, &g_ftFace ); if( error == FT_Err_Unknown_File_Format ) { printf( "Error: Unknown font file format\n" ); } else if( error ) { printf( "Error: Unknown error loading font\n" ); } } void ftMatrix( int xx, int xy, int yx, int yy ) { g_ftMatrix.xx = xx; g_ftMatrix.xy = xy; g_ftMatrix.yx = yx; g_ftMatrix.yy = yy; } void ftSize( int width, int height ) { if( FT_Set_Pixel_Sizes( g_ftFace, 80, 80 ) ) { printf( "Error: Could not set font pixel size\n" ); } } void ftText( char *image, char *text ) { int num_chars = strlen( text ); int x, y, i, j, p, q, x_max, y_max, pixel; char color; FT_Bitmap *bitmap; FT_GlyphSlot slot = g_ftFace->glyph; int n = 0; for( ; n < num_chars; n++ ) { FT_Set_Transform( g_ftFace, &g_ftMatrix, &g_ftPen ); if( FT_Load_Char( g_ftFace, text[n], FT_LOAD_RENDER ) ) { continue; } bitmap = &slot->bitmap; x = slot->bitmap_left; y = g_ftBoxHeight - slot->bitmap_top; x_max = x + bitmap->width; y_max = y + bitmap->rows; for( i = x, p = 0; i < x_max; i++, p++ ) { for( j = y, q = 0; j < y_max; j++, q++ ) { if( i < 0 || j < 0 || i >= g_ftBoxWidth || j >= g_ftBoxHeight ) { continue; } color = bitmap->buffer[q * bitmap->width + p]; pixel = ( j * g_ftBoxHeight + i ) * 4; image[pixel++] = 0xff; // R image[pixel++] = 0xff; // G image[pixel++] = 0xff; // B image[pixel] |= color; // A } } g_ftPen.x += slot->advance.x; g_ftPen.y += slot->advance.y; } } void ftTranslate( int x, int y ) { g_ftPen.x = x << 6; g_ftPen.y = ( g_ftBoxHeight - y ) << 6; }
This is how you use the new functions. Much nicer now!
#define IMG_WIDTH 512 #define IMG_HEIGHT 512 // create a bitmap unsigned char *image = malloc( IMG_WIDTH * IMG_HEIGHT * 4 ); if( image == NULL ) { printf( "Error: malloc()\n" ); return 0; } memset( image, 0, IMG_WIDTH * IMG_HEIGHT * 4 ); // draw our text using our awesome functions! ftInit(); ftFace( "c:/windows/fonts/verdana.ttf" ); ftSize( 80, 80 ); ftBox( IMG_WIDTH, IMG_HEIGHT ); double angle = ( -30.0 / 180.0 ) * 3.14159; ftMatrix( (FT_Fixed)( cos( angle ) * 0x10000L ), (FT_Fixed)(-sin( angle ) * 0x10000L ), (FT_Fixed)( sin( angle ) * 0x10000L ), (FT_Fixed)( cos( angle ) * 0x10000L ) ); ftTranslate( 50, 100 ); ftText( image, "Hello, world!" ); ftTranslate( 50, 200 ); ftText( image, "Hello, world!" ); ftTranslate( 50, 300 ); ftText( image, "Hello, world!" ); // ...and create a OpenGL texture of it GLint img; glGenTextures( 1, &img ); glBindTexture( GL_TEXTURE_2D, img ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, IMG_WIDTH, IMG_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, image );
UPDATE: Today I use Cairo. Which is not only a font renderer but a full blown vector graphics library. They are now building support for OpenGL. Sweet!
[u]UPDATE: Today I use Cairo. Which is not only a font renderer but a full blown vector graphics library. They are now building support for OpenGL. Sweet![/u]
I'm writing an OpenGL GUI interface. One thing that's very important is drawing some fonts. This means 2D, not 3D fonts. There are a numbers of ways to do this. Even some nice C++ library's that you could use. But I want to know the 'magic'. When you work with Linux you probebly heard of FreeType. Which is a cross-platform library created to load fonts. Just what we needed!
FreeType renders the text into his own grayscale bitmap. We could uses this bitmap as an alpha channel.
Steps for writing fonts with OpenGL:
1: Load the font
2: Draw some text onto a bitmap
3: Load this bitmap as an OpenGL texture
4: Draw the texture
I used the code snippet from documentation of FreeType self. And made some little changes to it.
http://www.freetype.org/freetype2/docs/tutorial/step1.html
The 'magic' code:
#define WIDTH 512 #define HEIGHT 512 char *text = "Hello, world!"; int num_chars = strlen( text ); double angle = ( -45.0 / 180.0 ) * 3.14159; // my RGBA bitmap unsigned char *data = malloc( WIDTH * HEIGHT * 4 ); if( data == NULL ) { printf( "Error: malloc()\n" ); return 0; } memset( data, 0, WIDTH * HEIGHT * 4 ); // init FreeType FT_Library library; if( FT_Init_FreeType( &library ) ) { printf( "Error: could not initialize FreeType library\n" ); } // loads a face FT_Face face; FT_Error error = FT_New_Face( library, "c:/windows/fonts/verdana.ttf", 0, &face ); if( error == FT_Err_Unknown_File_Format ) { printf( "Error: Unknown font file format\n" ); } else if( error ) { printf( "Error: Unknown error loading font\n" ); } // set font dimensions 80 x 80 pixels if( FT_Set_Pixel_Sizes( face, 80, 80 ) ) { printf( "Error: Could not set font pixel size\n" ); } FT_GlyphSlot slot = face->glyph; // transformation matrix FT_Matrix matrix; matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L ); matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L ); matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L ); matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L ); // untransformed origin // the pen position in 26.6 cartesian space coordinates; // start at (50,100) relative to the upper left corner FT_Vector pen; pen.x = 50 << 6; pen.y = ( HEIGHT - 100 ) << 6; int n = 0; for( ; n < num_chars; n++ ) { FT_Set_Transform( face, &matrix, &pen ); // load glyph image into the slot (erase previous one) if( FT_Load_Char( face, text[n], FT_LOAD_RENDER ) ) { continue; // ignore errors } FT_Bitmap *bitmap = &slot->bitmap; FT_Int x = slot->bitmap_left; FT_Int y = HEIGHT - slot->bitmap_top; FT_Int i, j, p, q; FT_Int x_max = x + bitmap->width; FT_Int y_max = y + bitmap->rows; for( i = x, p = 0; i < x_max; i++, p++ ) { for( j = y, q = 0; j < y_max; j++, q++ ) { if( i < 0 || j < 0 || i >= WIDTH || j >= HEIGHT ) { continue; } char color = bitmap->buffer[q * bitmap->width + p]; int pixel = ( j * HEIGHT + i ) * 4; data[pixel++] = 0xff; // R data[pixel++] = 0xff; // G data[pixel++] = 0xff; // B data[pixel] |= color; // A } } // increment pen position pen.x += slot->advance.x; pen.y += slot->advance.y; } // Now load the bitmap into an OpenGL texture GLint img; glGenTextures( 1, &img ); glBindTexture( GL_TEXTURE_2D, img ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); // And now do some OpenGL drawing! glTranslatef( WIDTH / 2, HEIGHT / 2, 0.0f ); glScalef( WIDTH, HEIGHT, 1.0f ); glBindTexture( GL_TEXTURE_2D, img ); glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); glBegin( GL_QUADS ); glTexCoord2f( 0.0f, 0.0f ); glVertex2f( -0.5f, -0.5f ); glTexCoord2f( 1.0f, 0.0f ); glVertex2f( 0.5f, -0.5f ); glTexCoord2f( 1.0f, 1.0f ); glVertex2f( 0.5f, 0.5f ); glTexCoord2f( 0.0f, 1.0f ); glVertex2f( -0.5f, 0.5f ); glEnd();
That's it! Pretty easy huh? Thank FreeType for this great library!
I made it using CodeBlocks.
The project file and sources are here: http://vin.ingine.nl/posts/11/opengl_fonts.zip
Yesterday I wrote a simple RSS reader in Actionscript 3.0. Nothing fancy really. But I thought I shared it with you. The code is pretty self explanational. TIP: Try to use embedded fonts, this will make a nicer transition between the feeds. NOTE: Not every html entitie is supported by Flash, like é (= é) for example. You must do string.replace( /é/, 'é' ) for every non supporting entity. But that's up to you ;)
An entity list: http://www.w3schools.com/tags/ref_entities.asp
BTW! Only RSS version 2.0 is supported.
Here's the snippet:
// which rss url to load? var RSSURL:String = "http://feeds.feedburner.com/tweakers/mixed"; // the length per feed in seconds var DURATION:int = 5; // how fast is the alpha wipe? value must be between 0 and 1! var FADE:Number = 0.07; // width and height of the feed var WIDTH:int = 640; var HEIGHT:int = 480; // the layout of the feed, you can use %title% and %desc% var LAYOUT:String = '<font face="Verdana" color="#000000" size="20"><b>%title%</b></font><br />' + '<font face="Verdana" color="#444444" size="14"><b>%desc%</b></font>'; // use embedded fonts? var EMBED_FONTS:Boolean = false; ////////////////////////////////////////////////////////////////////// // DON'T CHANGE WHAT'S UNDERNEATH! (unless you know what you doing) // ////////////////////////////////////////////////////////////////////// var loader:URLLoader = new URLLoader(); loader.addEventListener( Event.COMPLETE, evtComplete ); loader.addEventListener( SecurityErrorEvent.SECURITY_ERROR, evtSecurity ); loader.addEventListener( IOErrorEvent.IO_ERROR, evtIOError ); loader.load( new URLRequest( RSSURL + '?r=' + Math.random() ) ); var rss:XML; var arr:Array; var txtA:TextField; var txtB:TextField; var txtTemp:TextField; var pos:int = 0; var dWait:Date; var dNow:Date; function evtComplete( e:Event ):void { try { rss = new XML( loader.data ); } catch( e:Error ) { trace( 'XML Parse Error: ' + e ); return; } if( rss.@version != '2.0' ) { trace( 'Error: RSS feed not version 2.0, your version: ' + rss.@version ); return; } arr = new Array(); for each ( var item:XML in rss.channel.item ) { arr.push( { 'title': item.title, 'desc': item.description } ); } txtA = new TextField(); txtB = new TextField(); txtA.width = txtB.width = WIDTH; txtA.height = txtB.height = HEIGHT; txtA.alpha = txtB.alpha = EMBED_FONTS ? 0.0 : 1.0; txtA.antiAliasType = txtB.antiAliasType = AntiAliasType.ADVANCED; txtA.embedFonts = txtB.embedFonts = EMBED_FONTS; txtA.wordWrap = txtB.wordWrap = true; txtA.multiline = txtB.multiline = true; txtA.htmlText = getText(); txtB.htmlText = ''; dWait = new Date(); dWait.setSeconds( dWait.seconds + DURATION ); addEventListener( Event.ENTER_FRAME, evtEnterFrame ); addChild( txtA ); addChild( txtB ); } function evtEnterFrame( e:Event ):void { dNow = new Date(); if( dNow > dWait ) { txtB.htmlText = getText(); txtTemp = txtA; txtA = txtB; txtB = txtTemp; dWait.setSeconds( dNow.seconds + DURATION ); } if( EMBED_FONTS ) { txtA.alpha += ( 1.0 - txtA.alpha ) * FADE; txtB.alpha += ( 0.0 - txtB.alpha ) * FADE; } else { txtA.visible = true; txtB.visible = false; } } function evtIOError( e:IOErrorEvent ):void { trace( 'IOErrorEvent: ' + e ); } function evtSecurity( e:SecurityErrorEvent ):void { trace( 'SecurityErrorEvent: ' + e ); } function getText():String { if( !arr || arr.length == 0 ) { return ':('; } var txt:String = LAYOUT .replace( /%title%/, arr[pos].title ) .replace( /%desc%/, arr[pos].desc ) .replace( /é/, 'é' ); // as an example, you do the rest :P if( ++pos == arr.length ) { pos = 0; } return txt; }
So you want to open a website with PHP with fopen() or file_get_contents()? But it's taken to long is not available? Well I got this problem with reading my Twitter account that I want to show on the right. Today Twitter has a lot of downtimes so if you check my website, my website taking a long time to load!
UPDATE: Twitter had a DDOS attack that causes the downtime. Well, it's good for testing the code ;)
The only thing you need to do is change the default_socket_timeout ini value like so:
// set timeout for 5 seconds ini_set( 'default_socket_timeout', 5 );
I store all my community feeds into a cache file. So if there's a downtime, it will show the old one stored in the cache. And you don't need to reload the content per every page click. So it's nice to have it stored in cache for like 6 minutes.
function getContents( $url ) { // set the timeout for 3 seconds ini_set( 'default_socket_timeout', 3 ); // store the cachefile into $file $file = md5( $url ); $old = true; if( $f = fopen( "cache/$file", 'r' ) ) { $stat = fstat( $f ); // check if the cache file is NOT older then 360 seconds if( time() - 360 < $stat['mtime'] ) { $old = false; } fclose( $f ); } // if NOT old, return the cache file if( !$old ) { return file_get_contents( "cache/$file" ); } // ...else get the new content, if timeout, return the cache file if( !$con = file_get_contents( $url ) ) { return file_get_contents( "cache/$file" ); } // store the new content in the cache file if( $f = fopen( "cache/$file", 'w' ) ) { fwrite( $f, $con ); fclose( $f ); } // ...and return the new content return $con; } if( $con = getContents( 'http://some.web.page' ) ) { // Woohoo! Do something with it... }
If you build a website in these days. You must be very alerted by the spambots that are crawling trough your site. When I build my blog, I was very aware of this and made some simpel yet effective code to protect some of my html by using Javascript.
I see lots of website just doing mymail [at] yourwebsite [dot] com. This will proberply help for some of the spambots. But definitely not all! If I was a spambot, I would also looking for the [at]'s and [dot]'s, and also the {at}'s and {dot}'s like I do.
Here is the snippet:
function protect( $s ) { $s = str_replace( "\n", ' ', str_replace( "\r", ' ', $s ) ); $a = array(); $p = 0; $l = strlen( $s ); while( $p < $l ) { $n = rand( 1, 4 ); $a[] = substr( $s, $p, $n ); $p += $n; } asort( $a ); $j = 'var a = new Array();'; foreach( $a as $k => &$v ) { $j .= "a[$k] = '" . addslashes( $v ) . "';"; } $j .= 'document.write( a.join("") );'; return '<script language="javascript">' . $j . '</script>'; }
You can just do the following to write the protected code.
echo protect( 'Help! Protect me from these evil spambots! Please!' ); echo protect( '<a href="mailto:insert.mail@address.here">e-mail me</a>' );
What it does is. It cuts the inputted string into random length en put them into a array. Sort the array to make ik not linear. And let Javascript join it into a string and document.write() it. This time Javascript writing it and your code would not be seen as plain text in the html source code.
Why Vin Ingine?
My real name is Vincent van Ingen. But people call me just Vin or Vinnie for short. Ingine is my company name which I got from mixing "engine" and my last name "Ingen".
Are you available for work?
Yes I am. I've got a company Visionplay in The Netherlands where I do work for external companys.
How can I contact you?
Click on the e-mail at the right menu of this site under Contact.
For now not much faq. Need to know something more? Leave a comment below :)
Hi! My name is Vincent van Ingen. And finally I have my own personal web blog! I've been around for some time now but never had a website where I could share my stuff with the rest of the world.
I like to develop in a very creative way. Nowdays I like todo that in just plain C with some OpenGL stuff. But also in Flash Actionscript, Processing or any other language that's good looking. Hence, I've started my own programming language!
Today I'm working on several things. I got my company Visionplay where I work on some websites and RIA applications. I got another company called Ingine which from now on I started developing games for multiple platforms. And last, Vii2Media which is a cross-media platform for broadcasting.
Well, that's about it for now. I could tell more, but let the blog do the talking for now.
Enjoy your stay :)