Facebook: Update your account recovery information for additional security

I remember seeing a link to this before, but Facebook decided to make it one of those random links that shows up once or twice and never appears again.

Click below to configure alternate emails in case your primary email gets hacked, security questions and mobile number.

image

uTorrent: How to fix the disgusting user interface changes in uTorrent 2.2

image 
Look at that shit! Just look at it.

Here I am, updating my uTorrent to v2.2 in blind trust because in the past, their updates have always been awesome.

Not this time. They've fucked the UI and joined the app bandwagon. The fuck is this shit? For Christ sake, it isn't a mobile phone! Why the hell do I need apps to play games on uTorrent?

This update was a gigantic waste of time. Time which they could have spent making progress on the 97+ page bug tracker.

Looking through the first page of the forums, there was no problem finding other people who were even angrier than me about it!

Anyway, I'm glad they took the time to make a skin for us that brought back the v2.04 theme icons. It was posted on the release information.

  • Download the skin and save it on your computer.
  • Open up the uTorrent window
  • Drag the skin file into your uTorrent window
  • The skin should apply immediately

image
Beautiful again.

The progress bars are still retarded, but that can be changed in the advanced settings in preferences. Change "gui.color_progressbars" to false.

Please uTorrent, I've always advocated your use but don't do anything stupid like this again.

Sources

Python: How to generate a random string with letters and numbers

This is probably one of the shortest and simplest implementations I've seen in any language. Nice work MasterPi !

import string
import random

"".join([random.choice(string.letters+string.digits) for x in range(1, desired_length)])

[ Source ]

Git: Do a "git status" on each submodule using foreach

Strangely enough, its fine doing a git branch on each submodule using "git submodule foreach git branch".

However, if you try "git status" it wont be happy. It'll spit out this error after the first submodule.

Stopping at 'firstmodule'; script returned non-zero status.

Instead, use:

git submodule foreach "git status || true"

This will go through each submodule and perform a status, without any errors.

Now go forth and celebrate your success!

wvrex2

Android: How to parse an XML string

There are quite a few examples on how to parse XML from a resource or InputStream, however only a handful will show you how to parse a String in XML format.

Luckily, the method is very similar to most of the other examples as you still need to use a SAX ContentHandler.

Consider the example XML file:

<?xml version="1.0" encoding="UTF-8"?>
<scoreboard lastUpdated="1292447376" version="1.0">
<highscores players="8579">
<score points="587" player="twig" when="1292447376"></score>
<score points="447" player="sheik" when="1292437376"></score>
<score points="396" player="tux" when="129242000"></score>
<score points="276" player="nunkii" when="129241000"></score>
<score points="187" player="Anonymous" when="129240000"></score>
</highscores>
<scores submitted="50">
<score points="587" player="twig" when="1292447376"></score>
<score points="104" player="twig" when="1292447370"></score>
<score points="103" player="twig" when="1292447360"></score>
<score points="50" player="twig" when="1292447350"></score>
<score points="20" player="twig" when="1292447340"></score>
</scores>
</scoreboard>

Once you've got your XML string, parse it using:

ContentHandler parser = new ScoreboardXmlParser();
Xml.parse(strXML, parser);

Scoreboard sb = parser.scoreboard;

Now for the ContentHandler class. The main functions to implement are:

  • startDocument(): You can use this to initialise any lists to store data.
  • endDocument(): To know when you've finished parsing and clean up after yourself.
  • startElement(): When the parser reaches a new element. You can also access the element attributes here.
  • endElement(): When the element is done with the current element and ready to move onto the next.

Everything else you can leave empty.

This is the complete class.

import java.util.ArrayList;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

public class ScoreboardXmlParser implements ContentHandler {
private long lastUpdated;
private int totalPlayers;
private int totalSubmissionsFromPlayer;
private ArrayList<Score> highScores;
private ArrayList<Score> playerScores;
private ArrayList<Score> m_currentList;
public Scoreboard scoreboard;

@Override
public void startDocument() throws SAXException {
highScores = new ArrayList<Score>();
playerScores = new ArrayList<Score>();
lastUpdated = 0;
totalPlayers = 0;
totalSubmissionsFromPlayer = 0;
}

@Override
public void endDocument() throws SAXException {
scoreboard = new Scoreboard();
scoreboard.lastUpdated = lastUpdated;
scoreboard.totalPlayers = totalPlayers;
scoreboard.totalSubmissionsFromPlayer = totalSubmissionsFromPlayer;
scoreboard.highScores = new ArrayList<Score>(highScores);
scoreboard.playerScores = new ArrayList<Score>(playerScores);
}

@Override
public void startElement(String uri, String localName, String name, Attributes atts) throws SAXException {
if (localName.equals("scoreboard")) {
lastUpdated = Long.parseLong(atts.getValue("lastUpdated"));
}
else if (localName.equals("highscores")) {
totalPlayers = Integer.parseInt(atts.getValue("players"));
m_currentList = highScores;
}
else if (localName.equals("scores")) {
totalSubmissionsFromPlayer = Integer.parseInt(atts.getValue("submitted"));
m_currentList = playerScores;
}

if (localName.equals("score")) {
m_currentList.add(new Score(atts));
}
}

@Override
public void endElement(String uri, String localName, String name) throws SAXException {
if (localName.equals("highscores") || (localName.equals("scores"))) {
m_currentList = null;
}
}
}

A little trick here is that both "highscores" and "scores" lists contain an element called "score". I used "m_currentList" to keep track of which list the scores should be added to. Once the parser is finished with either "highscores" or "scores", the list is set back to null.

When the document ends, I just store all the information into into a Scoreboard object. You don't have to do this, but it was just an example to show you what you can do at the end of the parsing.

You should also implement a custom function such as isParsed() to check if the data was parsed correctly or not.

Sources:

Android: Use tabs in your view without XML layout files and TabActivity class

The Android framework has been pretty good to work with so far, until I tried to add a tab widget onto my view. Bloody hell that was fussy!

I'm not particularly fond of using the WYSIWYG editor for the user interface,

All these weird errors were thrown around were due to some expectations within the TabHost and TabWidget classes.

I'll try to explain what I can remember.

// This simple class just extends the LinearLayout and adds a Tab widget with 2 listviews, each in its own tab.
public class ScoreScreen extends LinearLayout {
private TabHost host;
private TabWidget widget;

public ScoreScreenView(Context context, final Scoreboard scoreboard) {
super(context);

this.setOrientation(VERTICAL);

// Set up the tab widget and put in onto the view
TabSpec tab;

host = new TabHost(context);
host.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

widget = new TabWidget(context);
widget.setId(android.R.id.tabs);
host.addView(widget, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

// the TabHost needs a frame layout for the views on the tab
FrameLayout frame = new FrameLayout(context);
frame.setId(android.R.id.tabcontent);
host.addView(frame, new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

host.setup(); // Magic function that initialises everything

// Start adding tabs
tab = host.newTabSpec("High Scores").setIndicator("High Scores").setContent(new TabContentFactory() {
@Override
public View createTabContent(String tag) {
ListView lv = new ListView(context);

lv.setAdapter(new ScoreAdaptor(scoreboard.highScores));
return lv;
}
});
host.addTab(tab);

tab = host.newTabSpec("Your Scores").setIndicator("Your Scores").setContent(new TabContentFactory() {
@Override
public View createTabContent(String tag) {
ListView lv = new ListView(context);

lv.setAdapter(new ScoreAdaptor(scoreboard.playerScores));
return lv;
}
});

host.addTab(tab);

// Add the tab to the layout
this.addView(host);

// Set the padding for the frame so the content doesn't cover the tabs
int tabHeight = host.getTabWidget().getChildAt(host.getTabWidget().getChildCount() -1).getLayoutParams().height;
frame.setPadding(0, tabHeight, 0, 0);
}
}

Now I guess we can both go back to doing whatever we were doing...

americapantsp1

Sources

Most of the setup magic cames from PocketMagic.

The code to set the proper non-hardcoded tab height came from StackOverflow.

Android: mBaselineAlignedChildIndex of LinearLayout set to an index that is out of bounds

There are some really whack error messages, and then theres this:

java.lang.RuntimeException: mBaselineAlignedChildIndex of LinearLayout set to an index that is out of bounds"

In laymens terms, all you really need to do is actually add some children to the LinearLayout.

[ Source ]

Android: Set HTTP socket timeout

The default timeout value for a HTTP request is quite long. So long that you'd forget what you were doing and wonder why the game has crashed.

Reduce the timeout value to get more responsiveness out of your app.

HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 5000); // Connection timeout
HttpConnectionParams.setSoTimeout(httpParameters, 3000); // Socket timeout

// Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient(httpParameters);

Now you can use the HttpClient as per usual for GET or POST requests.

[ Source ]

Android: Close the virtual "on-screen" keyboard

There was a slight quirk that I ran into while working on my app. If I were editing text and clicked "Save" on the activity, it'd close the screen but keep the keyboard open.

I'd then have to press the BACK button to close it. A small but somewhat irritating quirk. Luckily, its an easy thing to fix.

First, define an "OnFocusChangeListener":

private OnFocusChangeListener hideKeyboard = new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
};

When you're creating and setting up your edit boxes, just set the following listeners:

txtEmail.setOnFocusChangeListener(hideKeyboard);
txtUsername.setOnFocusChangeListener(hideKeyboard);

There you have it. It should now hide the keyboard automatically.

If no other objects take focus, then just call the listener manually.

hideKeyboard.onFocusChange(txtUsername, false);
hideKeyboard.onFocusChange(txtEmail, false);

[ Source ]

Apache: Run a Django project using mod_wsgi and .htaccess

To get Django up and running under your Apache configuration, you'll need to install mod_wsgi first. This will let Apache run Python code.

Assuming your files are in the format of:

image

For this example, the "forum" folder is the subdomain (http://forum.example.com) and the "forum_project" should be your Django project folder (containing manage.py, settings.py, etc).

In your subdomain folder, create a file called "dispatch.wsgi". This file will tell Apache what to do with the incoming request. In that file, paste:

import os, sys

sys.path.append("/home/twig/public_html/forum/forum_project");

# This refers to the "settings.py" file in forum_project
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

#import django.core.handlers.wsgi
#application = django.core.handlers.wsgi.WSGIHandler()

def application(environ, start_response):
"""Simplest possible application object"""
output = "Hello World"
status = '200 OK'
response_headers = [('Content-type', 'text/plain'), ('Content-Length', str(len(output)))]
start_response(status, response_headers)
return [output]

Now to create a file called ".htaccess", which will funnel all the URLs into dispatch.wsgi.

RewriteEngine On
RewriteBase /
RewriteRule ^(media/.*)$ - [L]
RewriteRule ^(admin_media/.*)$ - [L]
RewriteRule ^(dispatch\.wsgi/.*)$ - [L]
RewriteRule ^(.*)$ slowpoke/dispatch.wsgi/$1 [QSA,PT,L]

Lastly, add a few lines in your domain's vhost file so it knows to use Python and WSGI for requests.

<IfModule mod_wsgi.c>
WSGIScriptAlias / /home/twig/public_html/forum/dispatch.wsgi
WSGIDaemonProcess myapp processes=5 threads=1 display-name=%{GROUP}
WSGIProcessGroup myapp
WSGIApplicationGroup %{GLOBAL}
</IfModule>

Time to test the server. Open up the browser and point it to your domain. It should display "Hello world". If not, check your error logs. A useful guide to debugging WSGI errors is available on the mod_wsgi documentation pages.

Once its up and running, uncomment the Django wsgi code and delete the application() function from dispatch.wsgi. Your code should now look like this.

import os, sys

sys.path.append("/home/twig/public_html/forum/forum_project");

# This refers to the "settings.py" file in forum_project
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

That should be enough to get your project up and running with Apache, Django and mod_wsgi.

See here to serve CSS/JS/image files out of Django. For anything else Django related see here.

Sources

Linux: Log into a server using SSH without entering password

One of those little handy-things-to-have is the ability to log into a remote computer without having to enter in the password every time.

To do that, we have to generate a pair of authentication keys for the computers A and B.

On computer A, make sure you have a folder called ".ssh". If not, create it.

  • Type in "ssh-keygen -t rsa"
  • Save it to "~/.ssh/id_rsa"
  • Don't enter in a passphrase (just press enter)
  • Open ".ssh/id_rsa.pub" and copy the contents.

Now on computer B, create a folder called ".ssh" (if it doesn't already exist).

Create "~/.ssh/authorized_keys" and paste in the contents of id_rsa.pub. Save and exit.

Now you should be able to connect from computer A to B without any problems.

[ Source ]

Android: MediaPlayer stops playing sounds and AudioFlinger starts throwing "no more track names availlable"

This error occurs when you've created too many MediaPlayer instances without cleaning up your own filthy mess.

AudioFlinger: no more track names availlable
AudioTrack: AudioFlinger could not create track, status: -12
AudioSink: Unable to create audio track
VorbisPlayer: mAudioSink open failed

Instead, you should either reuse MediaPlayer instances or use the SoundPool class.

Note: The strange way of spelling "availlable" is a typo in the framework.

Reuse MediaPlayer

If you want to reuse the MediaPlayer, just remember to clean up after yourself and call MediaPlayer.release() after you're done.

Otherwise, dedicate one MediaPlayer instance to each sound effect and reuse it each time you play that specific sound.

Use SoundPool

This class manages multiple sounds for you, so you can set the maximum number of channels. It also handles stuff like left/right speaker volume, pausing, stopping, etc.

The annoying thing however is that it returns its own "Sound ID", which you have to keep track of. You get the new sound ID after you've loaded it up.

I've written a small class which uses a HashMap to keep track of them.

public class Sound {
private SoundPool m_soundPool;
private HashMap<Integer, Integer> m_soundIDs;

public Sound() {
int[] sounds = { R.raw.menu, R.raw.dizzy, R.raw.pokewrong, R.raw.go, R.raw.ready, R.raw.win, R.raw.music, };

m_soundIDs = new HashMap<Integer, Integer>();
m_soundPool = new SoundPool(8, AudioManager.STREAM_MUSIC, 0);

for (int sfx : sounds) {
m_soundIDs.put(sfx, m_soundPool.load(G.activity, sfx, 1));
}

}

public void play(int resid) {
if (!G.settings.sfx) {
return;
}

m_soundPool.play(m_soundIDs.get(resid), 1.0f, 1.0f, 1, 0, 1.0f);
}

Using this class, all you really have to pass in to play the sound is the resource ID.

Sources

Android: Disable camera sound

This is the most "stock" way of disabling the camera sound. The easiest way by far is to just download a camera app which takes photos silently.

I quite like the app which comes with my Samsung Galaxy S, so I figured I'd keep using it and just change the settings instead.

First of all, you need a rooted phone for this to work.

Second, you'll need "adb.exe" to manage the files.

If you're running Linux as your operating system, you can just mount the system drive and just access it as normal.

Disabling the camera click

  • To copy "default.prop" to your computer, type in: "adb pull /system/default.prop"
  • Now edit the file and search for "ro.camera.sound.forced"
  • If it exists, change it to 0.
  • Otherwise, add this to the file: "ro.camera.sound.forced=0", and remember to leave a blank line at the end
  • Save the file
  • Now copy the file back onto the phone using "adb push default.prop /sdcard/"
  • Connect to the phone: "adb shell"
  • Type in "su" to gain super user access.
  • Type in "cat /sdcard/default.prop > /system/default.prop" to replace your system settings
  • Optionally you can clean up by deleting "default.prop" from your computer and phone "/sdcard" directory.

Some extra reading

The magic line in this method is the "cat" method. Using the usual "mv" command to move files will fail with the error "Cross-device link" as Unix will not allow you to move files mv from device to device. Kudos to darkxsun from androidforums for that one!

Sources

Samsung Galaxy S: Wifi no longer detects any networks and unable to scan networks

My Samsung Galaxy S decided to chuck a hissy fit and ignore WiFi networks. I believe it's because I entered in a blank password with the WP2 encryption method.

The WiFi mode comes on temporarily to scan, decides it can't, displays an error message then turns off by itself. Sadly, to fix this problem you have two options.

Factory reset

The first is to do a factory reset. I personally think this sucks because I customise a great portion of the phone to maximise battery life.

Rooted access?

The second is to root the phone and delete the existing WiFi settings.

  • Root your phone
  • Move or rename "/sdcard/data/wifi/bcm_supp.conf"

To move or rename, you can use "adb shell" and request superuser access with the "su" command.

Another way is to use a file explorer such as ASTRO file explorer which can be downloaded from the market place.

Once the file is removed, just do a WiFi scan again and it should work.

Happy go lucky?

According to skeerthy who posted in the second source link on androidforums.com, he was able to remove the file using "ddms.bat". Search for "SOLUTION - WITHOUT ROOTING" to find his post.

I didn't have any luck with that because the phone would not let me browse the "data" directory.

Sources

Android: Root your phone safely without modifying any files

When I first wanted to root the phone, I got alot of results pointing me to TGA_Gunnman's method of rooting. This method uses the Android's system recovery method with "update.zip" to replace files and run a script which modifies some settings.

I personally found it cumbersome and it didn't work on my Samsung Galaxy S GT-i9000 (running Eclaire 2.1-update1 with Canadian firmware I9000UG JH2).

What's worse is that it required the .NET 4 framework to run a stupid user interface (that doesn't actually load, even with the damn .NOT framework installed!). In the end, all you really had to do is run the root.bat file (for Android 2.1).

  • Wasted time installing .NET framework 4 because the stupid program doesn't work anyway
  • Wasted time figuring out what script file to use
  • Wasted time trying to remove the files it installed
  • Wasted time because it didn't even work!

The solution

To get RyanZA's z4root working on your phone, first check to see if its supported. At time of writing, the list of phones supported by v1.3.0 are:

  • (permanently root)
    • Samsung Galaxy S (All variants)
    • Backflip
    • Sony X10
    • Xperia Mini
    • Droid 2
    • Galaxy Tab
    • Galaxy I5700
    • Galaxy 3 I5800
    • Droid X
    • Samsung Acclaim
    • Cricket Huawei Ascend
    • Motorola Cliq
    • Huawei 8120
    • Hero
    • G1
    • Optimus T
    • Droid 1
    • Garmin Asus A50
    • Motorola Defy
    • LG Ally
    • Motorola Flipside
    • Motorola Milestone 2
    • Dell streak
    • X10 Mini Pro
    • Smartq v7 android 2.

 

  • (temporary root only)
    • Desire (requires nand unlock)
    • Desire HD (requires nand unlock)
    • Magic (unknown)
    • Evo (requires nand unlock)
    • G2 (requires nand unlock)
    • Archos 70 (unknown)
    • myTouch 3G (unknown)
    • Wildfire
    • Droid Incredible

Procedure

Firstly, you need to register to download the latest release from the official thread. If you're ok with downloading from an unofficial source then I'm probably not able to help you if something goes wrong.

Now copy the file onto your phone somehow. You've got 3 options.

  • Using a memory card
    If your phone supports it, just copy the file onto the SD card.
  • Using adb.exe to push it:
    This uses the debugger to copy the file directly onto the phone. I'm assuming you have it installed somewhere. Open up a command prompt and type in:

adb push z4root.1.3.0.apk /sdcard/

  • Using a file explorer
    You'll have to download a file explorer type app from the app market. Most people seem to recommend ASTRO file explorer, but I've personally never used it.

Once the file is on your phone, click it to install it.

Open the "z4root" app and click on the rooting method of your choice.

So painless compared to the other methods, especially without all the brick-anxiety that comes with the whole recovery mode updates.

[ Source ]

Android: Recovery mode stuck on "Installing muti-csc"

A super noob mistake on my behalf, but I've seen a few posts on this issue.

If your phone is stuck in recovery mode and all it says is "Installing muti-csc" and the "reboot system now" option is highlighted, simply select the "apply sdcard:update.zip" option using the volume buttons and select with your select button.

image 

Once you do that, it'll start updating :)

django: Remove ugly "Thank you for your comment" message after posting comments

Django comments are really really easy to use, but one of the strangest quirks is that it displays a really ugly confirmation page after you've posted a comment. Luckily, its easy to fix.

image The first option is to prevent it from being shown altogether.

{% with your_object.get_absolute_url as next %}
{% render_comment_form for your_object %}
{% endwith %}

The second is to override the "content" block with a custom "comments/posted.html" file. That way you can fill it up with all sorts of silly messages.

  • Create "your_project/templates/comments/posted.html"
  • In it, put:

{% extends "your_base_file.html" %}

{% block content %}This is another silly message.{% endblock content %}

This way, you can still get your site's look and feel when displaying the thank you message.

Python: Define a static function in a class

Most functions in a class will refer to a "self" instance.

If you want a static function, you'll have to add the @staticmethod decorator.

class Something(object):
@staticmethod
def get_by_name(name):
return "Hello world"

[ Source ]

 
Copyright © Twig's Tech Tips
Theme by BloggerThemes & TopWPThemes Sponsored by iBlogtoBlog