Wednesday, March 28, 2012

Seven Languages in Seven Weeks - Io Day 3 Self-Study

It's been some time now, still I'm keeping up reading Seven Languages in Seven Weeks. Here's the last self-study section about the Io programming language.

Enhance the XML program to add spaces to show the indentation structure.

Builder := Object clone
Builder numIndents := 0
Builder doIndents := method (for (i, 1, numIndents, write(" ")))
Builder openTag := method(name, doIndents; writeln("<", name, ">"))
Builder closeTag := method(name, doIndents; writeln("</", name, ">"))
Builder forward := method (
  openTag(call message name);
  numIndents = numIndents + 1;
  call message arguments foreach (
    arg,
    content := self doMessage(arg);
    if (content type == "Sequence", doIndents; writeln(content))
  );
  numIndents = numIndents - 1;
  closeTag(call message name)
)

Builder ul(
  li("Javascript"),
  li("Lua"),
  li("Javascript")
)

Create a list syntax that uses brackets

squareBrackets := method(call message arguments)

Enhance the XML program to handle attributes: if the first argument is a map (use the curly brackets syntax), add attributes to the XML program. For example: book({"author": "Tate"}...) would print <book author="Tate">.

OperatorTable addAssignOperator(":", "atPutNumber")
Map atPutNumber := method(
  self atPut(
    call evalArgAt(0) asMutable removePrefix("\"") removeSuffix("\""),
    call evalArgAt(1)
  )
)
curlyBrackets := method(
  map := Map clone;
  call message arguments foreach(arg, map doMessage(arg));
  map
)

Builder := Object clone
Builder numIndents := 0
Builder doIndents := method (for (i, 1, numIndents, write(" ")))
Builder doAttributes := method(map, map keys foreach(key, write(" ", key, "=\"", map at(key) ,"\"")))
Builder forward := method (
  doIndents; write("<", call message name);
  if(call message arguments size == 0, writeln(">"));
  numIndents = numIndents + 1;
  call message arguments foreach (i, arg,
    content := self doMessage(arg);
    if (i == 0, 
      if(content type == "Map", doAttributes(content));
      writeln(">")
    )
    if (content type == "Sequence", doIndents; writeln(content));
  );
  numIndents = numIndents - 1;
  doIndents; writeln("</", call message name, ">")
)

Monday, March 12, 2012

Seven Languages in Seven Weeks - Io Day 2 Self-Study

Here's the next self-study section about the Io programming language. These are several exercises to get some practice.

A Fibonacci sequence starts with two 1s. Each subsequent number is the sum of the two numbers that came before; 1, 1, 2, 3, 5, 8, 13, 21, and so on. Write a program to get the nth Fibonacci number. fib(1) is 1, and fib(4) is 3. As a bonus, solve the problem with recursion and with loops

The recursive approach (very concise):
fib := method(n,  if (n <= 2, 1, fib(n-1) + fib(n-2)))
And with a loop:
fib := method(n,
  p := 1;
  q := 1;
  sum := 1;
  for (i, 3, n,
    sum := p + q;
    p := q;
    q := sum
  );
  sum
)
How would you change / to return 0 if the denominator is zero?
Number div := Number getSlot("/")
Number / := method(n, if (n == 0, 0, self div(n))
Write a program to add up all of the numbers in a two-dimensional array.
a := list(list(1, 2, 3, 4), list(5, 6, 7, 8))
s := 0
a foreach(sublist, s := s + sublist sum)
Or more concise:
a flatten sum
Add a slot called myAverage to a list that computes the average of all the numbers in a list. What happens if there are no numbers in a list? (Bonus: Raise an Io exception if any item in the list is not a number.)
List myAverage := method(self sum / self size)
And with exception handling:
List myAverage := method(
  sum := 0;
  self foreach(e,
    (e isKindOf(Number)) ifFalse(Exception raise("not a number"));
    sum := sum + e
  );
   sum / self size
)
Write a prototype for a two-dimensional list. The dim(x, y) method should allocate a list of y lists that are x elements long. set(x, y, value) should set the value, and get(x, y) should return that value
List2d := Object clone

List2d dim := method(x, y,
  self rows := List clone;
  for (i, 1, x,
    cols := List clone;
    for (j, 1, y,
      cols append(nil)
    );
    self rows append(cols)
  );
  self
)

List2d set := method(x, y, value, 
  self rows at(x) atPut(y, value);
  self
)

List2d get := method(x, y, 
  self rows at(x) at(y)
)
Bonus: write a transpose method so that (new_matrix get(y, x)) == matrix get(x, y) on the original list.
List2d transpose := method(
  transposed := List2d clone;
  transposed dim(self rows at(0) size, self rows size);
  self rows foreach(i, row, 
    row foreach(j, elem,
      transposed set(j, i, elem)
    );
  );
  transposed;
)
Write the matrix to a file, and read a matrix from a file
List2d toFile := method(filename,
  file := File clone open(filename);
  self rows foreach(col, 
    col foreach (elem,
      file write(elem asString, " ")
    );
    file write("\n")
  );
  file flush close;
  file
)

List2d fromFile := method(filename,
  self rows := List clone;
  file := File clone open(filename);
  file readLines foreach(line,
    cols := line split;
    self rows append(cols)
  );
  self
)
Write a program that gives you ten tries to guess a random number from 1--100. If you would like, give a hint of "hotter" or "colder" after the first guess.
secretNum := Random value(100) floor() + 1
in := File standardInput
for (i, 1, 10,
  write("Guess number (try #", i, "): ");
  guess := in readLine asNumber;
  if (guess == secretNum, write("Win!"); break);
  if (i > 1, 
    if ((secretNum - guess) abs < (secretNum - previousGuess) abs,
      write("hotter\n"),
      write("cooler\n")
    )
  );
  previousGuess := guess;
)

Thursday, March 8, 2012

Seven Languages in Seven Weeks - Io Day 1 Self-Study

Here's the first self-study section about the Io programming language. I didn't know Io before, I still find it a bit awkward, but I'm beginning to like it.

Evaluate 1 + 1 and then 1 + "one". Is Io strongly typed or weakly typed? Support you answer with code.
Io> 1 + 1
==> 2
Io> 1 + "one"

  Exception: argument 0 to method '+' must be a Number, not a 'Sequence'
  ---------
  message '+' in 'Command Line' on line 1
Io is strongly typed, operands of different types will not be implicitly converted:
Io> 1 + "2"

  Exception: argument 0 to method '+' must be a Number, not a 'Sequence'
  ---------
  message '+' in 'Command Line' on line 1
Is 0 true or false? What about the empty string? Is nil true or false? Support your answer with code.
Io> 0 and true
==> true
Io> "" and true
==> true
Io> nil and true
==> false
How can you tell what slots a prototype supports?

Invoking an object in the prompt will print the supported slots:
Io> Car
==>  Car_0x7fb039c9a1f0:
  type             = "Car"
  vroom            = method(...)
The slotNames message returns the list of slots:
Io> Car slotNames
==> list(type, vroom)
To get the slots defined by the parent, call the proto message:
Io> Car proto
==>  Vehicle_0x7fb039c6e270:
  description      = "Something that takes you far away"
  type             = "Vehicle"
What is the difference between = (equals), := (colon equals), and ::= (colon colon equals)? When would you use each one?
=Assigns value to slot if it exists, otherwise raises exception
:=Creates slot, assigns value
::=Creates slot, creates setter, assigns value
Run an Io program from a file
$ echo '"Hello, world!" println' > helloworld.io
$ io helloworld.io 
Hello, world!
Execute the code in a slot given its name

Unfortunately, I haven't been able to solve this one yet. I guess the intent is given a slot holding some code as a string, one should figure out a statement to execute this code.
Io> code := "\"hello\" println"
==> "hello" println

Sunday, March 4, 2012

Password Security 101 for Web Developers

Passwords are still the only mean of authentication for I'd say 99.95% of all online services including social networking sites, online shops and even e-banking applications. When you think about the consequences of a password theft, say for your personal email account, you'll soon realize that a password such as 123456, iloveyou or your mom's birthdate is totally insufficient... (see this and change your password everywhere if you get a match).

There a lots of articles that will tell you what a (more) secure password looks like (I especially like this one as well as it's illustration). And although many web sites will impose some password policy during registration that will reject any password unless it contains some digit or special characters, the choice (and the complexity) is ultimately left to the user. What's unavoidable is that users are almost certainly going to reuse at least one password sometime for one or the other online service. Haven't you also? (don't blush).

So what can you as a developer do about it? I don't know, but I can tell you what you should totally avoid if you don't want yourself and your company to be looked at as total newbs.

First realize that passwords are the user's good and you are due to treat that information with absolute care. Every single one of your clients has spent the effort of selecting some unnatural string, repeating the process until it complied with your password policy and spending the rest of the day trying not to forget it. This is the reason why user's will eventually reuse a password. So bear in mind, that you're not storing a user's password for your web application only, but most probably also for a number of other services the user has registered to. Respecting your client's integrity means that you will never disclose that data, not even internally within your company.

The most important precaution you should take when dealing with password data is: never ever store passwords in clear text. No system is safe enough, not even yours. And the risk's not worth it. If you don't know how to avoid storing passwords in clear text, learn about hash functions and salting.

Second rule: never ever send a password back to the user (for instance via email). This is totally unprofessional. You're not only showing your client that you're storing passwords in clear text (i.e. that you're a newb), you're also compromising his password by sending it over an unsecure channel.

I assume companies do this to reduce support cases related to lost passwords. They should rethink it all over. Recent attacks have shown how much damage is caused to the company (reputation) as well as to their clients by having confidential user data stolen. Think about RSA, the Sony Playstation network or recently Youporn (should you not know, the most popular pornographic website)...

Friday, March 2, 2012

Seven Languages in Seven Weeks - Ruby Day 3 Self Study

Hi again. Here's the self-study section for day 3 from the book Seven Languages in Seven Weeks, the last one about ruby.

Modify the CSV application to support an each method to return a CsvRow object. Use method_missing on that CsvRow to return the value for a given heading.
module ActsAsCsv
  
  def self.included (base)
    base.extend ClassMethods
  end
  
  module ClassMethods
    
    def acts_as_csv
      include InstanceMethods
    end
    
    module InstanceMethods
      
      class CsvRow
        def initialize (headers, row)
          @headers = headers
          @row = row
        end
        
        def method_missing (name, *args)
          index = @headers.index(name.to_s)
          @row[index] unless index.nil?
        end
      end
      
      def read
        @csv_contents = []
        filename = self.class.to_s.downcase + '.txt'
        file = File.new(filename)
        @headers = file.gets.chomp.split(', ')
        file.each do |row|
          @csv_contents << CsvRow.new(headers, row.chomp.split(', '))
        end
      end
      
      attr_accessor :headers, :csv_contents
      
      def initialize
        read
      end
      
      def each (&block)
        @csv_contents.each(&block)
      end
    end
  end
end