power-box.de
-


Hinweise


Antwort
 
LinkBack Themen-Optionen Thema durchsuchen
Alt 06.07.2004, 15:36   #1
seb
TP-Veteran
 
Registriert seit: Jan 2002
seb bringt sich richtig einseb bringt sich richtig ein

[Tutorial] Erweiterte PHP-Techniken


An dieser Stelle wird in kürze ein Tutorial von Strogij zu lesen sein.
seb ist offline   Mit Zitat antworten
Linktipp

Alt 06.07.2004, 15:56   #2
TP-Specialist
 
Registriert seit: Aug 2002
Strogij hilft, wo's gehtStrogij hilft, wo's geht
Post

Teil 1


Einführung:

Ich heiße Dich willkommen und freue mich, daß Du Interesse gefunden hast, mein Tutorial anzugucken. Erstmal möchte ich natürlich festlegen, wem das Tutorial hilfreich sein könnte und was genau das Ziel ist.
Wenn erstmal die Zeit reif wird, in der man in der Lage ist eigene Scripte mit PHP zu entwerfen, stellt sich die Frage ob man nun viel/genug weiß, oder gibt es noch etwas, was PHP zu bieten hat? Die Antwort lautet eindeutig: "Ja, und ob!". Man lernt nie aus, egal in welcher Branche man sich befindet. Als Anfänger lernt man die Sprachkonstrukte der Sprache, die Benutzung und Sinn dessen. Die Praxis fördert dann eine Denkweise beim Entwurf und Verwirklichung von Ideen, die sich streng an den gelernten Stoff hällt - die Möglichkeiten und Einsatzgebiete der Sprache. Oft wird ein falscher Weg genommen und man lernt die Funktionen auswendig, was natürlich bedingt Fortschritte in der Entwicklung bringt und man auch nicht begreift, wozu PHP fähig ist.
Ohne, dass ich jetzt als Einführung einen Roman verfasse, zähle ich die Punkte auf, die als Voraussetzung dienen sollten, um mit dem Tutorial was anfangen zu könen:
  • Du hast mit PHP bereits einige (kleine) Projekte entwickelt
  • Du möchtest tiefer in PHP eindringen, Theorie verstehen

Logik und Sinn einer Programmiersprache

Zwar ist PHP keine echte Programmiersprache, aber dennoch kann man sowohl eine schlechte wie auch eine gute Anwendung/Script damit schreiben. Aber wo sind die Grenzen von gut und schlecht? Unter schlecht kann/sollte man eine leichtsinnige, unüberlegte, „draufgemotzte“ Software vorstellen, die ohne sich als Programmierer Gedanken über das Design des Codes zu machen erstellt wurde. Eine gute braucht dagegen viel mehr als das. Aber das ist auch die Kunst, nach der ein guter Programmierer streben sollte.

Ich möchte jetzt auf Einzelheiten von PHP eingehen, die oft gar nicht beachtet werden und daher auch viele Fehler hervorrufen können, die nicht immer gleich erkennbar sind.

1 Operatoren
Operatoren sind in Programmiersprachen die Schnittstelle für den Programmierer, wenn es um logische Zusammenhänge geht. Daher liegt es klar auf der Hand, dass man damit bereits ein mächtiges Werkzeug hat, was aber auch unter Umständen zur Verwirrung führen kann. Lange Ausdrücke brauchen oftmals Klammern, um vor anderen Teilen des Ausdrucks ausgewertet zu werden. Zu beachten ist hier auch die Rangfolge von Operatoren. Es würde nichts als Unfug entstehen, wenn Operatoren diese nicht hätten.

Es folgen ein paar Beispiele:
PHP-Code:
// Rangfolge der Operatoren
$a 5;
$b 10;

$a $a || $a $a// Ausdruck 1
$a == 10 && $a// Ausdruck 2
$a == $a && 10// Ausdruck 3
$b += $a != 10 $a// Ausdruck 4 
Versuche diese vier Ausdrücke im Kopf zu durchlaufen. Danach kannst Du die Ausdrücke in einem PHP-Script ansehen. Stimmen die Ergebnisse überein? Wenn ja, dann arbeitest du wie ein PHP-Parser und zwar Schritt für Schritt. Sollten verschiedene Ergebnisse deine Welt in den Wahnsinn treiben – keine Panik, für alles gibt es eine logische Erklärung!

Im Ausdruck 1 werden der Operator +, * und || benutzt. Um auf ein Ergebnis zu gelangen, muss man wissen was zuerst zusammengefasst und ausgewertet wird. Dabei geht es nach der Priorität der drei Operatoren. Höchstens in der 6. Klasse weiß man, dass „Punkt- vor Strichrechnung“ kommt, was in PHP auch nicht anders ist. PHP wertet zuerst die *-, /-, %-Operatoren aus, bevor +, - und . dran sind. Erst danach findet der endgültige Vergleich der beiden Werte mit || statt. Also erhalten wir hier den Wert 1, true um genauer zu sein, da die Vergleichsoperatoren nur bool zurückliefern. Bei dem Ausdruck 2 kann schnell ein Denkfehler entstehen, obwohl da nur zwei Operatoren zur Wahl stehen. Tatsächlich ist der Operator == „stärker“ als && und es wird daher der boolesche Wert von $a == 10 schlussendlich mit dem &&-Operator verglichen, was in unserem Fall zu true führt. Die letzten zwei Beispiele enthalten ebenfalls leichte Verwirrungen, die man aber höchstens nach dem Durchgehen der Rangtabelle im PHP-Handbuch (s. Operatoren->Operator-Rangfolge) bewältigen sollte.

Jedenfalls verwirrend fand ich die Tatsache, dass die Operatoren and und or zwar das gleiche wie && und || tun, allerdings niedrigere Ränge haben, was manchmal vorteilhaft sein kann (häufigste Verwendung von or fiel mir bei „$var = $var2 or die();“ auf).

Was ist eher schlecht an folgendem Design?
PHP-Code:
// if-Verschachtelung
if ($var1)
 {
 if (
$var2)
  {
  if (
$var3)
   {
   
//… usw.
   
}
  }
 } 
Man versucht in der Hoffnung, dass soweit eine der drei Variablen false liefert, der Vorgang der weiteren Überprüfung sofort beendet wird, um keinen zusätzlichen Laufzeitaufwand zu erzeugen. Dabei wäre die Möglichkeit, die Ausdrücke mit && zusammenzufassen gar nicht schlechter/langsamer, sondern kürzer und übersichtlicher.
PHP-Code:
if ($var1 && $var2 && $var3) { /* … */ 
Sollte $var1 false zurückliefern, wird es gar nicht erst dazu kommen, dass $var2, $var3 auf false überprüft werden. Es bringt uns also keine Nachteile, die kurze Variante zu bevorzugen.
Um es an einem Beispiel zu demonstrieren kann es der Wert einer Funktion sein, die einen String auf Inhalt prüft, bei Erfolg und auch erst danach kann eine weitere Funktion aufgerufen werden, um den gleichen String in die Datenbank einzutragen.

Die meisten haben was von den Bit-Operatoren gehört. Einen Einsatz finden diese allerdings recht selten, vielleicht auch deswegen, weil man sie gar nicht beachtet, wenn eine Lösung gefunden werden soll. Dabei sind gerade diese Operatoren die Logik, der Grundstein für alles, was man mit den anderen Operatoren erreicht. Wie man vielleicht weiß, funktioniert ein CPU nur mit einem Paar an „Schaltungen“, die für den Menschen als logisch erscheinen sollen. Baut man diese weiter auf, so sind der Fantasie (fast) keine Grenzen gesetzt. Doch wo können die Bit-Operatoren eine praktische Verwendung finden?
Sagen wir mal Flags… was fällt uns dazu ein? Also Flags sind einfache Integers, die zur Übersicht als Konstanten definiert sind. Was könnte man denn machen, wenn eine Funktion mehrere von solchen Konstanten erwarten könnte? Sagen wir mal, wenn wir eine Funktion zur Darstellung einer Figur hätten. Es könnte ein Kreis sein, der im 2D, 3D, Farbe, Glanz usw. dargestellt werden könnte. Dabei kann es sein, dass man 3D, Farbe und Glanz in der Ausgabe haben will. Was nun? Sollte man für jede Einstellung einen Parameter anlegen? Und wenn es 10 Einstellungen möglich sein sollten? Eine Hilfe wäre jetzt eine Klasse oder Array, um die Elemente zusammenzufassen. Doch auch da müsste man jedes Mal viel Schreibarbeit anwenden, auch wenn nicht direkt in dem Funktionsrumpf. Angenehmer wäre es, wenn man die Einstellungen in einem Ausdruck übergeben könnte, ohne dafür besondere Methoden anzuwenden. Und da schaffen die Bit-Operatoren eine Abhilfe:
Wenn man bedenkt, dass jede dezimale Zahl vom CPU nur binär verstanden werden kann, heißt es auch, dass die einzelnen Bits sich nur zu verschieben brauchen, damit eine eindeutige Zahl entsteht. Im Dezimalsystem ist das natürlich nicht anders, wenn man 10 um eine Stelle (im Dezimalsystem ist die Basis 10) nach links verschiebt, bekommt man 100. Danach würde 1.000, 10.000… rauskommen. Was diese Tatsache allerdings für das Binärsystem interessant macht ist, dass man unsere Flags mit den Bitoperatoren zusammenfassen kann, auf die gleiche Weise wie das Beispiel mit der Zahl 10 als Basis. Im Binärsystem ist es die 2 als Basis, auf die die Bit-Operatoren auch spezialisiert sind.
Es folgt ein Beispiel mit unserer Funktion für Kreisdarstellung: (vereinfacht)
PHP-Code:
// Konstanten
define('OPTION_2D'0x1); // Binär: 0001
define('OPTION_3D'0x2); // Binär: 0010
define('OPTION_FARBE'0x4); // Binär: 0100
define('OPTION_GLANZ'0x8); // Binär: 1000

function Zeichne_Kreis($einstellungen)
 {
 if (
$einstellungen OPTION_2D) { /* … */ }
 
// …
 
}

// Aufruf der Funktion und Zusammenfassung von Einstellungen
Zeichne_Kreis(OPTION_2D OPTION_FARBE OPTION_GLANZ); 
Was wir nun geschaffen haben ist ein zusammengesetzter Wert, der die einzelnen Einstellungen nicht „stört“. Es ist also nicht von Bedeutung, ob ich alle Einstellungen zusammenfasse oder nur eine einzelne an die Funktion übergebe – es wird das getan, was ich an die Funktion als Aufgabe/Argument übergebe. (vorausgesetzt die Funktion verhält sich richtig)
Ich empfehle denen, für die etwas Derartiges neu erscheint den Vorgang genauer anzugucken. Warum wird zum Vergleichen der &- und nicht der ==-Operator verwendet? Was macht man, wenn man den zusammengesetzten Wert auf viele Einstellungen hin in einem Rutsch überprüfen will? (z.B. OPTION_3D und OPTION_2D) (s. PHP-Handbuch->Operatoren->Bit-Operatoren)
Bit-Operatoren werden u.a. in der Kryptografie und Netzwerk verwendet. Interessiert sich einer z.B. für Verschlüsselungstheorien und Algorithmen, so ist es unausweichlich, die Bit-Operatoren zu benutzen.

Fazit: Prinzipiell sollte man immer die Operator-Ränge im Auge behalten, wenn ein komplexer Ausdruck geplant ist. Dabei spielen Klammern eine wichtige und manchmal unausweichliche Rolle.
Bit-Operatoren verstehen können kann nie direkt schaden, es öffnen sich neue Türen bei der Programmierung, die man durchaus auch nutzen könnte/sollte.

Tipps:
  • Vermeide nach Möglichkeit zu lange Ausdrücke mit vielen unterschiedlichen Operatoren. (fasse dich möglichst kurz)
  • Vermeide unüberlegte Ausdrücke (man kann sehr oft etwas verbessern, wenn man sich ein wenig Zeit lässt)
  • Benutze Klammern, um Übersicht im Ausdruck zu haben und/oder Teile mit niedrigen Operator-Rängen zuerst auswerten zu lassen

Über Operatoren könnte man noch so einiges schreiben, sie sind es auch Wert wie ich finde. Nur soll es hier kein Buch werden und ich habe noch andere Themen, über die geschrieben werden muss(?).

Geändert von Strogij (23.12.2005 um 16:19 Uhr).
Strogij ist offline   Mit Zitat antworten
Alt 06.07.2004, 16:05   #3
TP-Specialist
 
Registriert seit: Aug 2002
Strogij hilft, wo's gehtStrogij hilft, wo's geht
Post

Teil 2


2 Funktionen
Was Funktionen sind brauche ich wohl nicht zu erklären, allerdings möchte ich einige extra Sachen hervorrufen, die mit Funktionen realisierbar sind.

So ziemlich jeder kennt die eingebaute PHP-Funktion printf(). Mit dieser lassen sich beliebig viele Argumente an die Funktion übergeben. Für eigene Funktionen gibt es diese Möglichkeit ebenfalls: ab PHP 4 stehen die speziellen Funktionen func_num_args() (für die Anzahl der übergebenen Argumenten), func_get_arg($x) (für ein Argument mit der Nummer $x) und func_get_args() (für ein Array mit allen Argumenten, die übergeben wurden) zur Verfügung. Obwohl die variable Anzahl an Argumenten praktisch erscheint, ist in den meisten Fällen ein Array die bessere Entscheidung. Mit Arrays lässt es sich einfach besser weiterarbeiten. Für Funktionen wie printf() eignet sich ein Array allerdings eher weniger, die Argumente können eine Beziehung zueinander haben und man sieht diese gleich im Funktionsrumpf. Außerdem ist der Aufruf einer solchen Funktion „konstant“, ich kann nicht wie bei einem Array zur Laufzeit des Scripts die Anzahl der Werte erhöhen, Werte entfernen und dann die Funktion aufrufen. Daher soll es gut überlegt sein, bevor man etwas Derartiges verwendet, wie ich aber bereits sagte ist es oftmals überflüssig.

Ein Thema, was vielen Anfängern Angst macht ist u.a. Rekursion. Man sagt auch, dass man erstmal die Rekursion verstehen muss, um die Rekursion zu verstehen. (oh ja, das heißt so) Warum sich viele davor fürchten ist mir nicht wirklich klar, denn es gibt Sachen, die hat ein Anfänger recht schnell drauf und die sind schwieriger als Rekursion zu verstehen. Ich versuche es aber trotzdem so gut es geht zu erklären, damit es eine gewisse Klarheit schafft.
Und zwar geht es darum, dass eine Funktion sich selbst aufrufen kann, ein Beispiel:
PHP-Code:
// Rekursive Funktion
function foo($arg)
 {
 if (
$arg 5)
  {
  
// Unsere Funktion ruft sich selbst auf, allerdings mit $arg+1:
  
return foo(++$arg); 
  }
  else
   {
   return 
1;
   }
 }

// Aufrufen wie jede andere Funktion auch
foo(1); 
Von dem Sinn und Zweck der Funktion zu schweigen erfüllt diese eine von uns gewünschte Rekursion. Sie ruft sich also selbst auf wenn eine gewisse Bedingung erfüllt ist, wäre keine Bedingung da, würde eine endlose Schleife entstehen, die man ebenfalls mit while (true) erreichen könnte. Außerdem wird der Wert um 1 erhöht, bevor es übergeben wird, was sonst auch zu einer endlosen Schleife führen würde. Nützlich kann das in einigen Fällen schon sein, wie z.B. zur Entstehung von virtuellen Bäumen (Menü->Untermenü). Man spart in dem Fall eine Schleifenstruktur, die unter Umständen komplexer aussehen könnte. Man sollte einfach einmal den Weg verfolgen, den der Aufruf von Funktionen macht. Es ist mit einem Telefonat vergleichbar, die Sekretärin verbindet den Kunden mit einem Fachangestellten, der wiederum mit einer weiteren Hotline… und schließlich wird man mit der richtigen Person verbunden - return übergibt den richtigen Wert aus den weiteren, verschachtelten Funktionsaufrufen.

Tipps:
  • Behalte im Auge, dass man Funktionen mit einer variablen Anzahl an Parametern definieren kann. Überlege Dir allerdings gut, ob das deiner Funktion gut tut
  • Eine Rekursion kann Schleifen ablösen und eine gut strukturierte Funktion aufbauen, ein Menü oder Stammbaum sind zwei Beispiele, für die es in Frage käme

Geändert von Strogij (23.12.2005 um 16:18 Uhr).
Strogij ist offline   Mit Zitat antworten
Alt 23.12.2005, 09:07   #4
TP-Supporter
 
Registriert seit: Dec 2005
[jacky] ist auf einem guten Weg
Danke für das Tutorial. Ich fände es cool, wenn du noch mehr auf die Rekusrion bzw auf die bitweisen Operatoren eingehen würdest. Letzteres verstehe ich zwar einigermaßen (habe hier auch in meinem schlauen Buch einiges stehene) aber so richtig klar wird mir die Anwendung etc immer noch nicht
[jacky] ist offline   Mit Zitat antworten
Alt 23.12.2005, 16:44   #5
TP-Specialist
 
Registriert seit: Aug 2002
Strogij hilft, wo's gehtStrogij hilft, wo's geht
@[jacky]: Rekursive Funktionen sind recht schwer zu erklären. Sie rufen sich selbst auf und haben eine Bedingung, die diesen Vorgang abbricht (in meinem Beispiel "if ($arg < 5)"). Wie du siehst, habe ich beim Aufruf in der Funktion ++$arg übergeben, damit die innere Funktion einen neuen Wert hat und somit auch nicht endlos abläuft.

Was die bitweisen Operatoren angeht, da musst du das duale (binäre) Zahlensystem berücksichtigen, in dem die Variablen abgespeichert werden. Danach kannst du auch nachvollziehen, warum die Werte sich so und nicht anders ändern. In meinem Beispiel werden diese Operatoren so angewandt, dass die einzelnen Bits eine Option darstellen und man diese auch leicht ändern, überprüfen kann (ob das Bit an der bestimmten Stelle nun gesetzt ist oder nicht).
Strogij ist offline   Mit Zitat antworten
Alt 23.12.2005, 21:24   #6
TP-Supporter
 
Registriert seit: Dec 2005
[jacky] ist auf einem guten Weg

Ja also eigentlich kann ich rekursive funtionen recht gut: dafür wäre entweder eine function zu nennen, die ein ganzes verzeichnis mit allen unterordnern inkl. dateien einließt, eine function, die ein n-dimensionales array mit bestimmten filtern durchläuft oder eine function, die die fakultät ausrechnet alles schon programmiert

So, zu den bitweisen sachen. Also ich habe gestern mal in meinem Buch gelesen (welches ich vergöttere ^^). Naja dabei habe ich mal was über die verschiedenen Operatoren:

&
|
>>
<<
^
~

kennengelernt. Joa, nur der sinn ist mir einfach nicht so richtig klar.
Das dualsystem kenne ich ja, ist ja auch selbstklärend:
Code:
2^ ...   1      2     3      4      5      6   ....
           |________________________|
                             |
                             V
            2     4      8      16     32     64
Aber mir ist der sinn einfach nicht klar. In meinem Buch wird gesagt, dass es kaum zum einsatz kommt, da es auf CPU basis passiert (da es dort ja auch nur 0/1 gibt) ... naja aber wo nutzt man es ... ich fände ein anwendungsbeispiel sehr gut z.b.
[jacky] ist offline   Mit Zitat antworten
Alt 23.12.2005, 21:48   #7
TP-Specialist
 
Registriert seit: Aug 2002
Strogij hilft, wo's gehtStrogij hilft, wo's geht
Denk mal nach: Wo könnte es nützlich sein, wenn man einzelne Bits manipuliert? (ich gebe zu, in einer Sprache wie PHP nicht ganz leicht zu beantworten)
Strogij ist offline   Mit Zitat antworten
Alt 24.12.2005, 10:36   #8
TP-Supporter
 
Registriert seit: Dec 2005
[jacky] ist auf einem guten Weg
hm, kein plan :/
eventuell um irgendwas auf dem server rumzumachen, oder im dateisystem

naja, was mir noch eingefallen ist ... damit kann man auch auf ne gerade/jngerade zahl überprüfen:

PHP-Code:
<?php
$zahl 
45;

if(
$zahl 0)
    echo 
$zahl .' => gerade';
else
    echo 
$zahl .' => ungerade';
?>
verkürzt bischen die schreibweise mit dem modulo (if($zahl%2 == 0)) und lässt das professioneller wirken
[jacky] ist offline   Mit Zitat antworten
Alt 24.12.2005, 13:49   #9
TP-Specialist
 
Registriert seit: Aug 2002
Strogij hilft, wo's gehtStrogij hilft, wo's geht
Zitat:
Zitat von [jacky]
naja, was mir noch eingefallen ist ... damit kann man auch auf ne gerade/jngerade zahl überprüfen
Ne, kann man so einfach nicht.

Bei den Kryptografie-, Netzwerk-Algorithmen werden die Bit-Operatoren verwendet, weil es da auf Genauigkeit ankommt. Also solange du die nicht brauchst, besteht auch kein Bedarf.
Strogij ist offline   Mit Zitat antworten
Alt 24.12.2005, 16:07   #10
TP-Supporter
 
Registriert seit: Dec 2005
[jacky] ist auf einem guten Weg
Zitat:
Zitat von Strogij
Ne, kann man so einfach nicht.
doch , so:

PHP-Code:
<?php
$zahl 
123;

if(
$zahl 1)
    echo 
$zahl .' => ungerade';
else
    echo 
$zahl .' => gerade';
?>
hatte da was kleines vertauscht
[jacky] ist offline   Mit Zitat antworten
Alt 24.12.2005, 20:42   #11
TP-Specialist
 
Registriert seit: Aug 2002
Strogij hilft, wo's gehtStrogij hilft, wo's geht
Ja, so stimmt das, hast Recht. Weißt du auch, warum das nur mit einer 1 rechts geht?
Strogij ist offline   Mit Zitat antworten
Alt 24.12.2005, 21:45   #12
TP-Supporter
 
Registriert seit: Dec 2005
[jacky] ist auf einem guten Weg
klar doch

wenn man siche ifnach das binärsystem anschaut, dann sieht man, dass es eigentloich alles ungerade zahlen sind, außer die 2^0 (2^1 - 2^n = gerade, da ein vielfaches von 2).

so und der & operator überprüft ja, ob bei beiden zahlen die zahl gesetzt ist, also z.b.:

1010 & 1001 = 1000

so, und da man ungerade zahlen NUR mit einer 1 an letzter stelle darstellen kann, ist sie also ungerade :

5 = 101
15 = 1111

etc ...
[jacky] ist offline   Mit Zitat antworten
Alt 24.12.2005, 21:47   #13
TP-Specialist
 
Registriert seit: Aug 2002
Strogij hilft, wo's gehtStrogij hilft, wo's geht
Gut!
Strogij ist offline   Mit Zitat antworten
Antwort

  Aktuelles Thema
  TP Hilfe Forum > Web-Editoren & Coding > Traum-Dynamik > Workshops und Tutorials
[Tutorial] Erweiterte PHP-Techniken [Tutorial] Erweiterte PHP-Techniken
« [Workshop] Mein erstes OOP-Projekt | Workshop - Adressverwaltung mit PHP und MySQL »

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
 
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Erweiterte Techniken mit Photoshop [Download] BSE Royal Photoshop 15 22.02.2004 23:33
Wie funktioniert PHP, was ist Apache Nice Einfach so ... 1 24.09.2002 00:01
Php 4.1.0 Rc1 Doc.Silizium Traum-Dynamik 0 19.10.2001 17:22


Alle Zeitangaben in WEZ +2. Es ist jetzt 00:09 Uhr.

Powered by: vBulletin Version 3.7 (Deutsch)
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd. / Search Engine Friendly URLs by vBSEO 3.2.0 RC7 ©2008, Crawlability, Inc.
Traum-Projekt.com | Suchen | Archiv | Impressum | Kontakt | | | Nach oben |



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67