COMS W4771 Machine Learning - Spring 2000

 

Homework 4: Genetic Programming for Othello

Competitive Fitness Measure - Tournament Selection

 

Student: Jorge Lepre (CVN) leprej@cs.columbia.edu

Introduction

In this project we apply a Genetic Programming algorithm to learn a program to play the game Othello. The main motivation and focus is on investigating if a good player can be produced by Genetic Programming without the need for strong supervision. This means that we would like the Genetic Programming algorithm to learn a good player without the need of a human player or a sophisticated automatic player like Edgar. It is probably true that in most problems in real life that we want to apply Genetic Programming to, there is no known good solution like Edgar or the cost of evaluating each hypothesis, by playing against a human for instance, is prohibitive. Genetic Programming addresses this issue by the standard method of a Competitive Fitness Measure, where the members of the hypothesis population evolve by competing between themselves. In this project, we show the results of some runs where hypothesis compete via the method of Tournament Selection.

Methods

Every hypothesis in the Genetic Programming algorithm is represented by functional tree. This tree simply computes a real valued function from the state of the playing board. This value can be used to decide favorable moves from unfavorable ones. The fitness of a hypothesis can be evaluated by playing a game against other hypothesis. In Tournament Selection, whenever two hypothesis are required for crossover, first two hypothesis are selected from the current population at random, second a tournament group of hypothesis is selected from the current population at random, third the first two hypothesis and the tournament group are played against each other in a single elimination tournament, at last, the winner and second place hypothesis are selected for crossover resulting in the children that will fill the next population. The size of the tournament group is a parameter of the algorithm.

Code changes required for this project include overriding the method betterThan(GP gp) in the class GPOthelloGP. This method is called from the Tournament Selection function, and it plays the called GPOthelloGP object against the given GP object (that is assumed to be an instance of the GPOthelloGP class too). The result is true if the called object wins the game, false otherwise, and if there is a draw, the complexity of the hypothesis is used to decide for the simplest (shortest) one. In addition to this, every hypothesis is played 5 games against a random player, and the average score obtained against the random player is added to the score in any tournament game, thus a hypothesis must do well, on average, against both the random player and the other competing hypothesis to win the tournament.

A minor difficulty exists when implementing the betterThan(GP gp) method, in that all hypothesis are trained to play Othello as the black opponent. When playing hypothesis against each other, one of them must play white, color for which we are not training them. The difficulty is solved by inverting the board colors and scores before whichever hypothesis is playing as white makes its move, after the move is made, the board colors and scores are inverted again.

With the Java package we are given a fairly good player, Edgar, that could be used for evaluating hypothesis by playing against it. But given the aim of this project, we cannot use it for training, we want to investigate if Genetic Programming can produce a good player from little supervised information and we would not want to produce hypothesis that are overfitted to Edgar. Hence Edgar is used here only for testing, a method evaluateTest() was added to the class GPOthelloGP to evaluate the best hypothesis produced by the GP algorithm. The method evaluateTest() plays against Edgar. The best hypothesis of each generation is played against Edgar, to track the progress of the GP algorithm.

Results

Population evolution by Tournament Selection is more computationally expensive than standard Probabilistic Selection, because for each individual selected for the next population, a number of evaluations (games) roughly equal to the tournament size is required. For Probabilistic Selection only one evaluation per hypothesis is required. Here are the results of the biggest population run performed for this project:

PopulationSize = 1024
NumberOfGenerations = 25
CrossoverProbability = 90.0
CreationProbability = 0.0
CreationType = RampedHalf
MaximumDepthForCreation = 6
MaximumDepthForCrossover = 17
MaximumComplexity = 100
SelectionType = Tournament
TournamentSize = 10
DemeSize = 100
DemeticMigProbability = 100.0
SwapMutationProbability = 0.0
ShrinkMutationProbability = 0.0
TerminationFitness = 0.0
GoodRuns = 1
DemeticGrouping = false
AddBestToNewPopulation = false
SteadyState = false
PrintDetails = true
PrintPopulation = false
PrintExpression = true
PrintTree = true
TreeFontSize = 12
UseADFs = false
TestDiversity = true
ComplexityAffectsFitness = true
CheckpointGens = 0

RPB: + (2) - (2) * (2) / (2) 10 black_near_corners white_near_corners black_corners white_corners black_edges white_edges black white

Run number 1 (good runs 0)
Too complex 0
Duplicate 241

Gen| Fitness | Complexity | Depth |Variety
| Best Average Worst| B A W| B A W|
0| 3.00 141.14 373.00| 3 15.7 63| 2 3.7 6| 1.000
1| 1.00 106.48 334.00| 1 12.9 63| 1 3.7 6| 0.882
2| 1.00 94.38 334.00| 1 12.2 39| 1 3.8 6| 0.867
3| 1.00 89.85 327.00| 1 11.8 27| 1 3.9 11| 0.865
4| 1.00 88.30 301.00| 1 13.4 11| 1 4.2 4| 0.884
5| 1.00 83.57 306.00| 1 13.7 21| 1 4.4 6| 0.902
6| 1.00 84.21 309.00| 1 14.6 19| 1 4.6 7| 0.907
7| 1.00 85.20 304.00| 1 15.4 79| 1 4.9 9| 0.924
8| 1.00 81.57 293.00| 1 15.7 3| 1 5.0 2| 0.900
9| 1.00 85.14 301.00| 1 17.1 17| 1 5.3 5| 0.921
10| 1.00 83.49 295.00| 1 18.1 31| 1 5.5 8| 0.932
11| 3.00 89.05 312.00| 3 20.1 35| 2 5.8 8| 0.936
12| 1.00 86.93 335.00| 1 22.0 87| 1 6.1 12| 0.926
13| 1.00 88.73 304.00| 1 23.2 45| 1 6.3 8| 0.940
14| 1.00 91.01 359.00| 1 25.3 85| 1 6.5 10| 0.961
15| 3.00 93.84 306.00| 3 27.3 31| 2 6.8 7| 0.966
16| 3.00 91.56 307.00| 3 28.1 59| 2 7.0 15| 0.961
17| 3.00 91.38 319.00| 3 29.5 39| 2 7.2 10| 0.964
18| 1.00 95.87 328.00| 1 31.8 33| 1 7.5 7| 0.971
19| 3.00 98.06 325.00| 3 33.0 57| 2 7.7 10| 0.970
20| 3.00 91.56 324.00| 3 34.5 59| 2 7.9 10| 0.972
21| 3.00 91.77 344.00| 3 35.6 97| 2 8.1 13| 0.966
22| 1.00 92.43 347.00| 1 36.7 27| 1 8.3 10| 0.963
23| 3.00 91.33 366.00| 3 38.5 81| 2 8.5 13| 0.965
24| 3.00 94.70 311.00| 3 40.9 59| 2 9.0 12| 0.979
25| 3.00 95.29 342.00| 3 43.7 91| 2 9.2 11| 0.976

Fitness values shown are as obtained from playing against the random player only. The following hypothesis has the best fitness against the random player only. Such fitness value is only part of the competitive fitness measure and is added to each tournament result as explained before.

========================================================================
Generation:25 best:118 worst:920
GP# dad mum oper mut shrk mut fitness len dep
===== ============= ============= ======== ======== ========== ==== ====
B 118 52:RPB:1 1014:RPB:46 3.00 3 2

RPB: ( * black_edges white )

GPOthello.evaluatetest(), GP: 53.0, Edgar: 11.0

These are the best four hypothesis from the last population, they were selected by single elimination tournament over the whole population, each was played against Edgar and the resulting score is shown (the winner shows the lowest score, since we are thinking in terms consistent with fitness):

RPB: ( + ( * ( + black ( * black_corners black_edges )) ( + black_corners 10 )) ( / ( / ( - ( / ( * black_corners black_edges ) ( * black_edges white )) ( / ( * black_near_corners black_edges ) ( / ( + ( + black black_corners ) ( + ( / white black_edges ) ( - black_edges ( - white ( * black_corners black_edges ))))) ( * black_edges white )))) ( * black_edges white )) ( * black_edges white )))

GPOthello.evaluatetest(), GP: 39.0, Edgar: 25.0

RPB: ( - ( * white ( + black ( - black_edges ( + black_corners 10 )))) ( / ( + 10 white ) ( * ( * black_corners black_edges ) ( * ( + black_corners ( * black_edges black_corners )) ( + black_corners 10 )))))

GPOthello.evaluatetest(), GP: 20.0, Edgar: 44.0, Edgar loses here !

RPB: ( + ( * ( * ( * black_corners black_edges ) ( + 10 white )) ( + black_corners ( * black_edges black_corners ))) ( / ( / ( + black ( - 10 white_near_corners )) ( + white ( / ( * black_edges white ) ( * ( * black_near_corners white_corners ) ( + black_corners 10 ))))) ( * black_edges white )))

GPOthello.evaluatetest(), GP: 38.0, Edgar: 26.0

RPB: ( + ( * ( - 10 white_near_corners ) ( - ( * black_corners black_edges ) white_edges )) ( + 10 ( * black_edges black_corners )))

GPOthello.evaluatetest(), GP: 44.0, Edgar: 20.0
Run time 38283.89 seconds, 1507.80 seconds/generation

Conclusions

We are encouraged to find at least one hypothesis that can beat Edgar and that was generated without involving Edgar during training at all. The winning hypothesis looks rather complex, and should be tested against other players, like humans. It is possible that although that hypothesis beats Edgar, it may not be general enough to beat other players.

Future interesting work include extending the function node set and/or using ADFs. For this project just the function nodes given were used. Also more generations and bigger populations, run on a fast machine, may produce better results.

 -=- MIME -=-  --0__=zjnbTJiHtEHPwTDlNFcahKhtAOc0YtkAyTzM975E8cYWXv4qWO1nUd7E Content-type: text/plain; charset=us-ascii Content-Disposition: inline Dave, here it is, as attachement Othello.html: (See attached file: Othello.html) thanks, Jorge Lepre. --0__=zjnbTJiHtEHPwTDlNFcahKhtAOc0YtkAyTzM975E8cYWXv4qWO1nUd7E Content-type: text/html; name="Othello.html" Content-Disposition: attachment; filename="Othello.html" Content-transfer-encoding: base64 Content-Description: Internet HTML PGh0bWw+DQoNCjxoZWFkPg0KPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIg0KY29udGVu dD0idGV4dC9odG1sOyBjaGFyc2V0PWlzby04ODU5LTEiPg0KPG1ldGEgbmFtZT0iR0VORVJBVE9S IiBjb250ZW50PSJNaWNyb3NvZnQgRnJvbnRQYWdlIEV4cHJlc3MgMi4wIj4NCjx0aXRsZT5DUzQ5 OTUgQ29tcHV0YXRpb25hbCBHZW5vbWljczwvdGl0bGU+DQo8L2hlYWQ+DQoNCjxib2R5IGJnY29s b3I9IiNGRkZGRkYiIHRleHQ9IiMwMDAwMDAiIGxpbms9IiMwMDAwRUUiDQp2bGluaz0iIzU1MUE4 QiIgYWxpbms9IiNGRjAwMDAiPg0KDQo8aDIgYWxpZ249ImxlZnQiPkNPTVMgVzQ3NzEgTWFjaGlu ZSBMZWFybmluZyAtIFNwcmluZyAyMDAwPC9oMj4NCg0KPHAgYWxpZ249ImxlZnQiPiZuYnNwOzwv cD4NCg0KPGgyIGFsaWduPSJjZW50ZXIiPkhvbWV3b3JrIDQ6IEdlbmV0aWMgUHJvZ3JhbW1pbmcg Zm9yIE90aGVsbG88L2gyPg0KDQo8aDMgYWxpZ249ImNlbnRlciI+Q29tcGV0aXRpdmUgRml0bmVz cyBNZWFzdXJlIC0gVG91cm5hbWVudA0KU2VsZWN0aW9uPC9oMz4NCg0KPHAgYWxpZ249ImNlbnRl ciI+Jm5ic3A7PC9wPg0KDQo8aDQgYWxpZ249ImxlZnQiPlN0dWRlbnQ6IEpvcmdlIExlcHJlIChD Vk4pDQpsZXByZWpAY3MuY29sdW1iaWEuZWR1PC9oND4NCg0KPGgyIGFsaWduPSJsZWZ0Ij5JbnRy b2R1Y3Rpb248L2gyPg0KDQo8cCBhbGlnbj0ibGVmdCI+SW4gdGhpcyBwcm9qZWN0IHdlIGFwcGx5 IGEgR2VuZXRpYyBQcm9ncmFtbWluZw0KYWxnb3JpdGhtIHRvIGxlYXJuIGEgcHJvZ3JhbSB0byBw bGF5IHRoZSBnYW1lIE90aGVsbG8uIFRoZSBtYWluDQptb3RpdmF0aW9uIGFuZCBmb2N1cyBpcyBv biBpbnZlc3RpZ2F0aW5nIGlmIGEgZ29vZCBwbGF5ZXIgY2FuIGJlDQpwcm9kdWNlZCBieSBHZW5l dGljIFByb2dyYW1taW5nIHdpdGhvdXQgdGhlIG5lZWQgZm9yIHN0cm9uZw0Kc3VwZXJ2aXNpb24u IFRoaXMgbWVhbnMgdGhhdCB3ZSB3b3VsZCBsaWtlIHRoZSBHZW5ldGljDQpQcm9ncmFtbWluZyBh bGdvcml0aG0gdG8gbGVhcm4gYSBnb29kIHBsYXllciB3aXRob3V0IHRoZSBuZWVkIG9mDQphIGh1 bWFuIHBsYXllciBvciBhIHNvcGhpc3RpY2F0ZWQgYXV0b21hdGljIHBsYXllciBsaWtlIEVkZ2Fy LiBJdA0KaXMgcHJvYmFibHkgdHJ1ZSB0aGF0IGluIG1vc3QgcHJvYmxlbXMgaW4gcmVhbCBsaWZl IHRoYXQgd2Ugd2FudA0KdG8gYXBwbHkgR2VuZXRpYyBQcm9ncmFtbWluZyB0bywgdGhlcmUgaXMg bm8ga25vd24gZ29vZCBzb2x1dGlvbg0KbGlrZSBFZGdhciBvciB0aGUgY29zdCBvZiBldmFsdWF0 aW5nIGVhY2ggaHlwb3RoZXNpcywgYnkgcGxheWluZw0KYWdhaW5zdCBhIGh1bWFuIGZvciBpbnN0 YW5jZSwgaXMgcHJvaGliaXRpdmUuIEdlbmV0aWMgUHJvZ3JhbW1pbmcNCmFkZHJlc3NlcyB0aGlz IGlzc3VlIGJ5IHRoZSBzdGFuZGFyZCBtZXRob2Qgb2YgYSBDb21wZXRpdGl2ZQ0KRml0bmVzcyBN ZWFzdXJlLCB3aGVyZSB0aGUgbWVtYmVycyBvZiB0aGUgaHlwb3RoZXNpcyBwb3B1bGF0aW9uDQpl dm9sdmUgYnkgY29tcGV0aW5nIGJldHdlZW4gdGhlbXNlbHZlcy4gSW4gdGhpcyBwcm9qZWN0LCB3 ZSBzaG93DQp0aGUgcmVzdWx0cyBvZiBzb21lIHJ1bnMgd2hlcmUgaHlwb3RoZXNpcyBjb21wZXRl IHZpYSB0aGUgbWV0aG9kDQpvZiBUb3VybmFtZW50IFNlbGVjdGlvbi48L3A+DQoNCjxoMiBhbGln bj0ibGVmdCI+TWV0aG9kczwvaDI+DQoNCjxwIGFsaWduPSJsZWZ0Ij5FdmVyeSBoeXBvdGhlc2lz IGluIHRoZSBHZW5ldGljIFByb2dyYW1taW5nDQphbGdvcml0aG0gaXMgcmVwcmVzZW50ZWQgYnkg ZnVuY3Rpb25hbCB0cmVlLiBUaGlzIHRyZWUgc2ltcGx5DQpjb21wdXRlcyBhIHJlYWwgdmFsdWVk IGZ1bmN0aW9uIGZyb20gdGhlIHN0YXRlIG9mIHRoZSBwbGF5aW5nDQpib2FyZC4gVGhpcyB2YWx1 ZSBjYW4gYmUgdXNlZCB0byBkZWNpZGUgZmF2b3JhYmxlIG1vdmVzIGZyb20NCnVuZmF2b3JhYmxl IG9uZXMuIFRoZSBmaXRuZXNzIG9mIGEgaHlwb3RoZXNpcyBjYW4gYmUgZXZhbHVhdGVkIGJ5DQpw bGF5aW5nIGEgZ2FtZSBhZ2FpbnN0IG90aGVyIGh5cG90aGVzaXMuIEluIFRvdXJuYW1lbnQgU2Vs ZWN0aW9uLA0Kd2hlbmV2ZXIgdHdvIGh5cG90aGVzaXMgYXJlIHJlcXVpcmVkIGZvciBjcm9zc292 ZXIsIGZpcnN0IHR3bw0KaHlwb3RoZXNpcyBhcmUgc2VsZWN0ZWQgZnJvbSB0aGUgY3VycmVudCBw b3B1bGF0aW9uIGF0IHJhbmRvbSwNCnNlY29uZCBhIHRvdXJuYW1lbnQgZ3JvdXAgb2YgaHlwb3Ro ZXNpcyBpcyBzZWxlY3RlZCBmcm9tIHRoZQ0KY3VycmVudCBwb3B1bGF0aW9uIGF0IHJhbmRvbSwg dGhpcmQgdGhlIGZpcnN0IHR3byBoeXBvdGhlc2lzIGFuZA0KdGhlIHRvdXJuYW1lbnQgZ3JvdXAg YXJlIHBsYXllZCBhZ2FpbnN0IGVhY2ggb3RoZXIgaW4gYSBzaW5nbGUNCmVsaW1pbmF0aW9uIHRv dXJuYW1lbnQsIGF0IGxhc3QsIHRoZSB3aW5uZXIgYW5kIHNlY29uZCBwbGFjZQ0KaHlwb3RoZXNp cyBhcmUgc2VsZWN0ZWQgZm9yIGNyb3Nzb3ZlciByZXN1bHRpbmcgaW4gdGhlIGNoaWxkcmVuDQp0 aGF0IHdpbGwgZmlsbCB0aGUgbmV4dCBwb3B1bGF0aW9uLiBUaGUgc2l6ZSBvZiB0aGUgdG91cm5h bWVudA0KZ3JvdXAgaXMgYSBwYXJhbWV0ZXIgb2YgdGhlIGFsZ29yaXRobS48L3A+DQoNCjxwIGFs aWduPSJsZWZ0Ij5Db2RlIGNoYW5nZXMgcmVxdWlyZWQgZm9yIHRoaXMgcHJvamVjdCBpbmNsdWRl DQpvdmVycmlkaW5nIHRoZSBtZXRob2QgYmV0dGVyVGhhbihHUCBncCkgaW4gdGhlIGNsYXNzIEdQ T3RoZWxsb0dQLg0KVGhpcyBtZXRob2QgaXMgY2FsbGVkIGZyb20gdGhlIFRvdXJuYW1lbnQgU2Vs ZWN0aW9uIGZ1bmN0aW9uLCBhbmQNCml0IHBsYXlzIHRoZSBjYWxsZWQgR1BPdGhlbGxvR1Agb2Jq ZWN0IGFnYWluc3QgdGhlIGdpdmVuIEdQDQpvYmplY3QgKHRoYXQgaXMgYXNzdW1lZCB0byBiZSBh biBpbnN0YW5jZSBvZiB0aGUgR1BPdGhlbGxvR1ANCmNsYXNzIHRvbykuIFRoZSByZXN1bHQgaXMg dHJ1ZSBpZiB0aGUgY2FsbGVkIG9iamVjdCB3aW5zIHRoZQ0KZ2FtZSwgZmFsc2Ugb3RoZXJ3aXNl LCBhbmQgaWYgdGhlcmUgaXMgYSBkcmF3LCB0aGUgY29tcGxleGl0eSBvZg0KdGhlIGh5cG90aGVz aXMgaXMgdXNlZCB0byBkZWNpZGUgZm9yIHRoZSBzaW1wbGVzdCAoc2hvcnRlc3QpIG9uZS4NCklu IGFkZGl0aW9uIHRvIHRoaXMsIGV2ZXJ5IGh5cG90aGVzaXMgaXMgcGxheWVkIDUgZ2FtZXMgYWdh aW5zdCBhDQpyYW5kb20gcGxheWVyLCBhbmQgdGhlIGF2ZXJhZ2Ugc2NvcmUgb2J0YWluZWQgYWdh aW5zdCB0aGUgcmFuZG9tDQpwbGF5ZXIgaXMgYWRkZWQgdG8gdGhlIHNjb3JlIGluIGFueSB0b3Vy bmFtZW50IGdhbWUsIHRodXMgYQ0KaHlwb3RoZXNpcyBtdXN0IGRvIHdlbGwsIG9uIGF2ZXJhZ2Us IGFnYWluc3QgYm90aCB0aGUgcmFuZG9tDQpwbGF5ZXIgYW5kIHRoZSBvdGhlciBjb21wZXRpbmcg aHlwb3RoZXNpcyB0byB3aW4gdGhlIHRvdXJuYW1lbnQuPC9wPg0KDQo8cCBhbGlnbj0ibGVmdCI+ QSBtaW5vciBkaWZmaWN1bHR5IGV4aXN0cyB3aGVuIGltcGxlbWVudGluZyB0aGUNCmJldHRlclRo YW4oR1AgZ3ApIG1ldGhvZCwgaW4gdGhhdCBhbGwgaHlwb3RoZXNpcyBhcmUgdHJhaW5lZCB0bw0K cGxheSBPdGhlbGxvIGFzIHRoZSBibGFjayBvcHBvbmVudC4gV2hlbiBwbGF5aW5nIGh5cG90aGVz aXMNCmFnYWluc3QgZWFjaCBvdGhlciwgb25lIG9mIHRoZW0gbXVzdCBwbGF5IHdoaXRlLCBjb2xv ciBmb3Igd2hpY2gNCndlIGFyZSBub3QgdHJhaW5pbmcgdGhlbS4gVGhlIGRpZmZpY3VsdHkgaXMg c29sdmVkIGJ5IGludmVydGluZw0KdGhlIGJvYXJkIGNvbG9ycyBhbmQgc2NvcmVzIGJlZm9yZSB3 aGljaGV2ZXIgaHlwb3RoZXNpcyBpcw0KcGxheWluZyBhcyB3aGl0ZSBtYWtlcyBpdHMgbW92ZSwg YWZ0ZXIgdGhlIG1vdmUgaXMgbWFkZSwgdGhlDQpib2FyZCBjb2xvcnMgYW5kIHNjb3JlcyBhcmUg aW52ZXJ0ZWQgYWdhaW4uPC9wPg0KDQo8cCBhbGlnbj0ibGVmdCI+V2l0aCB0aGUgSmF2YSBwYWNr YWdlIHdlIGFyZSBnaXZlbiBhIGZhaXJseSBnb29kDQpwbGF5ZXIsIEVkZ2FyLCB0aGF0IGNvdWxk IGJlIHVzZWQgZm9yIGV2YWx1YXRpbmcgaHlwb3RoZXNpcyBieQ0KcGxheWluZyBhZ2FpbnN0IGl0 LiBCdXQgZ2l2ZW4gdGhlIGFpbSBvZiB0aGlzIHByb2plY3QsIHdlIGNhbm5vdA0KdXNlIGl0IGZv ciB0cmFpbmluZywgd2Ugd2FudCB0byBpbnZlc3RpZ2F0ZSBpZiBHZW5ldGljDQpQcm9ncmFtbWlu ZyBjYW4gcHJvZHVjZSBhIGdvb2QgcGxheWVyIGZyb20gbGl0dGxlIHN1cGVydmlzZWQNCmluZm9y bWF0aW9uIGFuZCB3ZSB3b3VsZCBub3Qgd2FudCB0byBwcm9kdWNlIGh5cG90aGVzaXMgdGhhdCBh cmUNCm92ZXJmaXR0ZWQgdG8gRWRnYXIuIEhlbmNlIEVkZ2FyIGlzIHVzZWQgaGVyZSBvbmx5IGZv ciB0ZXN0aW5nLCBhDQptZXRob2QgZXZhbHVhdGVUZXN0KCkgd2FzIGFkZGVkIHRvIHRoZSBjbGFz cyBHUE90aGVsbG9HUCB0bw0KZXZhbHVhdGUgdGhlIGJlc3QgaHlwb3RoZXNpcyBwcm9kdWNlZCBi eSB0aGUgR1AgYWxnb3JpdGhtLiBUaGUNCm1ldGhvZCBldmFsdWF0ZVRlc3QoKSBwbGF5cyBhZ2Fp bnN0IEVkZ2FyLiBUaGUgYmVzdCBoeXBvdGhlc2lzIG9mDQplYWNoIGdlbmVyYXRpb24gaXMgcGxh eWVkIGFnYWluc3QgRWRnYXIsIHRvIHRyYWNrIHRoZSBwcm9ncmVzcyBvZg0KdGhlIEdQIGFsZ29y aXRobS48L3A+DQoNCjxoMiBhbGlnbj0ibGVmdCI+UmVzdWx0czwvaDI+DQoNCjxwIGFsaWduPSJs ZWZ0Ij5Qb3B1bGF0aW9uIGV2b2x1dGlvbiBieSBUb3VybmFtZW50IFNlbGVjdGlvbiBpcw0KbW9y ZSBjb21wdXRhdGlvbmFsbHkgZXhwZW5zaXZlIHRoYW4gc3RhbmRhcmQgUHJvYmFiaWxpc3RpYw0K U2VsZWN0aW9uLCBiZWNhdXNlIGZvciBlYWNoIGluZGl2aWR1YWwgc2VsZWN0ZWQgZm9yIHRoZSBu ZXh0DQpwb3B1bGF0aW9uLCBhIG51bWJlciBvZiBldmFsdWF0aW9ucyAoZ2FtZXMpIHJvdWdobHkg ZXF1YWwgdG8gdGhlDQp0b3VybmFtZW50IHNpemUgaXMgcmVxdWlyZWQuIEZvciBQcm9iYWJpbGlz dGljIFNlbGVjdGlvbiBvbmx5IG9uZQ0KZXZhbHVhdGlvbiBwZXIgaHlwb3RoZXNpcyBpcyByZXF1 aXJlZC4gSGVyZSBhcmUgdGhlIHJlc3VsdHMgb2YNCnRoZSBiaWdnZXN0IHBvcHVsYXRpb24gcnVu IHBlcmZvcm1lZCBmb3IgdGhpcyBwcm9qZWN0OjwvcD4NCg0KPHAgYWxpZ249ImxlZnQiPjxmb250 IGZhY2U9IkNvdXJpZXIiPlBvcHVsYXRpb25TaXplID0gMTAyNDxicj4NCk51bWJlck9mR2VuZXJh dGlvbnMgPSAyNTxicj4NCkNyb3Nzb3ZlclByb2JhYmlsaXR5ID0gOTAuMDxicj4NCkNyZWF0aW9u UHJvYmFiaWxpdHkgPSAwLjA8YnI+DQpDcmVhdGlvblR5cGUgPSBSYW1wZWRIYWxmPGJyPg0KTWF4 aW11bURlcHRoRm9yQ3JlYXRpb24gPSA2PGJyPg0KTWF4aW11bURlcHRoRm9yQ3Jvc3NvdmVyID0g MTc8YnI+DQpNYXhpbXVtQ29tcGxleGl0eSA9IDEwMDxicj4NClNlbGVjdGlvblR5cGUgPSBUb3Vy bmFtZW50PGJyPg0KVG91cm5hbWVudFNpemUgPSAxMDxicj4NCkRlbWVTaXplID0gMTAwPGJyPg0K RGVtZXRpY01pZ1Byb2JhYmlsaXR5ID0gMTAwLjA8YnI+DQpTd2FwTXV0YXRpb25Qcm9iYWJpbGl0 eSA9IDAuMDxicj4NClNocmlua011dGF0aW9uUHJvYmFiaWxpdHkgPSAwLjA8YnI+DQpUZXJtaW5h dGlvbkZpdG5lc3MgPSAwLjA8YnI+DQpHb29kUnVucyA9IDE8YnI+DQpEZW1ldGljR3JvdXBpbmcg PSBmYWxzZTxicj4NCkFkZEJlc3RUb05ld1BvcHVsYXRpb24gPSBmYWxzZTxicj4NClN0ZWFkeVN0 YXRlID0gZmFsc2U8YnI+DQpQcmludERldGFpbHMgPSB0cnVlPGJyPg0KUHJpbnRQb3B1bGF0aW9u ID0gZmFsc2U8YnI+DQpQcmludEV4cHJlc3Npb24gPSB0cnVlPGJyPg0KUHJpbnRUcmVlID0gdHJ1 ZTxicj4NClRyZWVGb250U2l6ZSA9IDEyPGJyPg0KVXNlQURGcyA9IGZhbHNlPGJyPg0KVGVzdERp dmVyc2l0eSA9IHRydWU8YnI+DQpDb21wbGV4aXR5QWZmZWN0c0ZpdG5lc3MgPSB0cnVlPGJyPg0K Q2hlY2twb2ludEdlbnMgPSAwPGJyPg0KPGJyPg0KUlBCOiArICgyKSAtICgyKSAqICgyKSAvICgy KSAxMCBibGFja19uZWFyX2Nvcm5lcnMNCndoaXRlX25lYXJfY29ybmVycyBibGFja19jb3JuZXJz IHdoaXRlX2Nvcm5lcnMgYmxhY2tfZWRnZXMNCndoaXRlX2VkZ2VzIGJsYWNrIHdoaXRlIDxicj4N Cjxicj4NClJ1biBudW1iZXIgMSAoZ29vZCBydW5zIDApPGJyPg0KVG9vIGNvbXBsZXggMDxicj4N CkR1cGxpY2F0ZSAyNDE8YnI+DQo8YnI+DQpHZW58IEZpdG5lc3MgfCBDb21wbGV4aXR5IHwgRGVw dGggfFZhcmlldHk8YnI+DQp8IEJlc3QgQXZlcmFnZSBXb3JzdHwgQiBBIFd8IEIgQSBXfDxicj4N CjB8IDMuMDAgMTQxLjE0IDM3My4wMHwgMyAxNS43IDYzfCAyIDMuNyA2fCAxLjAwMCA8YnI+DQox fCAxLjAwIDEwNi40OCAzMzQuMDB8IDEgMTIuOSA2M3wgMSAzLjcgNnwgMC44ODIgPGJyPg0KMnwg MS4wMCA5NC4zOCAzMzQuMDB8IDEgMTIuMiAzOXwgMSAzLjggNnwgMC44NjcgPGJyPg0KM3wgMS4w MCA4OS44NSAzMjcuMDB8IDEgMTEuOCAyN3wgMSAzLjkgMTF8IDAuODY1IDxicj4NCjR8IDEuMDAg ODguMzAgMzAxLjAwfCAxIDEzLjQgMTF8IDEgNC4yIDR8IDAuODg0IDxicj4NCjV8IDEuMDAgODMu NTcgMzA2LjAwfCAxIDEzLjcgMjF8IDEgNC40IDZ8IDAuOTAyIDxicj4NCjZ8IDEuMDAgODQuMjEg MzA5LjAwfCAxIDE0LjYgMTl8IDEgNC42IDd8IDAuOTA3IDxicj4NCjd8IDEuMDAgODUuMjAgMzA0 LjAwfCAxIDE1LjQgNzl8IDEgNC45IDl8IDAuOTI0IDxicj4NCjh8IDEuMDAgODEuNTcgMjkzLjAw fCAxIDE1LjcgM3wgMSA1LjAgMnwgMC45MDAgPGJyPg0KOXwgMS4wMCA4NS4xNCAzMDEuMDB8IDEg MTcuMSAxN3wgMSA1LjMgNXwgMC45MjEgPGJyPg0KMTB8IDEuMDAgODMuNDkgMjk1LjAwfCAxIDE4 LjEgMzF8IDEgNS41IDh8IDAuOTMyIDxicj4NCjExfCAzLjAwIDg5LjA1IDMxMi4wMHwgMyAyMC4x IDM1fCAyIDUuOCA4fCAwLjkzNiA8YnI+DQoxMnwgMS4wMCA4Ni45MyAzMzUuMDB8IDEgMjIuMCA4 N3wgMSA2LjEgMTJ8IDAuOTI2IDxicj4NCjEzfCAxLjAwIDg4LjczIDMwNC4wMHwgMSAyMy4yIDQ1 fCAxIDYuMyA4fCAwLjk0MCA8YnI+DQoxNHwgMS4wMCA5MS4wMSAzNTkuMDB8IDEgMjUuMyA4NXwg MSA2LjUgMTB8IDAuOTYxIDxicj4NCjE1fCAzLjAwIDkzLjg0IDMwNi4wMHwgMyAyNy4zIDMxfCAy IDYuOCA3fCAwLjk2NiA8YnI+DQoxNnwgMy4wMCA5MS41NiAzMDcuMDB8IDMgMjguMSA1OXwgMiA3 LjAgMTV8IDAuOTYxIDxicj4NCjE3fCAzLjAwIDkxLjM4IDMxOS4wMHwgMyAyOS41IDM5fCAyIDcu MiAxMHwgMC45NjQgPGJyPg0KMTh8IDEuMDAgOTUuODcgMzI4LjAwfCAxIDMxLjggMzN8IDEgNy41 IDd8IDAuOTcxIDxicj4NCjE5fCAzLjAwIDk4LjA2IDMyNS4wMHwgMyAzMy4wIDU3fCAyIDcuNyAx MHwgMC45NzAgPGJyPg0KMjB8IDMuMDAgOTEuNTYgMzI0LjAwfCAzIDM0LjUgNTl8IDIgNy45IDEw fCAwLjk3MiA8YnI+DQoyMXwgMy4wMCA5MS43NyAzNDQuMDB8IDMgMzUuNiA5N3wgMiA4LjEgMTN8 IDAuOTY2IDxicj4NCjIyfCAxLjAwIDkyLjQzIDM0Ny4wMHwgMSAzNi43IDI3fCAxIDguMyAxMHwg MC45NjMgPGJyPg0KMjN8IDMuMDAgOTEuMzMgMzY2LjAwfCAzIDM4LjUgODF8IDIgOC41IDEzfCAw Ljk2NSA8YnI+DQoyNHwgMy4wMCA5NC43MCAzMTEuMDB8IDMgNDAuOSA1OXwgMiA5LjAgMTJ8IDAu OTc5IDxicj4NCjI1fCAzLjAwIDk1LjI5IDM0Mi4wMHwgMyA0My43IDkxfCAyIDkuMiAxMXwgMC45 NzYgPGJyPg0KPGJyPg0KPC9mb250PkZpdG5lc3MgdmFsdWVzIHNob3duIGFyZSBhcyBvYnRhaW5l ZCBmcm9tIHBsYXlpbmcgYWdhaW5zdA0KdGhlIHJhbmRvbSBwbGF5ZXIgb25seS4gVGhlIGZvbGxv d2luZyBoeXBvdGhlc2lzIGhhcyB0aGUgYmVzdA0KZml0bmVzcyBhZ2FpbnN0IHRoZSByYW5kb20g cGxheWVyIG9ubHkuIFN1Y2ggZml0bmVzcyB2YWx1ZSBpcw0Kb25seSBwYXJ0IG9mIHRoZSBjb21w ZXRpdGl2ZSBmaXRuZXNzIG1lYXN1cmUgYW5kIGlzIGFkZGVkIHRvIGVhY2gNCnRvdXJuYW1lbnQg cmVzdWx0IGFzIGV4cGxhaW5lZCBiZWZvcmUuPC9wPg0KDQo8cCBhbGlnbj0ibGVmdCI+PGZvbnQg ZmFjZT0iQ291cmllciI+PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PGJyPg0KR2VuZXJhdGlvbjoyNSBiZXN0OjEx OCB3b3JzdDo5MjA8YnI+DQpHUCMgZGFkIG11bSBvcGVyIG11dCBzaHJrIG11dCBmaXRuZXNzIGxl biBkZXA8YnI+DQo9PT09PSA9PT09PT09PT09PT09ID09PT09PT09PT09PT0gPT09PT09PT0gPT09 PT09PT0gPT09PT09PT09PQ0KPT09PSA9PT09PGJyPg0KQiAxMTggNTI6UlBCOjEgMTAxNDpSUEI6 NDYgMy4wMCAzIDI8YnI+DQo8YnI+DQpSUEI6ICggKiBibGFja19lZGdlcyB3aGl0ZSApPGJyPg0K PGJyPg0KR1BPdGhlbGxvLmV2YWx1YXRldGVzdCgpLCBHUDogNTMuMCwgRWRnYXI6IDExLjA8YnI+ DQo8L2ZvbnQ+PC9wPg0KDQo8cCBhbGlnbj0ibGVmdCI+VGhlc2UgYXJlIHRoZSBiZXN0IGZvdXIg aHlwb3RoZXNpcyBmcm9tIHRoZSBsYXN0DQpwb3B1bGF0aW9uLCB0aGV5IHdlcmUgc2VsZWN0ZWQg Ynkgc2luZ2xlIGVsaW1pbmF0aW9uIHRvdXJuYW1lbnQNCm92ZXIgdGhlIHdob2xlIHBvcHVsYXRp b24sIGVhY2ggd2FzIHBsYXllZCBhZ2FpbnN0IEVkZ2FyIGFuZCB0aGUNCnJlc3VsdGluZyBzY29y ZSBpcyBzaG93biAodGhlIHdpbm5lciBzaG93cyB0aGUgbG93ZXN0IHNjb3JlLA0Kc2luY2Ugd2Ug YXJlIHRoaW5raW5nIGluIHRlcm1zIGNvbnNpc3RlbnQgd2l0aCBmaXRuZXNzKTo8L3A+DQoNCjxw IGFsaWduPSJsZWZ0Ij48Zm9udCBmYWNlPSJDb3VyaWVyIj5SUEI6ICggKyAoICogKCArIGJsYWNr ICggKg0KYmxhY2tfY29ybmVycyBibGFja19lZGdlcyApKSAoICsgYmxhY2tfY29ybmVycyAxMCAp KSAoIC8gKCAvICggLQ0KKCAvICggKiBibGFja19jb3JuZXJzIGJsYWNrX2VkZ2VzICkgKCAqIGJs YWNrX2VkZ2VzIHdoaXRlICkpICggLw0KKCAqIGJsYWNrX25lYXJfY29ybmVycyBibGFja19lZGdl cyApICggLyAoICsgKCArIGJsYWNrDQpibGFja19jb3JuZXJzICkgKCArICggLyB3aGl0ZSBibGFj a19lZGdlcyApICggLSBibGFja19lZGdlcyAoIC0NCndoaXRlICggKiBibGFja19jb3JuZXJzIGJs YWNrX2VkZ2VzICkpKSkpICggKiBibGFja19lZGdlcyB3aGl0ZQ0KKSkpKSAoICogYmxhY2tfZWRn ZXMgd2hpdGUgKSkgKCAqIGJsYWNrX2VkZ2VzIHdoaXRlICkpKTxicj4NCjxicj4NCkdQT3RoZWxs by5ldmFsdWF0ZXRlc3QoKSwgR1A6IDM5LjAsIEVkZ2FyOiAyNS4wPGJyPg0KPC9mb250PjwvcD4N Cg0KPHAgYWxpZ249ImxlZnQiPjxmb250IGZhY2U9IkNvdXJpZXIiPlJQQjogKCAtICggKiB3aGl0 ZSAoICsgYmxhY2sNCiggLSBibGFja19lZGdlcyAoICsgYmxhY2tfY29ybmVycyAxMCApKSkpICgg LyAoICsgMTAgd2hpdGUgKSAoICoNCiggKiBibGFja19jb3JuZXJzIGJsYWNrX2VkZ2VzICkgKCAq ICggKyBibGFja19jb3JuZXJzICggKg0KYmxhY2tfZWRnZXMgYmxhY2tfY29ybmVycyApKSAoICsg YmxhY2tfY29ybmVycyAxMCApKSkpKTxicj4NCjxicj4NCkdQT3RoZWxsby5ldmFsdWF0ZXRlc3Qo KSwgR1A6IDIwLjAsIEVkZ2FyOiA0NC4wLCBFZGdhciBsb3NlcyBoZXJlDQohPGJyPg0KPC9mb250 PjwvcD4NCg0KPHAgYWxpZ249ImxlZnQiPjxmb250IGZhY2U9IkNvdXJpZXIiPlJQQjogKCArICgg KiAoICogKCAqDQpibGFja19jb3JuZXJzIGJsYWNrX2VkZ2VzICkgKCArIDEwIHdoaXRlICkpICgg KyBibGFja19jb3JuZXJzICggKg0KYmxhY2tfZWRnZXMgYmxhY2tfY29ybmVycyApKSkgKCAvICgg LyAoICsgYmxhY2sgKCAtIDEwDQp3aGl0ZV9uZWFyX2Nvcm5lcnMgKSkgKCArIHdoaXRlICggLyAo ICogYmxhY2tfZWRnZXMgd2hpdGUgKSAoICogKA0KKiBibGFja19uZWFyX2Nvcm5lcnMgd2hpdGVf Y29ybmVycyApICggKyBibGFja19jb3JuZXJzIDEwICkpKSkpICgNCiogYmxhY2tfZWRnZXMgd2hp dGUgKSkpPGJyPg0KPGJyPg0KR1BPdGhlbGxvLmV2YWx1YXRldGVzdCgpLCBHUDogMzguMCwgRWRn YXI6IDI2LjA8YnI+DQo8L2ZvbnQ+PC9wPg0KDQo8cCBhbGlnbj0ibGVmdCI+PGZvbnQgZmFjZT0i Q291cmllciI+UlBCOiAoICsgKCAqICggLSAxMA0Kd2hpdGVfbmVhcl9jb3JuZXJzICkgKCAtICgg KiBibGFja19jb3JuZXJzIGJsYWNrX2VkZ2VzICkNCndoaXRlX2VkZ2VzICkpICggKyAxMCAoICog YmxhY2tfZWRnZXMgYmxhY2tfY29ybmVycyApKSk8YnI+DQo8YnI+DQpHUE90aGVsbG8uZXZhbHVh dGV0ZXN0KCksIEdQOiA0NC4wLCBFZGdhcjogMjAuMDxicj4NClJ1biB0aW1lIDM4MjgzLjg5IHNl Y29uZHMsIDE1MDcuODAgc2Vjb25kcy9nZW5lcmF0aW9uPGJyPg0KPC9mb250PjwvcD4NCg0KPGgy IGFsaWduPSJsZWZ0Ij5Db25jbHVzaW9uczwvaDI+DQoNCjxwIGFsaWduPSJsZWZ0Ij5XZSBhcmUg ZW5jb3VyYWdlZCB0byBmaW5kIGF0IGxlYXN0IG9uZSBoeXBvdGhlc2lzDQp0aGF0IGNhbiBiZWF0 IEVkZ2FyIGFuZCB0aGF0IHdhcyBnZW5lcmF0ZWQgd2l0aG91dCBpbnZvbHZpbmcNCkVkZ2FyIGR1 cmluZyB0cmFpbmluZyBhdCBhbGwuIFRoZSB3aW5uaW5nIGh5cG90aGVzaXMgbG9va3MgcmF0aGVy DQpjb21wbGV4LCBhbmQgc2hvdWxkIGJlIHRlc3RlZCBhZ2FpbnN0IG90aGVyIHBsYXllcnMsIGxp a2UgaHVtYW5zLg0KSXQgaXMgcG9zc2libGUgdGhhdCBhbHRob3VnaCB0aGF0IGh5cG90aGVzaXMg YmVhdHMgRWRnYXIsIGl0IG1heQ0Kbm90IGJlIGdlbmVyYWwgZW5vdWdoIHRvIGJlYXQgb3RoZXIg cGxheWVycy48L3A+DQoNCjxwIGFsaWduPSJsZWZ0Ij5GdXR1cmUgaW50ZXJlc3Rpbmcgd29yayBp bmNsdWRlIGV4dGVuZGluZyB0aGUNCmZ1bmN0aW9uIG5vZGUgc2V0IGFuZC9vciB1c2luZyBBREZz LiBGb3IgdGhpcyBwcm9qZWN0IGp1c3QgdGhlDQpmdW5jdGlvbiBub2RlcyBnaXZlbiB3ZXJlIHVz ZWQuIEFsc28gbW9yZSBnZW5lcmF0aW9ucyBhbmQgYmlnZ2VyDQpwb3B1bGF0aW9ucywgcnVuIG9u IGEgZmFzdCBtYWNoaW5lLCBtYXkgcHJvZHVjZSBiZXR0ZXIgcmVzdWx0cy48L3A+DQo8L2JvZHk+ DQo8L2h0bWw+DQo= --0__=zjnbTJiHtEHPwTDlNFcahKhtAOc0YtkAyTzM975E8cYWXv4qWO1nUd7E--