/*
* Design a Bird
*
* Problem
* Model Pigeon, Crow, Sparrow, Ostrich, Penguin.
* Penguin and Ostrich cannot fly.
* Crow and Sparrow fly the same way. Pigeon flies differently.
* Every bird eats and sings the same way.
*
* These are different ways people first design this. Not all of them work.
*
* 1. One Bird class + if (sparrow) / else if (penguin) in fly()
* Breaks SRP and OCP. Unreadable at 20 species. Tests pile into
* one file. Two people collide on the same class.
*
* 2. Abstract Bird with fly() on the parent
* Penguin then "implements" fly with an empty body, a log, or
* an exception. Callers still think every Bird can fly. Breaks LSP.
*
* 3. FlyableBird / NonFlyableBird extra parent classes
* Fine for one behavior. Add eat variants and the tree explodes
* into 2^n classes. Flying and eating are behaviors, not kinds of bird.
*
* 4. The design in this file (the one that works)
* Bird holds identity + eat/sing. No fly() on Bird.
* Only flyers implement Flyable (ISP + LSP).
* Flying style is a separate class, injected in the constructor
* (Strategy + DIP + DI).
* Crow and Sparrow share CrowSparrowFlyingBehavior.
* A new bird is a new class. If it flies like Crow, reuse that
* behavior. Do not edit old species (OCP).
*
* Usage
* List<Bird> → describe / eat / sing for everyone
* List<Flyable> → fly() with no instanceof and no try/catch
*/
import java.util.ArrayList;
import java.util.List;
/* Small interfaces so a bird only takes on behaviors it actually has. */
interface Flyable {
void fly();
}
interface FlyingBehavior {
void makeFly();
}
interface EatingBehavior {
void eat();
}
interface SingingBehavior {
void sing();
}
/* Flying styles sit in their own classes so birds stay small. */
class CrowSparrowFlyingBehavior implements FlyingBehavior {
@Override
public void makeFly() {
System.
out.
println(" flying with short rapid wing flaps"); }
}
class PigeonFlyingBehavior implements FlyingBehavior {
@Override
public void makeFly() {
System.
out.
println(" flying in a steady glide with occasional flaps"); }
}
class DefaultEatingBehavior implements EatingBehavior {
@Override
public void eat() {
System.
out.
println(" pecking food"); }
}
class DefaultSingingBehavior implements SingingBehavior {
@Override
public void sing() {
System.
out.
println(" singing"); }
}
/*
* Shared name / color / size / weight, plus eat and sing.
* fly() is not here — Penguin and Ostrich would otherwise have to fake it.
*/
abstract class Bird {
private final double weightKg;
private final EatingBehavior eating;
private final SingingBehavior singing;
EatingBehavior eating, SingingBehavior singing) {
this.name = name;
this.color = color;
this.size = size;
this.weightKg = weightKg;
this.eating = eating;
this.singing = singing;
}
public String getName
() { return name
; }
public void eat() { eating.eat(); }
public void sing() { singing.sing(); }
public void describe() {
System.
out.
println(name
+ " [" + color
+ ", " + size
+ ", " + weightKg
+ "kg]"); }
}
/* Only species that fly implement Flyable. */
class Pigeon extends Bird implements Flyable {
private final FlyingBehavior flying;
EatingBehavior eating, SingingBehavior singing,
FlyingBehavior flying) {
super("Pigeon", color, size, weightKg, eating, singing);
this.flying = flying;
}
@Override
public void fly() {
flying.makeFly();
}
}
class Crow extends Bird implements Flyable {
private final FlyingBehavior flying;
EatingBehavior eating, SingingBehavior singing,
FlyingBehavior flying) {
super("Crow", color, size, weightKg, eating, singing);
this.flying = flying;
}
@Override
public void fly() {
flying.makeFly();
}
}
class Sparrow extends Bird implements Flyable {
private final FlyingBehavior flying;
EatingBehavior eating, SingingBehavior singing,
FlyingBehavior flying) {
super("Sparrow", color, size, weightKg, eating, singing);
this.flying = flying;
}
@Override
public void fly() {
flying.makeFly();
}
}
class Ostrich extends Bird {
EatingBehavior eating, SingingBehavior singing) {
super("Ostrich", color, size, weightKg, eating, singing);
}
}
class Penguin extends Bird {
EatingBehavior eating, SingingBehavior singing) {
super("Penguin", color, size, weightKg, eating, singing);
}
}
/* Main creates the behaviors and hands them to each bird. */
public class Main {
public static void main
(String[] args
) { EatingBehavior eat = new DefaultEatingBehavior();
SingingBehavior sing = new DefaultSingingBehavior();
FlyingBehavior crowSparrowFly = new CrowSparrowFlyingBehavior();
FlyingBehavior pigeonFly = new PigeonFlyingBehavior();
Pigeon pigeon = new Pigeon("grey", "medium", 0.3, eat, sing, pigeonFly);
Crow crow = new Crow("black", "medium", 0.5, eat, sing, crowSparrowFly);
Sparrow sparrow = new Sparrow("brown", "small", 0.03, eat, sing, crowSparrowFly);
Ostrich ostrich = new Ostrich("brown", "large", 110.0, eat, sing);
Penguin penguin = new Penguin("black-white", "medium", 15.0, eat, sing);
List<Bird> sanctuary = new ArrayList<Bird>();
sanctuary.add(pigeon);
sanctuary.add(crow);
sanctuary.add(sparrow);
sanctuary.add(ostrich);
sanctuary.add(penguin);
System.
out.
println("=== all birds eat + sing ==="); for (Bird bird : sanctuary) {
bird.describe();
bird.eat();
bird.sing();
}
System.
out.
println("=== only Flyable birds fly ==="); List<Flyable> flyers = new ArrayList<Flyable>();
flyers.add(pigeon);
flyers.add(crow);
flyers.add(sparrow);
for (Flyable flyer : flyers) {
flyer.fly();
}
System.
out.
println("Crow and Sparrow share CrowSparrowFlyingBehavior"); System.
out.
println("Pigeon uses PigeonFlyingBehavior"); System.
out.
println("Ostrich and Penguin are Birds, not Flyable"); }
}
LyoKICogRGVzaWduIGEgQmlyZAogKgogKiBQcm9ibGVtCiAqICAgTW9kZWwgUGlnZW9uLCBDcm93LCBTcGFycm93LCBPc3RyaWNoLCBQZW5ndWluLgogKiAgIFBlbmd1aW4gYW5kIE9zdHJpY2ggY2Fubm90IGZseS4KICogICBDcm93IGFuZCBTcGFycm93IGZseSB0aGUgc2FtZSB3YXkuIFBpZ2VvbiBmbGllcyBkaWZmZXJlbnRseS4KICogICBFdmVyeSBiaXJkIGVhdHMgYW5kIHNpbmdzIHRoZSBzYW1lIHdheS4KICoKICogVGhlc2UgYXJlIGRpZmZlcmVudCB3YXlzIHBlb3BsZSBmaXJzdCBkZXNpZ24gdGhpcy4gTm90IGFsbCBvZiB0aGVtIHdvcmsuCiAqCiAqICAgMS4gT25lIEJpcmQgY2xhc3MgKyBpZiAoc3BhcnJvdykgLyBlbHNlIGlmIChwZW5ndWluKSBpbiBmbHkoKQogKiAgICAgIEJyZWFrcyBTUlAgYW5kIE9DUC4gVW5yZWFkYWJsZSBhdCAyMCBzcGVjaWVzLiBUZXN0cyBwaWxlIGludG8KICogICAgICBvbmUgZmlsZS4gVHdvIHBlb3BsZSBjb2xsaWRlIG9uIHRoZSBzYW1lIGNsYXNzLgogKgogKiAgIDIuIEFic3RyYWN0IEJpcmQgd2l0aCBmbHkoKSBvbiB0aGUgcGFyZW50CiAqICAgICAgUGVuZ3VpbiB0aGVuICJpbXBsZW1lbnRzIiBmbHkgd2l0aCBhbiBlbXB0eSBib2R5LCBhIGxvZywgb3IKICogICAgICBhbiBleGNlcHRpb24uIENhbGxlcnMgc3RpbGwgdGhpbmsgZXZlcnkgQmlyZCBjYW4gZmx5LiBCcmVha3MgTFNQLgogKgogKiAgIDMuIEZseWFibGVCaXJkIC8gTm9uRmx5YWJsZUJpcmQgZXh0cmEgcGFyZW50IGNsYXNzZXMKICogICAgICBGaW5lIGZvciBvbmUgYmVoYXZpb3IuIEFkZCBlYXQgdmFyaWFudHMgYW5kIHRoZSB0cmVlIGV4cGxvZGVzCiAqICAgICAgaW50byAyXm4gY2xhc3Nlcy4gRmx5aW5nIGFuZCBlYXRpbmcgYXJlIGJlaGF2aW9ycywgbm90IGtpbmRzIG9mIGJpcmQuCiAqCiAqICAgNC4gVGhlIGRlc2lnbiBpbiB0aGlzIGZpbGUgKHRoZSBvbmUgdGhhdCB3b3JrcykKICogICAgICBCaXJkIGhvbGRzIGlkZW50aXR5ICsgZWF0L3NpbmcuIE5vIGZseSgpIG9uIEJpcmQuCiAqICAgICAgT25seSBmbHllcnMgaW1wbGVtZW50IEZseWFibGUgKElTUCArIExTUCkuCiAqICAgICAgRmx5aW5nIHN0eWxlIGlzIGEgc2VwYXJhdGUgY2xhc3MsIGluamVjdGVkIGluIHRoZSBjb25zdHJ1Y3RvcgogKiAgICAgIChTdHJhdGVneSArIERJUCArIERJKS4KICogICAgICBDcm93IGFuZCBTcGFycm93IHNoYXJlIENyb3dTcGFycm93Rmx5aW5nQmVoYXZpb3IuCiAqICAgICAgQSBuZXcgYmlyZCBpcyBhIG5ldyBjbGFzcy4gSWYgaXQgZmxpZXMgbGlrZSBDcm93LCByZXVzZSB0aGF0CiAqICAgICAgYmVoYXZpb3IuIERvIG5vdCBlZGl0IG9sZCBzcGVjaWVzIChPQ1ApLgogKgogKiBVc2FnZQogKiAgIExpc3Q8QmlyZD4gICAgIOKGkiBkZXNjcmliZSAvIGVhdCAvIHNpbmcgZm9yIGV2ZXJ5b25lCiAqICAgTGlzdDxGbHlhYmxlPiAg4oaSIGZseSgpIHdpdGggbm8gaW5zdGFuY2VvZiBhbmQgbm8gdHJ5L2NhdGNoCiAqLwoKaW1wb3J0IGphdmEudXRpbC5BcnJheUxpc3Q7CmltcG9ydCBqYXZhLnV0aWwuTGlzdDsKCi8qIFNtYWxsIGludGVyZmFjZXMgc28gYSBiaXJkIG9ubHkgdGFrZXMgb24gYmVoYXZpb3JzIGl0IGFjdHVhbGx5IGhhcy4gKi8KCmludGVyZmFjZSBGbHlhYmxlIHsKICAgIHZvaWQgZmx5KCk7Cn0KCmludGVyZmFjZSBGbHlpbmdCZWhhdmlvciB7CiAgICB2b2lkIG1ha2VGbHkoKTsKfQoKaW50ZXJmYWNlIEVhdGluZ0JlaGF2aW9yIHsKICAgIHZvaWQgZWF0KCk7Cn0KCmludGVyZmFjZSBTaW5naW5nQmVoYXZpb3IgewogICAgdm9pZCBzaW5nKCk7Cn0KCi8qIEZseWluZyBzdHlsZXMgc2l0IGluIHRoZWlyIG93biBjbGFzc2VzIHNvIGJpcmRzIHN0YXkgc21hbGwuICovCgpjbGFzcyBDcm93U3BhcnJvd0ZseWluZ0JlaGF2aW9yIGltcGxlbWVudHMgRmx5aW5nQmVoYXZpb3IgewogICAgQE92ZXJyaWRlCiAgICBwdWJsaWMgdm9pZCBtYWtlRmx5KCkgewogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiICBmbHlpbmcgd2l0aCBzaG9ydCByYXBpZCB3aW5nIGZsYXBzIik7CiAgICB9Cn0KCmNsYXNzIFBpZ2VvbkZseWluZ0JlaGF2aW9yIGltcGxlbWVudHMgRmx5aW5nQmVoYXZpb3IgewogICAgQE92ZXJyaWRlCiAgICBwdWJsaWMgdm9pZCBtYWtlRmx5KCkgewogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiICBmbHlpbmcgaW4gYSBzdGVhZHkgZ2xpZGUgd2l0aCBvY2Nhc2lvbmFsIGZsYXBzIik7CiAgICB9Cn0KCmNsYXNzIERlZmF1bHRFYXRpbmdCZWhhdmlvciBpbXBsZW1lbnRzIEVhdGluZ0JlaGF2aW9yIHsKICAgIEBPdmVycmlkZQogICAgcHVibGljIHZvaWQgZWF0KCkgewogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiICBwZWNraW5nIGZvb2QiKTsKICAgIH0KfQoKY2xhc3MgRGVmYXVsdFNpbmdpbmdCZWhhdmlvciBpbXBsZW1lbnRzIFNpbmdpbmdCZWhhdmlvciB7CiAgICBAT3ZlcnJpZGUKICAgIHB1YmxpYyB2b2lkIHNpbmcoKSB7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCIgIHNpbmdpbmciKTsKICAgIH0KfQoKLyoKICogU2hhcmVkIG5hbWUgLyBjb2xvciAvIHNpemUgLyB3ZWlnaHQsIHBsdXMgZWF0IGFuZCBzaW5nLgogKiBmbHkoKSBpcyBub3QgaGVyZSDigJQgUGVuZ3VpbiBhbmQgT3N0cmljaCB3b3VsZCBvdGhlcndpc2UgaGF2ZSB0byBmYWtlIGl0LgogKi8KYWJzdHJhY3QgY2xhc3MgQmlyZCB7CiAgICBwcml2YXRlIGZpbmFsIFN0cmluZyBuYW1lOwogICAgcHJpdmF0ZSBmaW5hbCBTdHJpbmcgY29sb3I7CiAgICBwcml2YXRlIGZpbmFsIFN0cmluZyBzaXplOwogICAgcHJpdmF0ZSBmaW5hbCBkb3VibGUgd2VpZ2h0S2c7CiAgICBwcml2YXRlIGZpbmFsIEVhdGluZ0JlaGF2aW9yIGVhdGluZzsKICAgIHByaXZhdGUgZmluYWwgU2luZ2luZ0JlaGF2aW9yIHNpbmdpbmc7CgogICAgcHJvdGVjdGVkIEJpcmQoU3RyaW5nIG5hbWUsIFN0cmluZyBjb2xvciwgU3RyaW5nIHNpemUsIGRvdWJsZSB3ZWlnaHRLZywKICAgICAgICAgICAgICAgICAgIEVhdGluZ0JlaGF2aW9yIGVhdGluZywgU2luZ2luZ0JlaGF2aW9yIHNpbmdpbmcpIHsKICAgICAgICB0aGlzLm5hbWUgPSBuYW1lOwogICAgICAgIHRoaXMuY29sb3IgPSBjb2xvcjsKICAgICAgICB0aGlzLnNpemUgPSBzaXplOwogICAgICAgIHRoaXMud2VpZ2h0S2cgPSB3ZWlnaHRLZzsKICAgICAgICB0aGlzLmVhdGluZyA9IGVhdGluZzsKICAgICAgICB0aGlzLnNpbmdpbmcgPSBzaW5naW5nOwogICAgfQoKICAgIHB1YmxpYyBTdHJpbmcgZ2V0TmFtZSgpIHsgcmV0dXJuIG5hbWU7IH0KCiAgICBwdWJsaWMgdm9pZCBlYXQoKSB7IGVhdGluZy5lYXQoKTsgfQogICAgcHVibGljIHZvaWQgc2luZygpIHsgc2luZ2luZy5zaW5nKCk7IH0KCiAgICBwdWJsaWMgdm9pZCBkZXNjcmliZSgpIHsKICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4obmFtZSArICIgWyIgKyBjb2xvciArICIsICIgKyBzaXplICsgIiwgIiArIHdlaWdodEtnICsgImtnXSIpOwogICAgfQp9CgovKiBPbmx5IHNwZWNpZXMgdGhhdCBmbHkgaW1wbGVtZW50IEZseWFibGUuICovCgpjbGFzcyBQaWdlb24gZXh0ZW5kcyBCaXJkIGltcGxlbWVudHMgRmx5YWJsZSB7CiAgICBwcml2YXRlIGZpbmFsIEZseWluZ0JlaGF2aW9yIGZseWluZzsKCiAgICBwdWJsaWMgUGlnZW9uKFN0cmluZyBjb2xvciwgU3RyaW5nIHNpemUsIGRvdWJsZSB3ZWlnaHRLZywKICAgICAgICAgICAgICAgICAgRWF0aW5nQmVoYXZpb3IgZWF0aW5nLCBTaW5naW5nQmVoYXZpb3Igc2luZ2luZywKICAgICAgICAgICAgICAgICAgRmx5aW5nQmVoYXZpb3IgZmx5aW5nKSB7CiAgICAgICAgc3VwZXIoIlBpZ2VvbiIsIGNvbG9yLCBzaXplLCB3ZWlnaHRLZywgZWF0aW5nLCBzaW5naW5nKTsKICAgICAgICB0aGlzLmZseWluZyA9IGZseWluZzsKICAgIH0KCiAgICBAT3ZlcnJpZGUKICAgIHB1YmxpYyB2b2lkIGZseSgpIHsKICAgICAgICBTeXN0ZW0ub3V0LnByaW50KGdldE5hbWUoKSk7CiAgICAgICAgZmx5aW5nLm1ha2VGbHkoKTsKICAgIH0KfQoKY2xhc3MgQ3JvdyBleHRlbmRzIEJpcmQgaW1wbGVtZW50cyBGbHlhYmxlIHsKICAgIHByaXZhdGUgZmluYWwgRmx5aW5nQmVoYXZpb3IgZmx5aW5nOwoKICAgIHB1YmxpYyBDcm93KFN0cmluZyBjb2xvciwgU3RyaW5nIHNpemUsIGRvdWJsZSB3ZWlnaHRLZywKICAgICAgICAgICAgICAgIEVhdGluZ0JlaGF2aW9yIGVhdGluZywgU2luZ2luZ0JlaGF2aW9yIHNpbmdpbmcsCiAgICAgICAgICAgICAgICBGbHlpbmdCZWhhdmlvciBmbHlpbmcpIHsKICAgICAgICBzdXBlcigiQ3JvdyIsIGNvbG9yLCBzaXplLCB3ZWlnaHRLZywgZWF0aW5nLCBzaW5naW5nKTsKICAgICAgICB0aGlzLmZseWluZyA9IGZseWluZzsKICAgIH0KCiAgICBAT3ZlcnJpZGUKICAgIHB1YmxpYyB2b2lkIGZseSgpIHsKICAgICAgICBTeXN0ZW0ub3V0LnByaW50KGdldE5hbWUoKSk7CiAgICAgICAgZmx5aW5nLm1ha2VGbHkoKTsKICAgIH0KfQoKY2xhc3MgU3BhcnJvdyBleHRlbmRzIEJpcmQgaW1wbGVtZW50cyBGbHlhYmxlIHsKICAgIHByaXZhdGUgZmluYWwgRmx5aW5nQmVoYXZpb3IgZmx5aW5nOwoKICAgIHB1YmxpYyBTcGFycm93KFN0cmluZyBjb2xvciwgU3RyaW5nIHNpemUsIGRvdWJsZSB3ZWlnaHRLZywKICAgICAgICAgICAgICAgICAgIEVhdGluZ0JlaGF2aW9yIGVhdGluZywgU2luZ2luZ0JlaGF2aW9yIHNpbmdpbmcsCiAgICAgICAgICAgICAgICAgICBGbHlpbmdCZWhhdmlvciBmbHlpbmcpIHsKICAgICAgICBzdXBlcigiU3BhcnJvdyIsIGNvbG9yLCBzaXplLCB3ZWlnaHRLZywgZWF0aW5nLCBzaW5naW5nKTsKICAgICAgICB0aGlzLmZseWluZyA9IGZseWluZzsKICAgIH0KCiAgICBAT3ZlcnJpZGUKICAgIHB1YmxpYyB2b2lkIGZseSgpIHsKICAgICAgICBTeXN0ZW0ub3V0LnByaW50KGdldE5hbWUoKSk7CiAgICAgICAgZmx5aW5nLm1ha2VGbHkoKTsKICAgIH0KfQoKY2xhc3MgT3N0cmljaCBleHRlbmRzIEJpcmQgewogICAgcHVibGljIE9zdHJpY2goU3RyaW5nIGNvbG9yLCBTdHJpbmcgc2l6ZSwgZG91YmxlIHdlaWdodEtnLAogICAgICAgICAgICAgICAgICAgRWF0aW5nQmVoYXZpb3IgZWF0aW5nLCBTaW5naW5nQmVoYXZpb3Igc2luZ2luZykgewogICAgICAgIHN1cGVyKCJPc3RyaWNoIiwgY29sb3IsIHNpemUsIHdlaWdodEtnLCBlYXRpbmcsIHNpbmdpbmcpOwogICAgfQp9CgpjbGFzcyBQZW5ndWluIGV4dGVuZHMgQmlyZCB7CiAgICBwdWJsaWMgUGVuZ3VpbihTdHJpbmcgY29sb3IsIFN0cmluZyBzaXplLCBkb3VibGUgd2VpZ2h0S2csCiAgICAgICAgICAgICAgICAgICBFYXRpbmdCZWhhdmlvciBlYXRpbmcsIFNpbmdpbmdCZWhhdmlvciBzaW5naW5nKSB7CiAgICAgICAgc3VwZXIoIlBlbmd1aW4iLCBjb2xvciwgc2l6ZSwgd2VpZ2h0S2csIGVhdGluZywgc2luZ2luZyk7CiAgICB9Cn0KCi8qIE1haW4gY3JlYXRlcyB0aGUgYmVoYXZpb3JzIGFuZCBoYW5kcyB0aGVtIHRvIGVhY2ggYmlyZC4gKi8KcHVibGljIGNsYXNzIE1haW4gewogICAgcHVibGljIHN0YXRpYyB2b2lkIG1haW4oU3RyaW5nW10gYXJncykgewogICAgICAgIEVhdGluZ0JlaGF2aW9yIGVhdCA9IG5ldyBEZWZhdWx0RWF0aW5nQmVoYXZpb3IoKTsKICAgICAgICBTaW5naW5nQmVoYXZpb3Igc2luZyA9IG5ldyBEZWZhdWx0U2luZ2luZ0JlaGF2aW9yKCk7CiAgICAgICAgRmx5aW5nQmVoYXZpb3IgY3Jvd1NwYXJyb3dGbHkgPSBuZXcgQ3Jvd1NwYXJyb3dGbHlpbmdCZWhhdmlvcigpOwogICAgICAgIEZseWluZ0JlaGF2aW9yIHBpZ2VvbkZseSA9IG5ldyBQaWdlb25GbHlpbmdCZWhhdmlvcigpOwoKICAgICAgICBQaWdlb24gcGlnZW9uID0gbmV3IFBpZ2VvbigiZ3JleSIsICJtZWRpdW0iLCAwLjMsIGVhdCwgc2luZywgcGlnZW9uRmx5KTsKICAgICAgICBDcm93IGNyb3cgPSBuZXcgQ3JvdygiYmxhY2siLCAibWVkaXVtIiwgMC41LCBlYXQsIHNpbmcsIGNyb3dTcGFycm93Rmx5KTsKICAgICAgICBTcGFycm93IHNwYXJyb3cgPSBuZXcgU3BhcnJvdygiYnJvd24iLCAic21hbGwiLCAwLjAzLCBlYXQsIHNpbmcsIGNyb3dTcGFycm93Rmx5KTsKICAgICAgICBPc3RyaWNoIG9zdHJpY2ggPSBuZXcgT3N0cmljaCgiYnJvd24iLCAibGFyZ2UiLCAxMTAuMCwgZWF0LCBzaW5nKTsKICAgICAgICBQZW5ndWluIHBlbmd1aW4gPSBuZXcgUGVuZ3VpbigiYmxhY2std2hpdGUiLCAibWVkaXVtIiwgMTUuMCwgZWF0LCBzaW5nKTsKCiAgICAgICAgTGlzdDxCaXJkPiBzYW5jdHVhcnkgPSBuZXcgQXJyYXlMaXN0PEJpcmQ+KCk7CiAgICAgICAgc2FuY3R1YXJ5LmFkZChwaWdlb24pOwogICAgICAgIHNhbmN0dWFyeS5hZGQoY3Jvdyk7CiAgICAgICAgc2FuY3R1YXJ5LmFkZChzcGFycm93KTsKICAgICAgICBzYW5jdHVhcnkuYWRkKG9zdHJpY2gpOwogICAgICAgIHNhbmN0dWFyeS5hZGQocGVuZ3Vpbik7CgogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiPT09IGFsbCBiaXJkcyBlYXQgKyBzaW5nID09PSIpOwogICAgICAgIGZvciAoQmlyZCBiaXJkIDogc2FuY3R1YXJ5KSB7CiAgICAgICAgICAgIGJpcmQuZGVzY3JpYmUoKTsKICAgICAgICAgICAgYmlyZC5lYXQoKTsKICAgICAgICAgICAgYmlyZC5zaW5nKCk7CiAgICAgICAgfQoKICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oKTsKICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oIj09PSBvbmx5IEZseWFibGUgYmlyZHMgZmx5ID09PSIpOwogICAgICAgIExpc3Q8Rmx5YWJsZT4gZmx5ZXJzID0gbmV3IEFycmF5TGlzdDxGbHlhYmxlPigpOwogICAgICAgIGZseWVycy5hZGQocGlnZW9uKTsKICAgICAgICBmbHllcnMuYWRkKGNyb3cpOwogICAgICAgIGZseWVycy5hZGQoc3BhcnJvdyk7CiAgICAgICAgZm9yIChGbHlhYmxlIGZseWVyIDogZmx5ZXJzKSB7CiAgICAgICAgICAgIGZseWVyLmZseSgpOwogICAgICAgIH0KCiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCk7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJDcm93IGFuZCBTcGFycm93IHNoYXJlIENyb3dTcGFycm93Rmx5aW5nQmVoYXZpb3IiKTsKICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oIlBpZ2VvbiB1c2VzIFBpZ2VvbkZseWluZ0JlaGF2aW9yIik7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJPc3RyaWNoIGFuZCBQZW5ndWluIGFyZSBCaXJkcywgbm90IEZseWFibGUiKTsKICAgIH0KfQ==