Tech Guru Guide Bookazine 07 (Sampler)

Page 1

gem “therubyracer”, “~> 0.11.4” group :development, :test do gem “rspec-rails”, “~> 2.13.0” $ gem install bundler $ gem install rails --version=3.2.12 $ rbenv rehash $ rai new todolist --skip-test-unit respond_to do |format| if @task.update_attributes(params[:task]) format.html { redirect_to @task, notice: ‘...’ } format.json { head :no_content } els format.html { render action: “edit” } format.json { render json: @task.errors, status: :unprocessable_entity } $ bundle exec rails generate migration add_priority_to_task priority:integer $ bundle exec rake db:migrate $ bundle exec rake db:migrate $ bundle exec rails server validate :due_at_is_in_the_past def due_at_is_in_the_past error add(:due_at, ‘is in the past!’) if due_at < Time.zone.now #!/usr/bin/en python import pygame from random import randrange MAX_STARS = 100 pygame.init() screen pygame.display.set_mode((640, 480)) clock = pygame.time.Clock() stars = for i in range(MAX_STARS): star = [randrange(0, 639), randrange(0, 479), randrange(1, 16)] star append(star) while True: clock.tick(30) for event in pygame.event.get(): if event.type == pygame.QUIT: exit(0) #!/usr/bin/perl $numstars = 100; use Time::HiRes qw(usleep use Curses; $screen = new Curses; noecho; curs_set(0); for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] = rand(80); $star_y[$i] = rand(24); $star_s[$i] = rand(4) + 1; } while (1 $screen->clear; for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] -= $star_s[$i]; if ($star_x[$i] < 0) { $star_x[$i] = 80; } $screen->addch($star_y[$i], $star_x[$i], “.”); } $screen->refres usleep 50000; gem “therubyracer”, “~> 0.11.4” group :development, :test do gem “rspec-rails”, “~> 2.13.0” $ gem install bundler $ gem install rails --version=3.2.12 $ rben rehash $ rails new todolist --skip-test-unit respond_to do |format| if @task.update_attributes(params[:task]) format.html { redirect_to @task, notice: ‘...’ } format.json { hea :no_content } else format.html { render action: “edit” } format.json { render json: @task.errors, status: :unprocessable_entity } $ bundle exec rails generate migration add priority_to_tasks priority:integer $ bundle exec rake db:migrate $ bundle exec rake db:migrate $ bundle exec rails server validate :due_at_is_in_the_past def due_at_is_in the_past errors.add(:due_at, ‘is in the past!’) if due_at < Time.zone.now #!/usr/bin/en python import pygame from random import randrange MAX_STARS = 100 pygam init() screen = pygame.display.set_mode((640, 480)) clock = pygame.time.Clock() stars = for i in range(MAX_STARS): star = [randrange(0, 639), randrange(0, 479), randrange( 16)] stars.append(star) while True: clock.tick(30) for event in pygame.event.get(): if event.type == pygame.QUIT: exit(0) #!/usr/bin/perl $numstars = 100; use Time::HiRe qw(usleep); use Curses; $screen = new Curses; noecho; curs_set(0); for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] = rand(80); $star_y[$i] = rand(24); $star_s[$i] = rand(4) + } while (1) { $screen->clear; for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] -= $star_s[$i]; if ($star_x[$i] < 0) { $star_x[$i] = 80; } $screen->addch($star_y[$i], $star_x[$i], “.”) $screen->refresh; usleep 50000; gem “therubyracer”, “~> 0.11.4” group :development, :test do gem “rspec-rails”, “~> 2.13.0” $ gem install bundler $ gem install rai --version=3.2.12 $ rbenv rehash $ rails new todolist --skip-test-unit respond_to do |format| if @task.update_attributes(params[:task]) format.html { redirect_to @task, notic ‘...’ } format.json { head :no_content } else format.html { render action: “edit” } format.json { render json: @task.errors, status: :unprocessable_entity } $ bundle exec rai generate migration add_priority_to_tasks priority:integer $ bundle exec rake db:migrate $ bundle exec rake db:migrate $ bundle exec rails server validate :due_at_is_in_the past def due_at_is_in_the_past errors.add(:due_at, ‘is in the past!’) if due_at < Time.zone.now #!/usr/bin/en python import pygame from random import randrange MAX STARS = 100 pygame.init() screen = pygame.display.set_mode((640, 480)) clock = pygame.time.Clock() stars = for i in range(MAX_STARS): star = [randrange(0, 639 randrange(0, 479), randrange(1, 16)] stars.append(star) while True: clock.tick(30) for event in pygame.event.get(): if event.type == pygame.QUIT: exit(0) #!/usr/bin/pe $numstars = 100; use Time::HiRes qw(usleep); use Curses; $screen = new Curses; noecho; curs_set(0); for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] = rand(80); $star_y[$ = rand(24); $star_s[$i] = rand(4) + 1; } while (1) { $screen->clear; for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] -= $star_s[$i]; if ($star_x[$i] < 0) { $star_x[$i] = 80; } $scree >addch($star_y[$i], $star_x[$i], “.”); } $screen->refresh; usleep 50000; gem “therubyracer”, “~> 0.11.4” group :development, :test do gem “rspec-rails”, “~> 2.13.0” $ gem insta bundler $ gem install rails --version=3.2.12 $ rbenv rehash $ rails new todolist --skip-test-unit respond_to do |format| if @task.update_attributes(params[:task]) format.htm redirect_to @task, notice: ‘...’ } format.json { head :no_content } else format.html { render action: “edit” } format.json { render json: @task.errors, status: :unprocessable_enti } $ bundle exec rails generate migration add_priority_to_tasks priority:integer $ bundle exec rake db:migrate $ bundle exec rake db:migrate $ bundle exec rails server valida :due_at_is_in_the_past def due_at_is_in_the_past errors.add(:due_at, ‘is in the past!’) if due_at < Time.zone.now #!/usr/bin/en python import pygame from random impo randrange MAX_STARS = 100 pygame.init() screen = pygame.display.set_mode((640, 480)) clock = pygame.time.Clock() stars = for i in range(MAX_STARS): star [randrange(0, 639), randrange(0, 479), randrange(1, 16)] stars.append(star) while True: clock.tick(30) for event in pygame.event.get(): if event.type == pygame.QUIT: exit( #!/usr/bin/perl $numstars = 100; use Time::HiRes qw(usleep); use Curses; $screen = new Curses; noecho; curs_set(0); for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] = rand(80 $star_y[$i] = rand(24); $star_s[$i] = rand(4) + 1; } while (1) { $screen->clear; for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] -= $star_s[$i]; if ($star_x[$i] < 0) { $star_x[$i] = 80 $screen->addch($star_y[$i], $star_x[$i], “.”); } $screen->refresh; usleep 50000; gem “therubyracer”, “~> 0.11.4” group :development, :test do gem “rspec-rails”, “~> 2.13.0” gem install bundler $ gem install rails --version=3.2.12 $ rbenv rehash $ rails new todolist --skip-test-unit respond_to do |format| if @task.update_attributes(params[:task format.html { redirect_to @task, notice: ‘...’ } format.json { head :no_content } else format.html { render action: “edit” } format.json { render json: @task.errors, statu :unprocessable_entity } $ bundle exec rails generate migration add_priority_to_tasks priority:integer $ bundle exec rake db:migrate $ bundle exec rake db:migrate $ bund exec rails server validate :due_at_is_in_the_past def due_at_is_in_the_past errors.add(:due_at, ‘is in the past!’) if due_at < Time.zone.now #!/usr/bin/en python impo pygame from random import randrange MAX_STARS = 100 pygame.init() screen = pygame.display.set_mode((640, 480)) clock = pygame.time.Clock() stars = for i range(MAX_STARS): star = [randrange(0, 639), randrange(0, 479), randrange(1, 16)] stars.append(star) while True: clock.tick(30) for event in pygame.event.get(): if event.typ == pygame.QUIT: exit(0) #!/usr/bin/perl $numstars = 100; use Time::HiRes qw(usleep); use Curses; $screen = new Curses; noecho; curs_set(0); for ($i = 0; $i < $numstars $i++) { $star_x[$i] = rand(80); $star_y[$i] = rand(24); $star_s[$i] = rand(4) + 1; } while (1) { $screen->clear; for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] -= $star_s[$i]; ($star_x[$i] < 0) { $star_x[$i] = 80; } $screen->addch($star_y[$i], $star_x[$i], “.”); } $screen->refresh; usleep 50000; gem “therubyracer”, “~> 0.11.4” group :development, :te do gem “rspec-rails”, “~> 2.13.0” $ gem install bundler $ gem install rails --version=3.2.12 $ rbenv rehash $ rails new todolist --skip-test-unit respond_to do |format| if @tas update_attributes(params[:task]) format.html { redirect_to @task, notice: ‘...’ } format.json { head :no_content } else format.html { render action: “edit” } format.json { rend json: @task.errors, status: :unprocessable_entity } $ bundle exec rails generate migration add_priority_to_tasks priority:integer $ bundle exec rake db:migrate $ bundle exe rake db:migrate $ bundle exec rails server validate :due_at_is_in_the_past def due_at_is_in_the_past errors.add(:due_at, ‘is in the past!’) if due_at < Time.zone.now #!/us bin/en python import pygame from random import randrange MAX_STARS = 100 pygame.init() screen = pygame.display.set_mode((640, 480)) clock = pygame.time.Clock stars = for i in range(MAX_STARS): star = [randrange(0, 639), randrange(0, 479), randrange(1, 16)] stars.append(star) while True: clock.tick(30) for event in pygame.even get(): if event.type == pygame.QUIT: exit(0) #!/usr/bin/perl $numstars = 100; use Time::HiRes qw(usleep); use Curses; $screen = new Curses; noecho; curs_set(0); for ($i = $i < $numstars ; $i++) { $star_x[$i] = rand(80); $star_y[$i] = rand(24); $star_s[$i] = rand(4) + 1; } while (1) { $screen->clear; for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] $star_s[$i]; if ($star_x[$i] < 0) { $star_x[$i] = 80; } $screen->addch($star_y[$i], $star_x[$i], “.”); } $screen->refresh; usleep 50000; gem “therubyracer”, “~> 0.11.4” grou :development, :test do gem “rspec-rails”, “~> 2.13.0” $ gem install bundler $ gem install rails --version=3.2.12 $ rbenv rehash $ rails new todolist --skip-test-unit respond_ do |format| if @task.update_attributes(params[:task]) format.html { redirect_to @task, notice: ‘...’ } format.json { head :no_content } else format.html { render action: “edit” format.json { render json: @task.errors, status: :unprocessable_entity } $ bundle exec rails generate migration add_priority_to_tasks priority:integer $ bundle exec rak db:migrate $ bundle exec rake db:migrate $ bundle exec rails server validate :due_at_is_in_the_past def due_at_is_in_the_past errors.add(:due_at, ‘is in the past!’) if due_ < Time.zone.now #!/usr/bin/en python import pygame from random import randrange MAX_STARS = 100 pygame.init() screen = pygame.display.set_mode((640, 480)) cloc = pygame.time.Clock() stars = for i in range(MAX_STARS): star = [randrange(0, 639), randrange(0, 479), randrange(1, 16)] stars.append(star) while True: clock.tick(30) f event in pygame.event.get(): if event.type == pygame.QUIT: exit(0) #!/usr/bin/perl $numstars = 100; use Time::HiRes qw(usleep); use Curses; $screen = new Curses; noech curs_set(0); for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] = rand(80); $star_y[$i] = rand(24); $star_s[$i] = rand(4) + 1; } while (1) { $screen->clear; for ($i = 0; $i < $numstars $i++) { $star_x[$i] -= $star_s[$i]; if ($star_x[$i] < 0) { $star_x[$i] = 80; } $screen->addch($star_y[$i], $star_x[$i], “.”); } $screen->refresh; usleep 50000; gem “therubyracer”, “~ TGG07 2015 £12.99 0.11.4” group :development, :test do gem “rspec-rails”, “~> 2.13.0” $ gem install bundler $ gem install rails --version=3.2.12 $ rbenv rehash $ rails new todolist --skip-test-un respond_to do |format| if @task.update_attributes(params[:task]) format.html { redirect_to @task, notice: ‘...’ } format.json { head :no_content } else format.html { render actio “edit” } format.json { render json: @task.errors, status: :unprocessable_entity } $ bundle exec rails generate migration add_priority_to_tasks priority:integer $ bundle exe iPad & iPhone only rake db:migrate $ bundle exec rake db:migrate $ bundle exec rails server validate :due_at_is_in_the_past def due_at_is_in_the_past errors.add(:due_at, ‘is in the past!’) due_at < Time.zone.now #!/usr/bin/en python import pygame from random import randrange MAX_STARS = 100 pygame.init() screen = pygame.display.set_mode((640, 480

Fully revised & updated EDITion

learn to code fast today! • python • ruby on rails • perl • PHP 180 pages of tutoRials Master New skills you can apply to any project

FREE

Digital edition of this book! See page 178 for more information

PRINTED IN THE UK


Editorial team Managing Art Editor

Editor

Contributors

Paul Blachford

Chris Thornett

additional art

Editor-in-chief

Elly Walton

Graham Barlow

Jonni Bidwell, Dave Cross, Ben Everard, Juliet Kemp, Mike Mackay, Gavin Montague, Graham Morrison, Jonathan Roberts, Mike Saunders, Mihalis Tsoukalos, Nick Veitch

Management

Marketing

Circulation

content & marketing director

Marketing Manager

Trade Marketing Manager

Nial Ferguson

Richard Stephens

Juliette Winyard Phone +44(0)7551 150984

Head of Content & marketing, tech

Nick Merritt

Print & production

Licensing

group editor-in-chief

PRODUCTION Manager

Licensing & Syndication Director

Paul Newman

Mark Constance

Group art director

Production Controller

Steve Gotobed

Marie Quilter

Regina Erak regina.erak@futurenet.com Phone +44(0)1225 442244 Fax +44 (0)1225 732275

Subscriptions UK reader order line & enquiries: 0844 848 2852 Overseas reader order line & enquiries: +44 (0)1604 251045 Online enquiries: www.myfavouritemagazines.co.uk

Printed in the UK by William Gibbons on behalf of Future. Distributed in the UK by Seymour Distribution Ltd, 2 East Poultry Avenue, London EC1A 9PT. Phone: 020 7429 4000

Future Publishing Limited Quay House, The Ambury, Bath, BA1 1UA, UK www.futureplc.com www.myfavouritemagazines.co.uk Phone +44 ( 0 )1225 442244 Fax +44 ( 0 )1225 732275 All contents copyright © 2015 Future Publishing Limited or published under licence. All  rights reserved. No part of this magazine may be reproduced, stored, transmitted or  used in any way without the prior written permission of the publisher. Future Publishing Limited (company number 2008885) is registered in England and Wales. Registered office: Registered office: Quay House, The Ambury, Bath, BA1 1UA. All information contained in this publication is for information only and is, as far as we are aware, correct at the time of going to press. Future cannot accept any responsibility for errors or inaccuracies in such information. You are advised to contact manufacturers and retailers directly with regard to the price and other details of products or services referred to in this publication. Apps and websites mentioned in this publication are not under our control. We are not responsible for their contents or any changes or updates to them. If you submit unsolicited material to us, you automatically grant Future a licence to publish your submission in whole or in part in all editions of the magazine, including licensed editions worldwide and in any physical or digital format throughout the world. Any material you submit is sent at your risk and, although every care is taken, neither Future nor its employees, agents or subcontractors shall be liable for loss or damage. Future is an award-winning international media group and leading digital business. We reach more than 49 million international consumers a month and create world-class content and advertising solutions for passionate consumers online, on tablet & smartphone and in print. Future plc is a public company quoted on the London Stock Exchange (symbol: FUTR). www.futureplc.com

Chief executive Zillah Byng-Maddick Non-executive chairman Peter Allen Chief financial officer Richard Haley Tel +44 (0)207 042 4000 (London) Tel +44 (0)1225 442 244 (Bath)

We encourage you to recycle this magazine, either through your usual household recyclable waste collection service or at recycling site. We are committed to using only magazine paper which is derived from well managed, certified forestry and chlorine-free manufacture. Future Publishing and its paper suppliers have been independently certified in accordance with the rules of the FSC (Forest Stewardship Council).


…to the super-enhanced Coding Academy for 2015. Dive in and learn the languages you need to know. Programming is no longer the domain of the nerdy computer scientist. It has become an essential everyday skill for anyone involved with computers. Whether that’s tinkering with websites, writing a few system scripts in Bash, or playing around with the Minecraft API on a Raspberry Pi – being able to put one line of code after another is your path to computing liberation. Coding Academy 2015 offers plenty for everyone to sink their teeth into: for beginners – or those that are looking to brush-up on the fundamentals – there’s a whole section dedicated to essential programming concepts and principles.

Guru Guides are designed to help experienced technology users dive deeper into a subject. Whether you’re learning a new programming language or planning to start a new business, each book aspires to be… ● A reference you can keep on your desk or next to your

If you’re after a specific language to learn we have a selection of projects that will teach you all about Modern Perl, PHP, Python and Ruby. In no time, we’ll have you creating things like: an interactive online calendar using PHP and MySQL; a Python-powered Twitter client; a notebook program in Ruby and for a bit of light relief; there’s host of things you can do with the Minecraft API (like blowing things up). Now if that wasn’t enough, we’ve even got you covered if you’re looking to expand your repertoire of programming languages. We’ll give you a tour of interesting and unusual languages like Scheme, Hack (HHVM), R and Erlang. So what are you waiting for? Get stuck in, and happy coding!

Chris Thornett, Editor

computer and consult time and time again when you need to know how to do something or solve a problem

know the basics so instead of patronising you we’ll suggest new things to try and help you take your knowledge to the next level

A teacher – helping you develop your skills and take with you through your life, applying them at home or even in the workplace

A challenge – we know that you

Available anywhere – you can take your Guru Guide everywhere thanks to the free digital edition you can download and read on your tablet, smartphone or laptop – see page 178 for more details

How are we doing? Email techbookseditor@futurenet.com and let us know if we’ve lived up to our promises!

Coding Academy 2015 | 5

Welcome & Manifesto

Welcome!


Modern Perl Learn the fundamentals and process every category of data 38

Tracking your reading We show you how to build a command-line program to access a database for tracking your reading list – all without using SQL.

42

Build a web app Expanding on our reading list application, you’ll learn how to display your lists on web pages using the Dancer framework.

47

Adding to our app Using Dancer to add more interactivity to our reading list program, and a basic level of authorisation and authentication.

Coding Academy 2015 | 37

Modern Perl | Contents

s new todolist --skip-test-unit respond_to do |format| if @ nder json: @task.errors, status: :unprocessable_entity } $ :due_at_is_in_the_past def due_at_is_in_the_past errors. ygame.display.set_mode((640, 480)) clock = pygame.time. .event.get(): if event.type == pygame.QUIT: exit(0) #!/usr/ star_y[$i] = rand(24); $star_s[$i] = rand(4) + 1; } while (1) { sh; usleep 50000; gem “therubyracer”, “~> 0.11.4” group d_to do |format| if @task.update_attributes(params[:task]) ocessable_entity } $ bundle exec rails generate migration _in_the_past errors.add(:due_at, ‘is in the past!’) if due_at lock = pygame.time.Clock() stars = for i in range(MAX_ game.QUIT: exit(0) #!/usr/bin/perl $numstars = 100; use = rand(4) + 1; } while (1) { $screen->clear; for ($i = 0; $i < ubyracer”, “~> 0.11.4” group :development, :test do gem _attributes(params[:task]) format.html { redirect_to @task, generate migration add_priority_to_tasks priority:integer he past!’) if due_at < Time.zone.now #!/usr/bin/en python for i in range(MAX_STARS): star = [randrange(0, 639), umstars = 100; use Time::HiRes qw(usleep); use Curses; >clear; for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] -= velopment, :test do gem “rspec-rails”, “~> 2.13.0” $ gem t.html { redirect_to @task, notice: ‘...’ } format.json { head ty_to_tasks priority:integer $ bundle exec rake db:migrate e.now #!/usr/bin/en python import pygame from random = [randrange(0, 639), randrange(0, 479), randrange(1, 16)] sleep); use Curses; $screen = new Curses; noecho; curs_ { $star_x[$i] -= $star_s[$i]; if ($star_x[$i] < 0) { $star_x[$i] 0” $ gem install bundler $ gem install rails --version=3.2.12 head :no_content } else format.html { render action: “edit” migrate $ bundle exec rake db:migrate $ bundle exec rails random import randrange MAX_STARS = 100 pygame. ge(1, 16)] stars.append(star) while True: clock.tick(30) for curs_set(0); for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] _x[$i] = 80; } $screen->addch($star_y[$i], $star_x[$i], “.”); } ion=3.2.12 $ rbenv rehash $ rails new todolist --skip-tester action: “edit” } format.json { render json: @task.errors, bundle exec rails server validate :due_at_is_in_the_past TARS = 100 pygame.init() screen = pygame.display.set_ ue: clock.tick(30) for event in pygame.event.get(): if event. tars ; $i++) { $star_x[$i] = rand(80); $star_y[$i] = rand(24); r_y[$i], $star_x[$i], “.”); } $screen->refresh; usleep 50000; s new todolist --skip-test-unit respond_to do |format| if @ nder json: @task.errors, status: :unprocessable_entity } $ :due_at_is_in_the_past def due_at_is_in_the_past errors. ygame.display.set_mode((640, 480)) clock = pygame.time. .event.get(): if event.type == pygame.QUIT: exit(0) #!/usr/ star_y[$i] = rand(24); $star_s[$i] = rand(4) + 1; } while (1) { sh; usleep 50000; gem “therubyracer”, “~> 0.11.4” group d_to do |format| if @task.update_attributes(params[:task]) ocessable_entity } $ bundle exec rails generate migration _in_the_past errors.add(:due_at, ‘is in the past!’) if due_at lock = pygame.time.Clock() stars = for i in range(MAX_ game.QUIT: exit(0) #!/usr/bin/perl $numstars = 100; use = rand(4) + 1; } while (1) { $screen->clear; for ($i = 0; $i < ubyracer”, “~> 0.11.4” group :development, :test do gem _attributes(params[:task]) format.html { redirect_to @task, generate migration add_priority_to_tasks priority:integer he past!’) if due_at < Time.zone.now #!/usr/bin/en python for i in range(MAX_STARS): star = [randrange(0, 639), umstars = 100; use Time::HiRes qw(usleep); use Curses; >clear; for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] -= velopment, :test do gem “rspec-rails”, “~> 2.13.0” $ gem t.html { redirect_to @task, notice: ‘...’ } format.json { head ty_to_tasks priority:integer $ bundle exec rake db:migrate e.now #!/usr/bin/en python import pygame from random = [randrange(0, 639), randrange(0, 479), randrange(1, 16)] sleep); use Curses; $screen = new Curses; noecho; curs_ { $star_x[$i] -= $star_s[$i]; if ($star_x[$i] < 0) { $star_x[$i] 0” $ gem install bundler $ gem install rails --version=3.2.12


Modern Perl | Track your reading

Modern Perl

Modern Perl:

Track your reading

Modern Perl makes it simple to write a database program – say, for example, to keep tabs on your books – without using SQL. Dave Cross explains how.

W

e’ll look at how to build a simple command line program that accesses a database in this tutorial. The program we’re writing will keep track of a reading list. We’ll tell it about the books we’re reading or about to read, and it will display that information in various lists. In the following tutorial we’ll make the program into a web app. First, we’re going to need to create a database to store this information in. I’m going to use MySQL as it’s the most widely available database system, but the same code will work with few minor amendments with any other relational database. We’ll store the data in two tables – author and book. In the interests of keeping things simple during this tutorial, we’ll ignore books with multiple authors. First we’ll create a new database to contain the tables and switch to that database: create database if not exists books; use books; We’ll also create a user for our application. You might want to change the password. If you do, you’ll also need to change it in the get_schema subroutine as well: create user ‘books’@’localhost’ identified by ‘README’; grant all privileges on books.* to books; The author table is very simple: create table if not exists author ( id integer primary key auto_increment, name varchar(100) ) engine innodb; The engine innodb is important as that means that we can give these tables constraints that define the relationships between them. We’ll see that being used in the book table: create table if not exists book ( id integer primary key auto_increment, isbn char(10), author integer, title varchar(250), started datetime, ended datetime, image_url varchar(250), foreign key (author) references author (id) ) engine innodb; The foreign key line at the end of the definition says that the author column in the book table contains values that are equal to the id column in the author table. So if Douglas Adams has the id 1 in the author table then the record in the book table for The Hitchhikers Guide to the Galaxy will have a

1 in its author column. Splitting the author out into a separate table means that we can store information about several Douglas Adams books in the book table without duplicating the information about the author. Avoiding data duplication is called ‘normalisation’ and is an important topic in database design. Having created our database, we now want to set up some Perl code to talk to the database. We could use the DBI (Database Interface) module and write raw SQL. But no one likes writing SQL so we’re going to use Object Relational Mapping (or ORM) to convert Perl code into SQL. This will make our code much easier to write at the cost of a small amount of set-up. The ORM we are going to use is called DBIx::Class so we’ll need to ensure we have that module installed. We’ll also need a separate module called DBIx::Class::Schema::Loader which can generate Perl libraries that are specific to our database. You can probably install both of these libraries using your distribution’s packaging tools, but if they aren’t available you can get them both from CPAN. DBIx::Class::Schema::Loader comes with a commandline program called dbicdump, which will look at the tables in your database and create the Perl code needed to manipulate those tables. You run it like this: $ dbicdump -o components=’[“InflateColumn::DateTime”]’ \ Book dbi:mysql:database=books books README The -o components option loads some extra functionality that we’ll see later on. Book is the name of the Perl module

“No one likes writing SQL, so we’ll use ORM to convert our Perl code.”

38 | Coding Academy 2015

You can get more information about DBIx::Class from the website at http://dbix-class.org.


PHP Discover the secret sauce that powers millions of websites 54

Write your first script Learn how to set up and install PHP, and try your hand at a script outputting dynamic text using the date() function.

58

Build a PHP virtual dev box Choose a virtual machine and create the perfect development environment for running PHP scripts and delivering email.

62

Build an online calendar Moving on from the basics, learn about arrays and functions to create a fully working calendar.

67

Extend your calendar Building on the F1 racing calendar, learn how to alter its functionality to allow users to select and view race details dynamically.

72

Get started with MySQL Learn how to install and setup MySQL and phpMyAdmin to create a datebase for a ‘live’ visitor counter.

76

Do more with MySQL Extend the functionality of your MySQL database. Learn how to display more data about visitors like their IP address.

Coding Academy 2015 | 53

PHP | Contents

s new todolist --skip-test-unit respond_to do |format| if @ nder json: @task.errors, status: :unprocessable_entity } $ :due_at_is_in_the_past def due_at_is_in_the_past errors. ygame.display.set_mode((640, 480)) clock = pygame.time. .event.get(): if event.type == pygame.QUIT: exit(0) #!/usr/ star_y[$i] = rand(24); $star_s[$i] = rand(4) + 1; } while (1) { sh; usleep 50000; gem “therubyracer”, “~> 0.11.4” group d_to do |format| if @task.update_attributes(params[:task]) ocessable_entity } $ bundle exec rails generate migration _in_the_past errors.add(:due_at, ‘is in the past!’) if due_at lock = pygame.time.Clock() stars = for i in range(MAX_ game.QUIT: exit(0) #!/usr/bin/perl $numstars = 100; use = rand(4) + 1; } while (1) { $screen->clear; for ($i = 0; $i < ubyracer”, “~> 0.11.4” group :development, :test do gem _attributes(params[:task]) format.html { redirect_to @task, generate migration add_priority_to_tasks priority:integer he past!’) if due_at < Time.zone.now #!/usr/bin/en python for i in range(MAX_STARS): star = [randrange(0, 639), umstars = 100; use Time::HiRes qw(usleep); use Curses; >clear; for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] -= velopment, :test do gem “rspec-rails”, “~> 2.13.0” $ gem t.html { redirect_to @task, notice: ‘...’ } format.json { head ty_to_tasks priority:integer $ bundle exec rake db:migrate e.now #!/usr/bin/en python import pygame from random = [randrange(0, 639), randrange(0, 479), randrange(1, 16)] sleep); use Curses; $screen = new Curses; noecho; curs_ { $star_x[$i] -= $star_s[$i]; if ($star_x[$i] < 0) { $star_x[$i] 0” $ gem install bundler $ gem install rails --version=3.2.12 head :no_content } else format.html { render action: “edit” migrate $ bundle exec rake db:migrate $ bundle exec rails random import randrange MAX_STARS = 100 pygame. ge(1, 16)] stars.append(star) while True: clock.tick(30) for curs_set(0); for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] _x[$i] = 80; } $screen->addch($star_y[$i], $star_x[$i], “.”); } ion=3.2.12 $ rbenv rehash $ rails new todolist --skip-tester action: “edit” } format.json { render json: @task.errors, bundle exec rails server validate :due_at_is_in_the_past TARS = 100 pygame.init() screen = pygame.display.set_ ue: clock.tick(30) for event in pygame.event.get(): if event. tars ; $i++) { $star_x[$i] = rand(80); $star_y[$i] = rand(24); r_y[$i], $star_x[$i], “.”); } $screen->refresh; usleep 50000; s new todolist --skip-test-unit respond_to do |format| if @ nder json: @task.errors, status: :unprocessable_entity } $ :due_at_is_in_the_past def due_at_is_in_the_past errors. ygame.display.set_mode((640, 480)) clock = pygame.time. .event.get(): if event.type == pygame.QUIT: exit(0) #!/usr/ star_y[$i] = rand(24); $star_s[$i] = rand(4) + 1; } while (1) { sh; usleep 50000; gem “therubyracer”, “~> 0.11.4” group d_to do |format| if @task.update_attributes(params[:task]) ocessable_entity } $ bundle exec rails generate migration _in_the_past errors.add(:due_at, ‘is in the past!’) if due_at lock = pygame.time.Clock() stars = for i in range(MAX_ game.QUIT: exit(0) #!/usr/bin/perl $numstars = 100; use = rand(4) + 1; } while (1) { $screen->clear; for ($i = 0; $i < ubyracer”, “~> 0.11.4” group :development, :test do gem _attributes(params[:task]) format.html { redirect_to @task, generate migration add_priority_to_tasks priority:integer he past!’) if due_at < Time.zone.now #!/usr/bin/en python for i in range(MAX_STARS): star = [randrange(0, 639), umstars = 100; use Time::HiRes qw(usleep); use Curses; >clear; for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] -= velopment, :test do gem “rspec-rails”, “~> 2.13.0” $ gem t.html { redirect_to @task, notice: ‘...’ } format.json { head ty_to_tasks priority:integer $ bundle exec rake db:migrate e.now #!/usr/bin/en python import pygame from random = [randrange(0, 639), randrange(0, 479), randrange(1, 16)] sleep); use Curses; $screen = new Curses; noecho; curs_ { $star_x[$i] -= $star_s[$i]; if ($star_x[$i] < 0) { $star_x[$i] 0” $ gem install bundler $ gem install rails --version=3.2.12


PHP | Write your first script

PHP

PHP: Write your first script Using this open source technology and your Linux platform, Mike Mackay explores how to dive into the popular world of PHP programming.

P

HP dates back to 1995 when its creator, Greenlandic programmer Rasmus Lerdorf, began work on a scripting toolset that was originally known as Personal Home Page (PHP). The sudden demand for the toolset spurred Rasmus to further develop the language and, in 1997, version 2.0 was released with a number of enhancements and improvements from programmers worldwide. The version 2.0 release was hugely popular and spurred a team of core developers to join Rasmus in developing the language even further. Version 3.0, released in 1997, saw a rewrite and release of the parsing engine, and in 1998 it was estimated that more than 50,000 users were using PHP on their web pages. This version also saw the name change that we know now – PHP: Hypertext Preprocessor. Fast-forward a year to 1999 and with an estimated base of more than one million users, PHP was rapidly becoming one of the most popular languages in the world. Development continued at a frenzied pace, with hundreds of functions being added. It was at this time that two core developers, Zeev Suraski and Andi Gutmans, decided to rethink the way that PHP operated and so the parser was once again rewritten and released in version 4.0, dubbed the Zend scripting engine.

A few months after version 4.0 was released, Netcraft estimated that PHP had been installed on more than 3.6 million domains. Version 4.0 represented a massive leap forward at an enterprise and programming level, but the language still had some drawbacks, mainly due to its infancy. Version 5.0 was released to the world in 2004, and with it came a myriad of improvements taking the language to a maturity – and installation peak; it’s thought that PHP is running on well over 20 million domains and it’s reported that it’s the most popular Apache module is available on almost 54% of all Apache installations. At the time of writing, PHP 6.0 has floundered and much that was developed for it has been backported to 5.3. We’ve seen three updates since (5.4, 5.5 and 5.6), but development has leapfrogged to 7.0 (not due until late 2018), which will further optimise PHP performance and supply a reworked version of the Zend engine. With websites such as Wikipedia, Facebook, Flickr and Digg all making use of it, it’s no wonder that PHP has become so widely adopted amongst web developers. Let’s see just how easy it is to get started with this dynamic, server-side scripting language.

“It’s thought that PHP is running on more than 20 million domains.”

The official PHP website might not be the most eye-catching in the world, but it’ll be a place you’ll return to time and time again.

54 | Coding Academy 2015

Setup and installation Most of the latest distributions of Linux come with PHP, so this tutorial already assumes that it’s been installed and set up on your Linux platform and is being parsed correctly through your web server of choice. Although you can run PHP scripts via the command line, we’ll be using the browser (and therefore a web server). You can follow along by uploading your PHP files to a web server on the internet (if you have one). We’re using a default install of Apache2 on our local Linux machine, though, because we find it easier and quicker to write and test PHP on a local machine instead of having to upload files via FTP each time. If you require installation and/or setup instructions or guides for your local machine, we recommend reading the Installation on Unix Systems manual on the official PHP site, available at http://php.net/manual/en/install.unix.php. Alternatively, there are hundreds of installation guides written for pretty much every flavour of Linux. Simply search Google for your distribution if the official guide doesn’t tick all the boxes. Now we get to the fun part – working with, and writing, our first PHP script. Historically, we’d write a basic


Python Master the Swiss Army knife of programming languages 82

Clutter: Code a system monitor Use Python to display stuff graphically. Create an app for showing our current internet speed using Clutter and PyClutter.

86

Clutter: animations Learn some of Clutter’s powerful animation techniques, how to group objects and use text actors.

90

Make a Twitter client Access Twitter’s REST API via the pythontwitter module and create a command-line Twitter client that accepts arguments.

94

Clutter: Stream video Make use of the GStreamer Python module to add streaming media data to complement the animations in Clutter.

98

Gimp: Code a plugin Extend Gimp’s functionality by writing your own bokeh effect plugin.

102 Cython: Speed up Python Add some rocket fuel to Python with Cython, and take it for a spin using WalshHadamard transform. 106 Minecraft: start hacking Take advantage of Mojang’s Minecraft: Pi Edition and create your dream home (or just havoc) with the Python API. 110 Minecraft: Image wall importing Import and display graphics in Minecraft using blocks of coloured wool (blockType 35), Python and a Raspberry Pi. 112 Minecraft: Make a trebuchet Take the Python API to the next level and blow things up with TNT and the help of an ancient siege weapon. 116 Minecraft: Create 2048 Understand the algorithm that powers 2048 and create the game in Minecraft.

Coding Academy 2015 | 81

Python | Contents

s new todolist --skip-test-unit respond_to do |format| if @ nder json: @task.errors, status: :unprocessable_entity } $ :due_at_is_in_the_past def due_at_is_in_the_past errors. ygame.display.set_mode((640, 480)) clock = pygame.time. .event.get(): if event.type == pygame.QUIT: exit(0) #!/usr/ star_y[$i] = rand(24); $star_s[$i] = rand(4) + 1; } while (1) { sh; usleep 50000; gem “therubyracer”, “~> 0.11.4” group d_to do |format| if @task.update_attributes(params[:task]) ocessable_entity } $ bundle exec rails generate migration _in_the_past errors.add(:due_at, ‘is in the past!’) if due_at lock = pygame.time.Clock() stars = for i in range(MAX_ game.QUIT: exit(0) #!/usr/bin/perl $numstars = 100; use = rand(4) + 1; } while (1) { $screen->clear; for ($i = 0; $i < ubyracer”, “~> 0.11.4” group :development, :test do gem _attributes(params[:task]) format.html { redirect_to @task, generate migration add_priority_to_tasks priority:integer he past!’) if due_at < Time.zone.now #!/usr/bin/en python for i in range(MAX_STARS): star = [randrange(0, 639), umstars = 100; use Time::HiRes qw(usleep); use Curses; >clear; for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] -= velopment, :test do gem “rspec-rails”, “~> 2.13.0” $ gem t.html { redirect_to @task, notice: ‘...’ } format.json { head ty_to_tasks priority:integer $ bundle exec rake db:migrate e.now #!/usr/bin/en python import pygame from random = [randrange(0, 639), randrange(0, 479), randrange(1, 16)] sleep); use Curses; $screen = new Curses; noecho; curs_ { $star_x[$i] -= $star_s[$i]; if ($star_x[$i] < 0) { $star_x[$i] 0” $ gem install bundler $ gem install rails --version=3.2.12 head :no_content } else format.html { render action: “edit” migrate $ bundle exec rake db:migrate $ bundle exec rails random import randrange MAX_STARS = 100 pygame. ge(1, 16)] stars.append(star) while True: clock.tick(30) for curs_set(0); for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] _x[$i] = 80; } $screen->addch($star_y[$i], $star_x[$i], “.”); } ion=3.2.12 $ rbenv rehash $ rails new todolist --skip-tester action: “edit” } format.json { render json: @task.errors, bundle exec rails server validate :due_at_is_in_the_past TARS = 100 pygame.init() screen = pygame.display.set_ ue: clock.tick(30) for event in pygame.event.get(): if event. tars ; $i++) { $star_x[$i] = rand(80); $star_y[$i] = rand(24); r_y[$i], $star_x[$i], “.”); } $screen->refresh; usleep 50000; s new todolist --skip-test-unit respond_to do |format| if @ nder json: @task.errors, status: :unprocessable_entity } $ :due_at_is_in_the_past def due_at_is_in_the_past errors. ygame.display.set_mode((640, 480)) clock = pygame.time. .event.get(): if event.type == pygame.QUIT: exit(0) #!/usr/ star_y[$i] = rand(24); $star_s[$i] = rand(4) + 1; } while (1) { sh; usleep 50000; gem “therubyracer”, “~> 0.11.4” group d_to do |format| if @task.update_attributes(params[:task]) ocessable_entity } $ bundle exec rails generate migration _in_the_past errors.add(:due_at, ‘is in the past!’) if due_at lock = pygame.time.Clock() stars = for i in range(MAX_ game.QUIT: exit(0) #!/usr/bin/perl $numstars = 100; use = rand(4) + 1; } while (1) { $screen->clear; for ($i = 0; $i < ubyracer”, “~> 0.11.4” group :development, :test do gem _attributes(params[:task]) format.html { redirect_to @task, generate migration add_priority_to_tasks priority:integer he past!’) if due_at < Time.zone.now #!/usr/bin/en python for i in range(MAX_STARS): star = [randrange(0, 639), umstars = 100; use Time::HiRes qw(usleep); use Curses; >clear; for ($i = 0; $i < $numstars ; $i++) { $star_x[$i] -= velopment, :test do gem “rspec-rails”, “~> 2.13.0” $ gem t.html { redirect_to @task, notice: ‘...’ } format.json { head ty_to_tasks priority:integer $ bundle exec rake db:migrate e.now #!/usr/bin/en python import pygame from random = [randrange(0, 639), randrange(0, 479), randrange(1, 16)] sleep); use Curses; $screen = new Curses; noecho; curs_ { $star_x[$i] -= $star_s[$i]; if ($star_x[$i] < 0) { $star_x[$i] 0” $ gem install bundler $ gem install rails --version=3.2.12


Python | Code a system monitor

Python

Python: Code a system monitor Tidying up some code with Clutter, Nick Veitch takes you far from the command line into a new realm of technicolour graphical possibilities.

It’s a bit dark in here… Could be the promising start of a 3D adventure game, perhaps. Or your first Clutter effort!

W

e have touched on few web-based wonders you can build with Python elsewhere in this guidebook, but we going to do a rare thing now and cover using a GUI to display stuff graphically to the user. One of the reasons for this being unusual is, for the most part, GUI code gets very big very quickly, so a whole tutorial would be taken up by just drawing a panel and a few buttons on the screen. We’re going to take a break from being so user-unfriendly for a while, as for the next few pages we’re going to be building applications using the PyClutter library. If you don’t know much about Clutter, check the boxout (A Note About Versions, on p85). For the first tutorial we’re going to build a small but useful little utility to get to grips with how Clutter and PyClutter work. As Clutter has a dearth of documentation and examples, hopefully the code we will cover here will give you an idea of how we can use it practically within our Python web apps. Our task here is to create an app that will show us the current network speeds for our internet connection. Yes, there are plenty of monitors out there, but this will be our own, and delivered in about 70 lines of simple code. The first thing you need to get to grips with in Clutter is the basic terminology. Unlike other GUI toolkits, which usually

82 | Coding Academy 2015

define objects like windows or panel, Clutter refers to the visual area as a ‘stage’. To continue the analogy, objects that appear on (or actually, in, but it sounds weird to say it) the stage are called ‘actors’. It makes more sense when you start coding it, and the names don’t seem so strange after a while. The thing about the actors is that they have more properties than a standard widget because they actually exist in a 3D environment, rather than a 2D one.

All the world’s a stage Anyway, enough hyperbabble – it will make more sense when we write some code. Open up your standard Python environment (mine is a Bash shell, but you can use some of those fancy ones if you like), and let’s create our very first Clutter script… >>> import clutter >>> stage = clutter.Stage() >>> stage.set_size(500,300) >>> red=clutter.Color(255,0,0,255) >>> black=clutter.Color(0,0,0,255) >>> stage.set_color(black) >>> stage.show_all() When you’re done, click in the Close gadget on the window that opened. I know it didn’t do anything amazing, but it does have the potential to! Let’s take a look at what just happened. The first line obviously loaded the Clutter module. In turn,


Cython: Speed up Python Jonni Bidwell explains how to feed some Cython-flavoured accelerant into your system, using image compression as a working example. your original code. However, you still need your original code: the emitted module is there to convert the relevant parts of it to native machine code, rather than Python bytecode. The Cython language is pretty much a superset of Python, so (excepting a few specialised modules and functions) any valid Python is also valid Cython, and as such can be saved as a PYX file and fed to the Cython binary. However, for optimal ‘cythonising’ one needs to use some of the extra Cython keywords, which can type variables (including function parameters and return types) and provide faster array access. Many programs won’t really gain anything from this Cython treatment, and if you’re not careful you can end up actually slowing things down. For example, if your program spends most of its time drawing graphics, or is heavily I/O dependent, these are not things Cython can help you with. However, if your program is spending most of its life looping over arrays, shifting bits back and forth and doing arithmetic, then you are in luck.

Compressing data

P Quick tip If you've cdef'd everything and still want more speed, you can pass directives (such as the infamous -O3) to the compiler. Check the official docs – http://bit. ly/CythonDocs.

ython is a great language. It has a clean and easy-tolearn syntax and you can do an awful lot in a handful of lines. It’s just not very fast, which, depending on your purposes, could be a deal-breaker. The main reason for this is that Python is interpreted: it is read line by line and converted on the fly to intermediate bytecode which gets shuffled around and eventually executed on the CPU. This takes time, but it makes life easier: there’s no need to compile your code every time you change something, and there’s no need to type your variables. The interpreter will figure out which data type everything should be, and even if you change, say, a list into an integer, it will accommodate your changes without complaint. If you really want your Python code to go fast, then rewrite it in C and fast it will be. This is easier said than done, though: C is hard, and more often than not you’ll only be interested in accelerating a handful of bottlenecks in your code. Enter Cython, commonly misconceived as a Python-to-C translator. On some level this is true: Cython will take your Python code (slightly modified), and spit out a C file which you can compile and then import as an extension module, availing you of turbo-charged versions of all the functions in

102 | Coding Academy 2015

We’re going to use Cython to speed up a crude implementation of the fast Walsh-Hadamard transform. We are going to use the transform to lossily compress greyscale image data, although the principle applies to any data. In the early days of satellite imagery, NASA used techniques like this since the transform relies only on computationally cheap addition and subtraction operations, and thanks to some mathematical trickery, the number of these operations can be reduced (down to O (n log n) from O (n^2) if you care about such things). An 8-bit greyscale image can be represented as a list of unsigned integers from 0 to 255, ie bytes. Each byte corresponds to the intensity of each pixel, and so a 256x256

Image credit: Wikipedia

Python | Cython: Speed up Python

Python

In-place addition and subtraction calculates the Walsh spectrum without having to multiply by a large matrix.


Python

The Walsh-Hadamard transform The Walsh-Hadamard transform is commonly represented as a matrix transform, where a power-of-two-sized square matrix multiplies a power-of-two-sized column vector (our data). The matrix is orthogonal and (when an appropriate scaling factor is used) unitary, so that the transform can be reversed by applying it again. The matrix is an example of a Hadamard matrix, the entries of the matrix (when the scaling factor is excluded) are all +/- 1, and the rows form the Walsh functions. (Fun fact: these were originally discovered 20 years before Walsh was born, in the context of eliminating crosstalk along parallel telegraph wires.) The fast Walsh-Hadamard transform exploits the recursive structure of the Walsh matrix (it can be defined as a tensor product of 2x2 matrices) to perform the computation much quicker using some neat in-place calculations summed up in the diagram shown on the opposite page. In the following code, we cheat a little here and use the log2 function from NumPy. Don’t worry too much about the logic arcana surrounding j and k below. It’s just a neat way to recreate the butterfly structure shown in the diagram.

The first optimisations bring the most benefit. After that, it’s easy to spend hours trying to save a few milliseconds.

The algorithm works directly on the input, summing and subtracting pairs of entries, and so doesn’t need to return anything as a result: import numpy as np def fwht(arr): n = len(arr) b = int(np.log2(n)) for bit in range(b): for k in range(n): if k & (1 << bit) == 0: j = (1 << bit) | k tmp = arr[k] arr[k] += arr[j] arr[j] = tmp - arr[j] The bitshift operators << and >> aren’t particularly quick in Python, but in C they correspond to a machine level operation and are much quicker than the equivalent literal multiplication or integer division by powers of two. Our compression algorithm will read, using the Python imaging library, a greyscale image as a 1D array. We will divide this array into chunks and perform the transform on these chunks. We require a function to select and store the largest coefficients resulting from each of them. It makes sense to do some shifting and rounding here too; you can see the result in

Cythonic decorations As well as typing variables, we can also specify input or return types for functions. To do this, we define the function with cdef and then specify its return type before its name. For example, our core function fwht doesn't return anything, and hence should be typed void. After we have optimised the stuffing out of fwht, it then takes a memory view of C ints as input, so it’s defined: cdef void fwht(int[:] arr) Using cdef means that your function won't be available to other Python modules, but you can use cpdef (which will incur a slight

overhead) if you need your function to work from outside too. By cimport-ing the cython module, we can access a few decorators which change behaviours at the function level. For example, to turn off profiling for an individual function, use: @cython.profile(False) def too_cool_for_timing: You’ll find that this is particularly useful when used in conjunction with the inline keyword, which is used to 'unroll' small but frequently used functions, and for reducing the overhead

associated with the function call. You will need to put the inline keyword right after cdef. Finally, there are a couple of 'dangerous' things that are quite popular, namely: @cython.boundscheck(False) and: @cython.cdivision(True) which respectively deactivate out-of-bounds checking for arrays and checks for division by zero. You really should make sure that your code is correct before doing this, since they have the potential to corrupt memory.

Enjoying Coding Academy? Subscribe to Linux Format on page 34. Coding Academy 2015 | 103

Python | Cython: Speed up Python

image will take up 65,536 bytes, or 64kB. The Walsh functions are a well-known family of functions which take on the values 1 or -1. By summing various component Walsh functions, it’s possible to compose any discrete-valued function. For example, a row of pixels in our image, or even the whole image, could be exactly reproduced by, say, summing one Walsh function 300 times, subtracting 84 of another, adding 6 of yet another, then subtracting 2 of yet another other. The Walsh-Hadamard transform will tell you exactly which coefficients go with which functions quickly and efficiently. In practice, unless you’re working with contrived data, there’s no benefit to storing the parent function in this way (you usually need to sum as many functions as you have pixels, or data points). However, if you’re not too worried about losing some data, then you can often get a very reasonable approximation of your data by discarding those functions with smaller Walsh coefficients. We won’t worry too much about storing or even how to store the approximated image. Instead, we’ll make some educated assumptions about its file size – in particular that each coefficient will take 10 bits to store (so that it can take values between -511 and 511) in addition to some bits for each index. We can show what the compressed image looks like, but it will still be represented as an uncompressed array in Python.


ENJOYED READING THIS MAGAZINE? Subscribe and make great savings at www.myfavouritemagazines.co.uk


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.