Zeven Rodriguez

Fall2010

Android Sms Tracking

mobilemedia, Tutorials

Comments Closed


Share this post

This application grabs gps location with on button and the second button sends a text message to my phone number.

package com.zevenwolf.tracking;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class Tracking extends Activity implements LocationListener, OnClickListener {
    /** Called when the activity is first created. */

    private LocationManager lm;

    Button gpsButton;
    Button messageButton;
    public String lat;
    public String lon;
    public String message;

    PendingIntent sentPI;
    // The intent action we are using
    String SENT = "SMS_SENT";
    BroadcastReceiver br;
    TextView lats;
    TextView lons;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

         lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
         lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000l, 5.0f, this);
         lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000l, 5.0f, this);

         lats = (TextView) this.findViewById(R.id.lat);
         lons = (TextView) this.findViewById(R.id.lon);

         sentPI = PendingIntent.getBroadcast(this, 0,
                    new Intent(SENT), 0);

        gpsButton = (Button) this.findViewById(R.id.gps);
        messageButton = (Button) this.findViewById(R.id.message);


        // The important thing is to set the onclicklistner event with in the setOnClickListener
        gpsButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {

                   lats.setText(lat);

                   lons.setText(lon);

                   message = lat + " " + lon;
                   Log.d("message", message);

                   Log.d("view", "hit");

            }});


        messageButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {


                   Log.d("view", "hit");

                   SmsManager sms = SmsManager.getDefault();
                    // send the message, passing in the pending intent, sentPI
                    sms.sendTextMessage("phonenumber", null, message, sentPI, null);

                    registerReceiver(br, new IntentFilter(SENT));



            }});


        // this broadcastreceiver when sent a receive code sends back a specific code which you then display

        br = new BroadcastReceiver(){
            @Override
            public void onReceive(Context ctx, Intent intent) {
                switch (getResultCode())
                {
                    case Activity.RESULT_OK:
                        Toast.makeText(getBaseContext(), "SMS sent",
                                Toast.LENGTH_SHORT).show();
                        break;
                    case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                        Toast.makeText(getBaseContext(), "SMS: Generic failure",
                                Toast.LENGTH_SHORT).show();
                        break;
                    case SmsManager.RESULT_ERROR_NO_SERVICE:
                        Toast.makeText(getBaseContext(), "SMS: No service",
                                Toast.LENGTH_SHORT).show();
                        break;
                    case SmsManager.RESULT_ERROR_NULL_PDU:
                        Toast.makeText(getBaseContext(), "SMS: Null PDU",
                                Toast.LENGTH_SHORT).show();
                        break;
                    case SmsManager.RESULT_ERROR_RADIO_OFF:
                        Toast.makeText(getBaseContext(), "SMS: Radio off",
                                Toast.LENGTH_SHORT).show();
                        break;
                }

                unregisterReceiver(br);
            }

        };


    }
public void onPause(){

    super.onPause();
    finish();

}
    // onPause
    //super onpause
    // run finish there

    @Override
    public void onLocationChanged(Location arg0) {
        lat = String.valueOf(arg0.getLatitude());
        lon = String.valueOf(arg0.getLongitude());


        Log.d("GPS", "location changed: lat=" + lat + ", lon=" + lon);
        Log.d("hello", "stff");

    }

    public void onProviderDisabled(String arg0) {
        Log.d("GPS", "provider disabled " + arg0);
        Log.d("hello", "stff");

    }

    public void onProviderEnabled(String arg0) {
        Log.d("GPS", "provider enabled " + arg0);
        Log.d("hello", "stff");

    }

    public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
        Log.d("GPS", "status changed to " + arg0 + " [" + arg1 + "]");
        Log.d("hello", "stff");

    }

     public void setGPS(String theText)
       {

       }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub

    }



}

Read more

How Does Your City Feel?

understandingnetworks

Comments Closed


Share this post

How Does Your City Feel? captures the emotions people feel in their cities by measuring them in the contents of local real-time Twitter messages.
What are people feeling in New York City? Seattle? San Francisco? Sad? Happy? Angry? Love?
When you visit, please choose a city and click an emotion to see the results. If you click only on the city, you will see a graph of the emotions measured by the statement, “I feel…” The mapping is created instantly via Google Charts API by parsing XML from Twitter’s search results. How Does Your City Feel is coded with Javascript, and AJAX. So far, I’ve been tickled by the different moods each city exhibits. San Francisco appears more relaxed while New York shows more emotional volatility. When New Yorkers feel love, they really express it – same goes for anger! See the screen shots below for more examples.
How Does Your City Feel? was created by Cindy Wong andZeven Rodriguez.
New York City

San Francisco

Seattle

Read more

Connections: Final Project Proposal

mobilemedia, understandingnetworks

1 Comment


Share this post

Connections is an multiuser interactive installation that uses a mobile web application as a collaboration tool. The system uses various nodes to accomplish this. The mobile application is the input method. A computer with a projector and arduino control the output. A server processes and syncs all communication between the computer, arduino, and mobile application.

Goal
This project is to highlight the importance of peoples connections. We emit alot of noise in the world, but at at some point we make that connection with someone that drowns out the rest of it.

Here is the working display. The selects 2 bottom squares.

How it works?
The user visits a website. They will be greeted with this application.

There they select a color the represents them, followed by selecting a block that will start emitting connection particles. Simultaneously a block (of the same color) will appear in the center “arena”. This is a worm hole for particles. So, if you create a red emitter you create a red collector. Particles have strong rules that attract them to the worm holes. The particles can only make connections once they are in the center “arena”. When particles start emitting they will have there own sound. Finally, at some point 2 different particles will make a connection. Once particles make a connection their combined tone will drown out the rest of the emitting particles.

connections
Laying out a pattern to cut out the foam. This was used to fit the the LED blocks.

Connections
This the first fitting of the blocks on the foam

Connections
Rune making the connections for the LED blocks


Testing the interfacing between the computer and led blocks


Running the web app with projection display

connections
Our most excited user.

Next Steps

  • Fix power issue. Because we are stringing so many of these addressable LEDs. They have a voltage drop off of .3 volts. We are going to address this by using multiple power supplies
  • Skin the front
  • Create more graphical interaction when particles connect

Issues

  • We found that decoupling the ground and the data by adding a .1 microfarad cap and 1k resistor in parallel fixed some syncing issues. We found that when we touched the wire the data and clocks would sync up. Eric Rosenthal gave us the idea of decoupling ground and data. We still had issues at the end of the 64 leds with sync

Read more

Android GPS Code

mobilemedia, Tutorials

Comments Closed


Share this post
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class Tracking extends Activity implements LocationListener, OnClickListener {
    /** Called when the activity is first created. */

    private LocationManager lm;

    Button gpsButton;

    public String lat;
    public String lon;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

         lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
         lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000l, 5.0f, this);
         lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000l, 5.0f, this);



        gpsButton = (Button) this.findViewById(R.id.gps);
        gpsButton.setOnClickListener(this);


    }



    @Override
    public void onLocationChanged(Location arg0) {
        lat = String.valueOf(arg0.getLatitude());
        lon = String.valueOf(arg0.getLongitude());


        Log.d("GPS", "location changed: lat=" + lat + ", lon=" + lon);
        Log.d("hello", "stff");
    }

    public void onProviderDisabled(String arg0) {
        Log.d("GPS", "provider disabled " + arg0);
        Log.d("hello", "stff");

    }

    public void onProviderEnabled(String arg0) {
        Log.d("GPS", "provider enabled " + arg0);
        Log.d("hello", "stff");

    }

    public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
        Log.d("GPS", "status changed to " + arg0 + " [" + arg1 + "]");
        Log.d("hello", "stff");

    }

     public void setGPS(String theText)
       {

       }

    @Override
    public void onClick(View arg0) {
        // TODO Auto-generated method stub

         TextView lats = (TextView) this.findViewById(R.id.lat);
           lats.setText(lat);

           TextView lons = (TextView) this.findViewById(R.id.lon);
           lons.setText(lon);

    }
}

Read more

Exquisite-mobile.com

mobilemedia

Comments Closed


Share this post

Exquisite-mobile.com is a game based on the exquisite corpse model. The game is set as like call and response. A prompt is presented and the user responds with a text or picture depending on the round. This is The game is setup as a admin and user interaction. The admin sets up the game and introduces the first prompt.

This is how we create games.

<?php

$tableName = $_POST["fname"];
$roundNumber = $_POST["roundNumber"];
$roundType = $_POST["roundType"];
$submission = $_POST["submission"];
$gameusers = $_POST["gameusers"];
//$tableName = "hello";

$mysql = sqlConnect();

$gametable = "CREATE TABLE  `exmob`.`$tableName` (
`gamesID` INT( 127 ) NOT NULL AUTO_INCREMENT ,
`gameID` INT( 127 ) NOT NULL ,
`roundNumber` INT( 127 ) NOT NULL ,
`roundType` VARCHAR( 127 ) NOT NULL ,
`submissionTable` VARCHAR( 127 ) NOT NULL ,
`userTable` VARCHAR( 127 ) NOT NULL ,
PRIMARY KEY (  `gamesID` )
)"
;

sqlQuery($gametable, $mysql);

$insertGameID = "INSERT INTO  `exmob`.`$tableName` (
`gamesID` ,
`gameID` ,
`roundNumber` ,
`roundType` ,
`submissionTable` ,
`userTable`
)
VALUES (
NULL ,  '$tableName',  '$roundNumber',  '$roundType',  '$submission',  '$gameusers'
);"
;

sqlQuery($insertGameID, $mysql);

$game = "CREATE TABLE  `exmob`.`$submission` (
`subID` INT( 127 ) NOT NULL AUTO_INCREMENT ,
`roundNumber` INT( 127 ) NOT NULL ,
`gameID` INT( 127 ) NOT NULL ,
`userID` INT( 127 ) NOT NULL ,
`media` VARCHAR( 127 ) NOT NULL ,
PRIMARY KEY (  `subID` )
)"
;

sqlQuery($game, $mysql);

$game1 = "CREATE TABLE  `exmob`.`$gameusers` (
`userID` INT( 127 ) NOT NULL AUTO_INCREMENT ,
`name` VARCHAR( 127 ) NOT NULL ,
`gameID` INT( 127 ) NOT NULL ,
PRIMARY KEY (  `userID` )
)"
;

sqlQuery($game1, $mysql);


$sql1 = "SHOW TABLES FROM `exmob`";

$result1 = mysql_query($sql1);

if (!$result1) {
    echo "DB Error, could not list tablesn";
    echo 'MySQL Error: ' . mysql_error();
    exit;
}

while ($row1 = mysql_fetch_row($result1)) {
    echo "Table: {$row1[0]}n";
}


header("Location: http://www.exquisite-mobile.com/admin.php"); /* Redirect browser */
?>

This is how we change levels. This type of script is a backbone for not only change levels, but also for adding players. You will notice when I use the var count I look at the current amount of tables in the database. I assume that the admin will create 3 tables: a game, player, and submissions table. The order is displayed alphabetically I assume that the total tables are divided by 3. So when I create the first game I have game1,sub1,user1. When I add another game, the table will look like this game1,game2,sub1,sub2,user1,user2. Thus total number of tables is 6 divide that by 3 you get 2. 2 is the latest table. Then by multiplying by 2 and 3, I get the index of the corresponding sub and user table.

<?php
$i=1;
$tableArray = array();
//include 'creategame.php';

$round = $_POST["round"];
$roundType = $_POST["roundType"];
//echo $round;
//GENERAL SQL CONNECT
sqlConnect();

//SQL CONNECT WITH VAR
$mysql = sqlConnect();

//LOOK AT THE DATABASE AND PULL OUT THE TABLES
$sql1 = "SHOW TABLES FROM `exmob`";

$result1 = mysql_query($sql1);

if (!$result1) {
    echo "DB Error, could not list tablesn";
    echo 'MySQL Error: ' . mysql_error();
    exit;
}

while ($row1 = mysql_fetch_row($result1)) {
    //echo $row1[0];
    $tableArray[$i] = $row1[0];
    //echo $tableArray[$i];
    $i++;

}
//THE ADMIN SUBMITS 3 TABLES AT A TIME SO THE MORE TABLES 3 WOULD BE THE MULTIPLIER TO FIND THE MOST RECENT 3 THAT WERE ADDED
$count = count($tableArray);
//echo $count;
$mostrecent = ($count/3);
//echo $mostrecent;

$gameTableNum = ($mostrecent);
$subTableNum = ($mostrecent * 2);
$usersTableNum = ($mostrecent * 3);

$gameTable = $tableArray[$gameTableNum];
$subTable = $tableArray[$subTableNum];
$usersTable = $tableArray[$usersTableNum];

//echo $gameTable;
//echo $subTable;
//echo $usersTable;

// find the gamesID orderby
$changeround = "UPDATE  `exmob`.`$gameTable` SET  `roundNumber` =  '$round',
`roundType` =  '$roundType' WHERE  `$gameTable`.`gamesID` =1 LIMIT 1 ;"
;

sqlQuery($changeround, $mysql);

header("Location: http://www.exquisite-mobile.com/admin.php"); /* Redirect browser */
?>

This is the script we used for uploading images. One of the big issues with php is its default upload tmp dir. Sometimes you will not have access to read and write to the temp dir. To bypass this you need to put a new php.ini file where you set the upload_temp_dir to whatever directory you want to use. For dreamhost it wanted it in a cgi-bin folder on the same level dir as the rest of your files.

if((!empty($_FILES["uploaded_file"])) && ($_FILES['uploaded_file']['error'] == 0)) {
  //Check if the file is JPEG image and it's size is less than 350Kb
  $filename = basename($_FILES['uploaded_file']['name']);
  $ext = substr($filename, strrpos($filename, '.') + 1);
  if (($ext == "jpg") && ($_FILES["uploaded_file"]["type"] == "image/jpeg") &&
    ($_FILES["uploaded_file"]["size"] < 35000000)) {
    //Determine the path to which we want to save this file
      $newname = dirname(__FILE__).'/upload/'.$filename;
      echo $newname;
     //newname to insert.php
      //Check if the file with the same name is already exists on the server
      if (!file_exists($newname)) {
        //Attempt to move the uploaded file to it's new place
        if ((move_uploaded_file($_FILES['uploaded_file']['tmp_name'],$newname))) {
           echo "It's done! The file has been saved as: ".$newname;
        } else {
           echo "Error: A problem occurred during file upload!";
        }
      } else {
         echo "Error: File ".$_FILES["uploaded_file"]["name"]." already exists";
      }
  } else {
     echo "Error: Only .jpg images under 350Kb are accepted for upload";
  }
} else {
 echo "Error: No file uploaded";
}

Read more

Final Project(or) tests

greenfab

Comments Closed


Share this post

For our final project for Greenfab, we are making a light graffiti project. We are looking to use cardboard boxes or tubes, 10mm led, a blinking circuit, and a nocturnal circuit to power the whole thing. Allison and I looked at how to do a projection system easily. We used a small cardboard box with a hole.

We initially tried 3 lights.

We then used the circle we cut out as a model for our stencil.

We found that one light was better then 3 lights. The LED operate well at 3.5v and 120mA.

We found some round cardboard tube and found that we can get a longer projection.

Read more

Traceroute Miami and New York

understandingnetworks

Comments Closed


Share this post

For Understand Networks, we had to run a traceroute on 24 sites. I did it located in Miami and New York. I wrote a python parser that takes in a large text file with all of the traceroutes and sorts what IPs were hit the most. I ran the traceroute on windows with this command tracert thensite.com >>master.txt. The >> appends to the end of an existing file. One thing I noticed with these maps is that most of my traffic was routed through the same IPs.

This is the site I used to make the map.

http://www.topwebhosts.org/tools/ip-locator.php

import re
from operator import itemgetter
def makeDict(site):
    superList = list()
    tempList = list()
    ip = str()
    timeList = list()
    avTime = int()
    map = dict()
    textAddress = ' '
    siteLister = list()
    for line in site:
        line = line.strip()
        siteLister.append(line)

    for i in range(4,len(siteLister)):
        if i >=4:
            listSplit = siteLister[i].split(' ')
            for num in range(0,len(listSplit)):
                    if 'ms' in listSplit[num]:
                        if ('<1' in listSplit[num-1]):
                            timeList.append("1")
                        else:
                            timeList.append(listSplit[num-1])

                    if re.findall(r"bw+.",listSplit[num]):
                        if re.findall(r"b(d{1}|d{2}|d{3}).(d{1}|d{2}|d{3}).(d{1}|d{2}|d{3}).(d{1}|d{2}|d{3})b",listSplit[num]):
                            tempList = re.findall(r"b(d{1}|d{2}|d{3}).(d{1}|d{2}|d{3}).(d{1}|d{2}|d{3}).(d{1}|d{2}|d{3})b", listSplit[num])
                            tempList = tempList[0]
                        #print tempList
                            for word in tempList:
                                ip = ".".join(tempList)
                        #print ip
                        else:
                            textAddress =  listSplit[num]
                            #print textAddress
                    if (len(timeList)==3):
                        avTime = (int(timeList[0]) + int(timeList[1]) + int(timeList[2])) / 3


            if ' ' in textAddress:
                textAddress = ip

            #map[ip]= [textAddress,avTime]
            superList.append([ip,textAddress,avTime])
            textAddress = ' '
            avTime = 0
            timeList = []
            tempList = []
            ip = ' '
    #print map
    return superList
    #print map.keys()

def sortIps(listBig):
    siteList = list()
    allMap = dict()
    bigSet = set()

    bigSetList = list()
    for i in range(0,len(listBig)):
        tempString = listBig[i][0]
        bigSet.add(tempString)
#
    bigSetList = list(bigSet)
# run through bigList checking every bigList[i][0] to see if it matches with bigSet[i]
    for i in range(0,len(listBig)):
        tempString = listBig[i][0]
        for j in range(0,len(bigSetList)):
            tempStringSet = bigSetList[j]
            if tempString in tempStringSet:
                if tempStringSet in allMap.keys():
                    allMap[tempStringSet]+=1
                else:
                    allMap[tempStringSet] = 1

    for w in sorted(allMap, key=allMap.get, reverse=True):
        if allMap[w]>1:
            print (w + " : " + str(allMap[w]))

bigList = list()
bigList1 = list()
masterSite = open('sites/master.txt')
masterSite1 = open('site2/master.txt')

print "MIAMI"
bigList = makeDict(masterSite)
sortIps(bigList)
print " "
print "NEW YORK"
bigList1 = makeDict(masterSite1)
sortIps(bigList1)



#for ips in bigSetList:
#    if allMap[ips]>1:
#        print (ips + " : " + str(allMap[ips]))

This is the output from the parser

MIAMI
  : 261
65.14.121.204 : 24
12.122.106.94 : 24
12.122.1.45 : 24
192.168.1.254 : 24
12.122.5.142 : 21
12.81.8.24 : 19
65.14.121.181 : 13
68.152.169.161 : 11
12.81.8.98 : 10
12.122.80.185 : 6
12.81.8.9 : 5
74.175.192.182 : 5
74.175.192.190 : 4
74.175.192.186 : 4
12.81.8.73 : 4
199.181.132.250 : 4
12.81.8.17 : 4
74.175.192.178 : 4
12.122.84.21 : 3
12.81.8.71 : 3
12.122.1.174 : 3
12.81.8.15 : 3
74.175.192.166 : 2
67.16.138.214 : 2
74.175.192.202 : 2
64.125.31.54 : 2
12.122.84.113 : 2
205.186.154.181 : 2
69.195.198.147 : 2
192.205.35.90 : 2
64.30.230.20 : 2
152.52.20.247 : 2
12.122.1.5 : 2
209.170.90.66 : 2
12.122.87.61 : 2
12.123.22.25 : 2
64.125.27.61 : 2
12.122.5.185 : 2
64.210.15.78 : 2
12.81.8.13 : 2
12.81.8.19 : 2
209.131.112.94 : 2
69.60.7.195 : 2
12.81.8.7 : 2
207.97.227.239 : 2
192.205.35.234 : 2
69.63.181.12 : 2
64.124.161.42 : 2
69.60.7.199 : 2
64.131.82.241 : 2
63.246.23.232 : 2
192.205.37.82 : 2
208.80.152.2 : 2
74.175.192.174 : 2
74.125.67.83 : 2
192.205.35.218 : 2

NEW YORK
  : 278
173.56.121.1 : 24
192.168.1.1 : 24
130.81.180.4 : 12
130.81.29.238 : 12
130.81.29.236 : 12
130.81.49.94 : 12
152.63.16.185 : 9
152.63.17.21 : 9
4.69.138.254 : 7
152.63.3.118 : 6
4.68.127.21 : 6
4.69.138.222 : 5
4.69.141.21 : 4
152.63.10.25 : 4
199.181.132.250 : 4
4.69.132.89 : 3
4.69.132.65 : 3
152.63.10.29 : 3
152.63.9.249 : 3
4.69.135.185 : 2
69.63.189.16 : 2
173.194.35.83 : 2
152.52.20.247 : 2
4.71.152.22 : 2
69.195.198.147 : 2
4.69.132.61 : 2
12.122.1.209 : 2
4.78.132.98 : 2
4.68.111.137 : 2
4.69.132.53 : 2
205.186.154.181 : 2
4.69.140.190 : 2
152.63.18.73 : 2
152.63.21.133 : 2
209.131.112.94 : 2
69.60.7.195 : 2
207.97.227.239 : 2
4.68.105.36 : 2
64.30.230.20 : 2
64.131.82.241 : 2
63.246.23.232 : 2
63.85.36.74 : 2
208.80.152.2 : 2
69.60.7.199 : 2
152.63.1.57 : 2
4.69.141.17 : 2

Read more

555 Timer

greenfab, Tutorials

Comments Closed


Share this post

Allison and I used this schematic to blink some lights with a 555 timer. We found out somethings about this circuit. 1. matching the resistors coming off pin 7 and 8 help you even out the blink rate. Also because the 555 timer output makes the voltage change from + to – so  can get the lights the blink at the same time if you orient them the same way.

Read more

Sounds of NY

mobilemedia

Comments Closed


Share this post

Sounds of NY is a project that lets you submit sounds of the city. It uses an email php parser and a processing sketch. The parser was written by Shawn Van Every. By emailing z e v e n w o l f . p i c s  at  g m a i l . c o m and attach your mp3 the sketch picks up the last sound uploaded.

The one thing I had to used fix the parser was when I would post to the database it included my server’s httpdocs in the url path. I used regular expressions to take the /httpdocs/ out. In php, the / starts and ends the regular expression. [^A-Za-z0-9] this sections chooses any non-number and letter in this case the first /. Then it finds httpdocs. Then [^A-Za-z0-9] finds the second /.

$tempData = $data[0]['sound'];
$patterns = "/[^A-Za-z0-9]httpdocs[^A-Za-z0-9]/";
$replacements = '/';
echo preg_replace($patterns, $replacements, $tempData);

Read more

Atari Punk Instructable

greenfab

Comments Closed


Share this post

Atari Punk Instructable

For Design for Greenfab we had to go through a tutorial and critique it. I did the Atari Punk Circuit. Like most instructables it is like shooting blind. The author did a good job of telling you what parts are needed. He also did a step by step of how to put it together. He also gives a brief description on how the circuit works with a schematic. At the end, he suggests how to take it abit further.

The big complaint I have with the step by step is lack of images to make sure your circuit is looking correct. Since I know how to read a schematic I was able to reference that. With the description of how the chip works some more history would have been nice. He mentions briefly types of circuits it originates from. In the end, I have to look at my circuit because it does not sound totally right as you see in the video below.

Read more