Blogue

Utiliser Sage dans une page web

14 octobre 2011 | Mise à jour: 07 mai 2012 | Catégories: web, sage | View Comments

Lorsque j'ai participé aux Sage Days 31 à Seattle en juin dernier (conférence dont l'objectif était de développer le Sage Notebook), j'ai rencontré Jason Grout (Drake University, Iowa). Le projet de Jason était de parvenir à utiliser Sage directement dans une page web (voir la discussion public single cell sur sage-devel pour en savoir plus).

Son projet est toujours en cours, mais il semble déjà être fonctionnel à en juger la page web de Rob Beezer (University of Puget Sound, Washington) qui illustre un exemple en faisant des calculs sur le graphe de Petersen et le calcul d'un factoriel.

Essayons d'immiter ce qu'il a fait! Dans la cellule qui suit, on définit une fonction de deux variables \(f(x,y) = \frac{xy}{e^{x^2 + y^2}}\) et on affiche ses lignes de niveau. Cliquez sur le bouton Calculer pour les afficher. Vous pouvez aussi changer la fonction et réévaluer la cellule.

Les graphes 3D fonctionnent aussi. Par exemple, ajoutez la ligne suivante dans la cellule et cliquez sur Calculer:

plot3d(f, (x,-4,4), (y,-4,4))

Vous obtiendrez le graphe 3D de la surface \(z = f(x,y)\).

Comment faire ?

Pour rendre ceci possible, il faut d'abord faire appel au serveur Single Cell logé à l'adresse http://aleph.sagemath.org. Cela se fait avec le code suivant:

<!-- Sage Free Trial  -->
<script type="text/javascript" src="http://aleph.sagemath.org/static/jquery.min.js"></script>
<script type="text/javascript" src="http://aleph.sagemath.org/embedded_sagecell.js"></script>
<script>
$(function() {
var makecells = function() {
singlecell.makeSagecell({
inputLocation: '#first_cell',
editor: 'codemirror',
replaceOutput: true,
hide: ['editorToggle', 'sageMode', 'computationID', 'messages', 'sessionTitle', 'done', 'sessionFilesTitle', 'sessionFiles',  'files', 'sageMode'],
evalButtonText: 'Calculer'
});
}
sagecell.init(makecells);
})
</script>

Et un peu plus bas dans la même page web, on écrit le code suivant, ce qui crée la cellule ci-haut:

<!-- First cell -->
<div id="first_cell"><script type="text/code">f(x,y) = x * y / exp(x^2 + y^2)
G = implicit_plot(f(x,y) , (x,-3,3), (y,-3,3), contours=30, cmap='hsv')
G.show(aspect_ratio=1)
</script></div>
Read and Post Comments

Trouver les composantes de Sage utilisées par un calcul

05 octobre 2011 | Catégories: sage | View Comments

Il existe une méthode peu connue pour connaître les composantes de Sage utilisées par un calcul. Supposons qu'on a le calcul suivant:

sage: g = Permutation('(2,3)')
sage: h = Permutation('(2,3,4,5)')
sage: S = PermutationGroup([g, h])
sage: c = S.conjugacy_classes_subgroups()

Pour connaître les systèmes utilisés par le calcul précédent, on écrit:

sage: import sage.misc.citation
sage: sage.misc.citation.get_systems('S.conjugacy_classes_subgroups()')
['GAP']

Cela permet de savoir par exemple quels systèmes on doit citer dans un article de recherche qui les utilise. Voici un autre exemple qui montre que quatre systèmes sont utilisés pour calculer l'intégrale \(\int \cos(x^2) dx\):

sage: from sage.misc.citation import get_systems
sage: get_systems("integrate(cos(x^2), x)")
['MPFI', 'ginac', 'GMP', 'Maxima']

L'existence de la fonction get_systems a été rappelée en juillet 2011 par Mike Hansen dans cette conversation sur sage-devel : Citing used Sage components automatically.

Read and Post Comments

Find the coordinates of the camera in Jmol

08 septembre 2011 | Catégories: jmol, sage | View Comments

In Sage, we can create 3d graphic objects like the following:

sage: a = line3d([(0,1,0), (0,0,0), (1,0,0), (2,0,0)], radius=0.1)
sage: b = line3d([(1,0,0), (1,0.5,0)], radius=0.1)
sage: g = a + b

sage: x,y = map(vector, g.bounding_box())
sage: g.frame_aspect_ratio(tuple(y-x))      # this sets the aspect ratio to 1

sage: g

Rotate the graphic object until you get a view you like.

/Files/2011/le_f.jpg

One can save an image as a jpg, but the quality is not always good and one could prefer to draw the image using another tool like tikz code. But how to draw the 3d graphic object with the same projection?

To get information about the actual view and hopefully about the camera position, right clic on the image and go to the current state ("État courant" in French).

/Files/2011/jmol_etat_courant.png /Files/2011/jmol_script_window.png

In the window that pops up, the information you need is the line starting with:

moveto 0.0 {933 -323 161 119.59}

According to the Jmol documentation of the moveto method (and also after doing some moveto tests in the script window), I understand that this tells that a rotation of angle \(119.59\) degrees is done on the axis \((933, -323, 161)\). The rotation is done counterclockwise (right-hand rule). From this information, we may then compute the rotation matrix using rotate_arbitrary method written by Robert Bradshaw and available in Sage. Note that the rotation of the method rotate_arbitrary is done counterclockwise (left-hand rule).

sage: from sage.plot.plot3d.transform import rotate_arbitrary
sage: v = (933, -323, 161)
sage: angle = 119.59                    # righ-hand rule
sage: angle = - angle                   # left-hand rule
sage: angle_rad = angle * pi / 180
sage: M = rotate_arbitrary(v, angle_rad)
sage: M
[  0.805577517225  -0.589785522899 -0.0565499842683]
[  -0.30988380511  -0.338059560724  -0.888643776062]
[  0.504991971294   0.733395371121  -0.455098163637]

Since the default position of the camera is on the positive Z axis, one can find the actual position of the camera by doing the inverse of the rotation on the vector \((0,0,1)\):

sage: camera = ~M * vector((0,0,1))
sage: camera
(0.504991971294, 0.733395371121, -0.455098163637)

To draw the same plot with the same angle of view in tikz, one needs the proper projection matrix:

sage: projection = M[:2]
sage: projection
[  0.805577517225  -0.589785522899 -0.0565499842683]
[  -0.30988380511  -0.338059560724  -0.888643776062]

One may test that this projection is really parallel to the segment that joins the origin to the camera:

sage: projection * camera
(5.55111512313e-17, 0.0)

The part of tikz code that gives the projection information is:

sage: s = '['
sage: s += 'x={(%scm, %scm)},\n' % tuple(projection * vector((1,0,0)))
sage: s += 'y={(%scm, %scm)},\n' % tuple(projection * vector((0,1,0)))
sage: s += 'z={(%scm, %scm)}'    % tuple(projection * vector((0,0,1)))
sage: s += ']'
sage: print s
[x={(0.805577517225cm, -0.30988380511cm)},
y={(-0.589785522899cm, -0.338059560724cm)},
z={(-0.0565499842683cm, -0.888643776062cm)}]

The complete tikz code is:

\begin{tikzpicture}
[x={(0.805577517225cm, -0.30988380511cm)},
y={(-0.589785522899cm, -0.338059560724cm)},
z={(-0.0565499842683cm, -0.888643776062cm)}, scale=3]
\draw[blue,line width=.4cm] (0,1,0) -- (0,0,0) -- (1,0,0) -- (2,0,0);
\draw[blue,line width=.4cm] (1,0,0) -- (1,0.5,0);
\end{tikzpicture}

The generated tikz image (pdf converted to a png: sorry for the bad quality) is:

/Files/2011/le_f_tikz.png

One can verified that it has the same view as the original Jmol view.

Thanks to my brother Jean-Philippe who tested this method.

Read and Post Comments

MathJax pour afficher du LaTeX dans une page web

07 septembre 2011 | Mise à jour: 05 janvier 2012 | Catégories: mathjax, web | View Comments

MathJax est un logiciel libre qui permet d'afficher des formules mathématiques dans une page web et qui fonctionne quelque soit le navigateur utilisé.

Propulsé par MathJax

MathJax se veut le successeur de JsMath tous deux développés principalement par David P. Cervone. Pour Cervone, il était important que le projet survive en son absence (on se sait jamais ce que la vie nous réserve) et ne dépende pas que de lui. Ainsi, il s'est assuré d'avoir les appuis nécessaires : le projet est notamment parrainé par l'American Mathematical Society et est soutenu par l'American Physical Society, Elsevier et le projet Euclide. Les sites web MathSciNet et MathOverflow utilisent maintenant MathJax.

Pour utiliser MathJax dans cette page, j'ai copié les lignes suivantes dans le code de la page:

<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js"],
    jax: ["input/TeX", "output/HTML-CSS"],
    tex2jax: {
      inlineMath: [ ["\\(","\\)"] ],
      displayMath: [ ["\\[","\\]"] ],
      processEscapes: true
    },
    "HTML-CSS": { availableFonts: ["TeX"] }
  });
</script>
<script type="text/javascript"
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js"></script>

Ainsi, des formules telles que:

Of a set \(\mathcal{S}\) is a bijection \(\psi : \mathcal{S} \rightarrow \mathcal{S}\).

se transforment en:

Of a set \(\mathcal{S}\) is a bijection \(\psi : \mathcal{S} \rightarrow \mathcal{S}\).

Autres exemples:

\(\pi = \frac{C}{d}\) devient \(\pi=\frac{C}{d}\)

\(\int\cos(x) dx = \sin(x) + K\) devient \(\int\cos(x) dx = \sin(x) + K\)

On peut changer les options d'affichage des formules en faisant un clic-droit sur les formules. Par exemple, je trouve que le résultat est plus beau lorsque HTML-CSS est utilisé plutôt que MATHML. On peut changer ce paramètre dans allant dans Settings -> Math Renderer. Par contre, HTML-CSS est un peu plus long à charger.

Read and Post Comments

Système de pointage proposé pour la saison 2011-2012 du Circuit québécois d'ultimate 4 contre 4

26 août 2011 | Mise à jour: 06 septembre 2011 | Catégories: ultimate, fqu | View Comments

Le système de pointage du Circuit québécois d'ultimate 4 contre 4 pour la saison 2010-2011 était le suivant:

  • Série A: Movember, Bye Bye, La Flotte, Coup de Foudre, Mars Attaque
  • Série B: OctoberDisk, Fun-E-nuF, La Virée

Une échelle allant de 1 à 73 points était utilisée pour les tournois de série A et donnait des points à 31 équipes. Une échelle de 1 à 16 points était utilisée pour les tournois de série B et donnait des points à 16 équipes. Ces échelles de pointages avaient été conçues à l'automne 2007 à une époque où le plus grand tournoi acceptait 36 équipes. Vu l'augmentation de popularité du circuit (le nombre d'équipes participant au circuit a doublé en trois ans), le système de pointage doit être actualisé. Notamment, sur les 88 équipes ayant participé au tournoi Mars Attaque en mars 2011, seules 31 équipes ont reçu des points et 57 équipes ont obtenu un pointage de zéro. De plus, à cause de l'ajout d'un tournoi de série A à Montréal, plusieurs équipes ont fait le choix de ne pas participer au tournoi La Flotte de Rimouski ce qui a créé un déséquilibre dans le système.

Ainsi, le système doit être actualisé pour deux raisons : (1) donner des points à toutes les équipes et (2) équilibrer le système en fonction de la force des tournois.

Plusieurs discussions ont eu lieu à ce sujet au cours des derniers mois. Certaines personnes ont suggéré de modifier complètement le système. Certains ont mentionné l'idée de ligue, etc. Dans ce message, je propose un système en continuité avec celui utilisé au cours des dernières années. À mon avis le système utilisé depuis le début va plutôt bien, on doit simplement l'actualiser.

En s'inspirant du système de l'ATP où le gagnant d'un tournoi obtient un nombre rond de points (ATP 1000 points, 2000 points, 500 points). Je propose de faire de même pour le CQU4. Ainsi, l'équipe gagnante d'un tournoi de série A obtiendra 1000 points et 400 points pour un tournoi de série B. Cinquante équipes obtiendront des points dans un tournoi de série A (sauf pour le Mars Attaque où l'échelle sera allongée) et 24 équipes obtiendront des points pour un tournoi de série B. Le tournoi La Flotte aura sa propre classe : 800 points pour l'équipe gagnante et 32 équipes obtiendront des points. Ainsi, l'équipe gagnante du tournoi La Flotte obtiendra autant de points qu'une 5e place dans un tournoi de série A ce qui correspond à la réalité. Les quatre tournois de série A seraient : Movember, Bye Bye, Coup de Foudre, Mars Attaque et les tournois de série B seraient : OctoberDisk, Fun-E-nuF, La Virée, Ottawa (nouveau) et Landaudière (nouveau). Cela est résumé dans l'image ci-bas:

/Files/2011/systeme_cqu4_2010_2011.png /Files/2011/systeme_cqu4_2011_2012.png

Points d'esprit sportif

Trois équipes obtiennent 50 points pour les tournois de Série A et le tournoi La Flotte et une équipe obtient 50 points pour les tournois de Série B.

Somme des 3 meilleurs résultats

Pour calculer le nombre de points total d'une équipe, on fait la somme des trois meilleurs résultats comme par les années précédentes.

Les valeurs exactes des points selon les positions finales à chaque tournoi sont dans le tableau suivant.

Points par tournoi

Position Série A Mars Attaque La Flotte Série B
1 1000 1000 800 400
2 938 938 728 355
3 884 884 668 317
4 835 835 614 285
5 791 791 566 256
6 750 750 522 230
7 711 711 482 206
8 675 675 444 184
9 641 641 409 164
10 609 609 377 146
11 578 578 346 129
12 549 549 317 114
13 521 521 291 99
14 494 494 265 86
15 469 469 242 74
16 444 444 219 63
17 421 421 198 52
18 399 399 178 43
19 377 377 160 34
20 356 356 142 26
21 336 336 126 19
22 317 317 110 12
23 299 299 95 6
24 281 281 82 1
25 264 264 69 0
26 248 248 57 0
27 232 232 46 0
28 217 217 35 0
29 202 202 26 0
30 188 188 17 0
31 174 174 9 0
32 161 161 1 0
33 149 149 0 0
34 137 137 0 0
35 125 125 0 0
36 114 114 0 0
37 103 103 0 0
38 93 93 0 0
39 83 83 0 0
40 74 74 0 0
41 65 73 0 0
42 57 72 0 0
43 48 70 0 0
44 41 69 0 0
45 33 68 0 0
46 26 67 0 0
47 19 65 0 0
48 13 64 0 0
49 7 63 0 0
50 1 62 0 0
51 0 61 0 0
52 0 59 0 0
53 0 58 0 0
54 0 57 0 0
55 0 56 0 0
56 0 55 0 0
57 0 53 0 0
58 0 52 0 0
59 0 51 0 0
60 0 50 0 0
61 0 48 0 0
62 0 47 0 0
63 0 46 0 0
64 0 45 0 0
65 0 44 0 0
66 0 42 0 0
67 0 41 0 0
68 0 40 0 0
69 0 39 0 0
70 0 38 0 0
71 0 36 0 0
72 0 35 0 0
73 0 34 0 0
74 0 33 0 0
75 0 31 0 0
76 0 30 0 0
77 0 29 0 0
78 0 28 0 0
79 0 27 0 0
80 0 25 0 0
81 0 24 0 0
82 0 23 0 0
83 0 22 0 0
84 0 20 0 0
85 0 19 0 0
86 0 18 0 0
87 0 17 0 0
88 0 16 0 0
89 0 14 0 0
90 0 13 0 0
91 0 12 0 0
92 0 11 0 0
93 0 10 0 0
94 0 8 0 0
95 0 7 0 0
96 0 6 0 0
97 0 5 0 0
98 0 3 0 0
99 0 2 0 0
100 0 1 0 0

Classement de la saison 2010-2011 avec le système proposé

Avec le système proposé, voici le classement qu'on obtient selon les résultats de la saison 2010-2011. La colonne Variation indique le déplacement positif ou négatif en nombre de positions par rapport au classement avec le système de l'an passé. Notez que les points d'esprit sportif ne sont pas comptabilisés dans ce classement fictif.

Position Équipe Points Variation
1 Fluo Turbo Butt Bullets 3000 1
2 NINJAX 2773 -1
3 Chainsaw 2760 0
4 Les Outs 2706 0
5 International 2296 0
6 Legends 2291 1
7 Petites Douceurs 2223 3
8 Les bergers de la mort 2216 1
9 Gros Mene 2124 2
10 Doc Tape 2052 -4
11 Mighty Disc 2048 -3
12 X-Kin (SAMBUCA) 1923 1
13 Gushmus 1705 1
14 Red Fox 1692 -2
15 Sales-Add 1548 0
16 Sweet Dreams 1407 4
17 Commando 1389 0
18 Traction integrale 1370 5
19 Triangle des Bermudes 1208 0
20 Disco inferno 1184 -4
21 TRUC 1182 1
22 DISKCOM 1158 -4
23 Captain Morgan 1069 1
24 Tree Huckers 1056 -3
25 Sugar Daddies 1000 4
26 Octopus 973 0
27 William Wallace 951 5
28 Rejected 899 5
29 TUX 863 -4
30 Diskover 810 1
31 Scrat 797 3
32 Wasabi 783 10
33 FLU 718 5
34 La Galere 675 -7
35 Poupix 670 4
36 Piranhas 618 9
37 Alkatraz 616 -1
38 Bi-Winning 609 -8
39 Morues 603 -11
40 Les Garcons Perdus 599 1
41 Je m'appelle Claude 494 -1
42 Rangers du Disque 486 2
43 Squeezee Lemon 436 11
44 Sunrise 436 11
45 Ta Mere 420 10
46 Mon Equipe 402 -3
47 Scorsoneres 390 3
48 Disco Stu 360 -13
49 Mauviettes 356 4
50 Torrents 356 4
51 Les Loups 355 -2
52 Poutine 336 7
53 Squall 333 -7
54 New Disc 323 55
55 Weapon of Choice 317 -4
56 Road Runners Atomiques 317 -4
57 Zazzle 310 -10
58 Baril Poulet 291 -21
59 Les Chemises Dragon 285 -7
60 Nightlifes 285 -7
61 Les Booms 274 20
62 Les Boudisques 268 3
63 DiskTrackFUL 261 6
64 Dispatch 256 -7
65 Les Eyjafjallajokull en Eruption 256 -7
66 Absolut 245 14
67 VooDoo 238 10
68 Saucez les Glosettes 217 11
69 Jordiscs 206 -21
70 Mad Ployes 206 -21
71 UMCE 206 -21
72 Les Rene Angelil 184 -6
73 Les Enfoirees de Grues 164 -6
74 Whimps and Phores 164 -6
75 Black Hole 161 9
76 Dix-vins 149 15
77 Weedeaters 146 -6
78 Gang bang 137 -3
79 Eclipse 125 14
80 Le Napolitain 114 -2
81 Saimiris 103 34
82 les Blitzies 83 19
83 PFunk 83 19
84 Farfadet en furie 80 10
85 Ordehum 79 28
86 Die Gotter des Ultimate 74 -4
87 UNB 74 -4
88 Tony Hortons 74 -4
89 Trick or Treat 68 32
90 Cobra Kai 67 -3
91 Hypnos 65 7
92 Haies de Ced 64 5
93 Bretzel 63 -20
94 Le Rocco 63 -20
95 Now Playing 62 17
96 les Super-Genisses 58 7
97 Chummeyz 48 -11
98 Diskobol 48 -11
99 The Crazy 88 47 19
100 Charettes de Plastique 45 -15
101 Les Cocktails 44 -25
102 Green Monster 41 -6
103 Couvercles et Plats 40 -15
104 Team Samoulle 39 12
105 Mobydicks 36 1
106 Nordet UQAR 36 1
107 Les Pades 35 -5
108 Feu Vert 33 -13
109 Mustangs 31 -1
110 T-Q 30 10
111 Va comme jte pousse 29 11
112 Dislocks 27 -22
113 Team Youhou! 25 4
114 Double Zebras 24 -22
115 Bleu Marin 23 -43
116 Chapos Poilus 22 -42
117 Mr Freeze 20 -10
118 Mammouths Laineux 19 -13
119 Los KB 18 -15
120 Nordiques 17 -9
121 Juicy Pickles 16 -22
122 Grues d'Acajou 9 -52

Formules

Soit \(M\) le nombre de points donnés à l'équipe gagnante d'un tournoi et soit \(N\) le nombre d'équipes à qui on donne des points. On assume que l'on donnera 1 point à la \(N\)-ième équipe. On définit les deux fonctions suivantes:

\[ F_{N}(p) = \int_p^N \log\left(\frac{\sqrt{2}N}{x}\right) dx \]

\[ G_{M,N}(p) = (M-1) \frac {F_{N}(p)} {F_{N}(1)} + 1 \]

La valeur de \(G_{M,N}(p)\) (arrondi à l'entier le plus près) est le nombre de points donnés à l'équipe terminant en position \(p\), \(1\leq p \leq N\), en fonction des paramètres \(M\) et \(N\). On remarque facilement que les deux hypothèses mentionnées ci-haut sont vérifiées: le nombre de points donnés à l'équipe gagnante est bien \(G_{M,N}(1) = M\) et le nombre de points donnés à l'équipe terminant en \(N\)-ième position est bien \(G_{M,N}(N) = 1\).

Pour les tournois de série A, les paramètres sont \(M=1000\) et \(N=50\). Pour le tournoi La Flotte, les paramètres sont \(M=800\) et \(N=32\). Pour les tournois de série B, les paramètres sont \(M=400\) et \(N=24\).

Afin de donner des points à toutes les équipes participant au tournoi Mars Attaque, on linéarise le nombre de points données à partir de la position 40 jusqu'à la dernière position (88 en 2011, 100 estimé en 2012) en donnant un point à la dernière position.

Questions à considérer

Quelques questions sont à considérer sur ce nouveau système et sur l'ultimate 4 contre 4 en général au Québec.

Question 1. Nouveaux tournois dans le circuit québécois

  • Combien d'équipes participeront aux nouveaux tournois d'Ottawa et de Lanaudière?
  • Quelle force donnera-t-on à ces deux nouveaux tournois (Série A, Série B, intermédiaire)?

Quelques autres propositions:

Question 2. Envergure du Championnat québécois 4 contre 4

Le Championnat québécois d'ultimate 4 contre 4 (où sont invitées les 16 meilleures équipes au classement) manque d'envergure. Il y a peu de spectateurs. C'est une opportunité perdue pour la promotion du sport. Comment augmenter son envergure?

Voici des solutions non exclusives:

  • Organiser un Beginner's Luck en parallèle.
  • Faire des ateliers pour les juniors.
  • Inviter le 17-32 au Championnat québécois dans un tournoi parallèle.
  • Inviter le top 8 des meilleures équipes junior du circuit et faire un Championnat junior 4 contre 4

Question 3. Règles du jeu du 4 contre 4

Temps morts dans les 5 dernières minutes. Veut-on faire comme à Paganello?

CQU4 au Québec: Revirement

À Paganello: reprise du jeu, validation sur compte + 2 (maximum 9)

Il faudrait aussi Faire les améliorations proposées (de forme) par Lorne Beckman il y a bientôt deux ans.

Question 4. Règlements sur l'alignement

Doit-on alléger ou modifier les règles sur l'alignement des équipes spécialement pour le Championnat québécois 4 contre 4?

Tous les joueurs d'une équipe qui participent au Championnat québécois 4 contre 4 doivent avoir joué à au moins deux tournois avec cette équipe au cours de la saison.

En effet, les demandes de dérogation au réglement génère trop de gestion administrative et d'énergie perdue.

Question 5. Les finales du dimanche

Veut-on suivre le modèle Mars Attaque 2010? C'est-à-dire devancer la finale pour que ça ne soit pas le dernier match du tournoi.

Question 6. Autres modifications (de forme) des Règlements du circuit

  • Dans la section "Critères d’organisation d’un tournoi du circuit (A et B)", fusionner la partie série A et série B.

  • Dans la section "Critères d’organisation d’un tournoi du circuit (A et B)", modifier

    Remettre à la FQU le classement final et complet des équipes de même que le top 3 de l'esprit sportif voté par les équipes participantes;

    par

    Remettre à la FQU le classement final et complet des équipes avec la ville de provenance de même que le top 3 de l'esprit sportif voté par les équipes participantes;

  • Dans la section "Responsabilité de la FQU", ajouter "Déléguer la sélection aux associations".

  • Fusionner les formulaires à la fin du document pour la série A et B qui sont presque identique en ajoutant une case à cocher : Série A ou Série B.

Read and Post Comments

« Previous Page -- Next Page »