# IT2202 - 03 Laboratory Exercise 1: Pygame and OpenGL
# Text-based simulation for online compilers (OneCompiler compatible)
# This version demonstrates the cube structure without graphics libraries
import math
import time
class Cube3D:
"""
Simulates a 3D cube with rotation capabilities using text output
"""
def __init__(self):
# Step 14: Define the 8 vertices of the cube (same as lab manual)
self.vertices = [
[1, 1, 1], # Vertex 0: X=1, Y=1, Z=1
[1, 1, -1], # Vertex 1: X=1, Y=1, Z=-1
[1, -1, -1], # Vertex 2: X=1, Y=-1, Z=-1
[1, -1, 1], # Vertex 3: X=1, Y=-1, Z=1
[-1, 1, 1], # Vertex 4: X=-1, Y=1, Z=1
[-1, -1, -1], # Vertex 5: X=-1, Y=-1, Z=-1
[-1, -1, 1], # Vertex 6: X=-1, Y=-1, Z=1
[-1, 1, -1] # Vertex 7: X=-1, Y=1, Z=-1
]
# Step 15: Define the edges connecting pairs of vertices
self.edges = [
(0, 1), # Edge A: Vertex 0 to Vertex 1
(1, 2), # Edge B: Vertex 1 to Vertex 2
(2, 3), # Edge C: Vertex 2 to Vertex 3
(3, 0), # Edge D: Vertex 3 to Vertex 0
(4, 7), # Edge E: Vertex 4 to Vertex 7
(7, 5), # Edge F: Vertex 7 to Vertex 5
(5, 6), # Edge G: Vertex 5 to Vertex 6
(6, 4), # Edge H: Vertex 6 to Vertex 4
(3, 6), # Edge I: Vertex 3 to Vertex 6
(0, 4), # Edge J: Vertex 0 to Vertex 4
(2, 5), # Edge K: Vertex 2 to Vertex 5
(1, 7) # Edge L: Vertex 1 to Vertex 7
]
self.rotation_angle = 0
def rotate_vertex(self, vertex, angle_x, angle_y, angle_z):
"""
Step 16: Simulate glRotatef() - Rotate a vertex around x, y, z axes
"""
x, y, z = vertex
# Rotation around X-axis
cos_x, sin_x = math.cos(angle_x), math.sin(angle_x)
y_new = y * cos_x - z * sin_x
z_new = y * sin_x + z * cos_x
y, z = y_new, z_new
# Rotation around Y-axis
cos_y, sin_y = math.cos(angle_y), math.sin(angle_y)
x_new = x * cos_y + z * sin_y
z_new = -x * sin_y + z * cos_y
x, z = x_new, z_new
# Rotation around Z-axis
cos_z, sin_z = math.cos(angle_z), math.sin(angle_z)
x_new = x * cos_z - y * sin_z
y_new = x * sin_z + y * cos_z
x, y = x_new, y_new
return [x, y, z]
def get_rotated_vertices(self):
"""
Apply rotation to all vertices
"""
angle = math.radians(self.rotation_angle)
rotated = []
for vertex in self.vertices:
rotated_vertex = self.rotate_vertex(vertex, angle, angle, angle)
rotated.append(rotated_vertex)
return rotated
def display_cube_info(self):
"""
Display cube structure and current state
"""
print("\n" + "="*60)
print("IT2202 - Lab Exercise 1: 3D Wireframe Cube")
print("="*60)
# Display original vertices (as specified in lab manual)
print("\nOriginal Vertices (Lab Manual Table):")
print("Vertex | X | Y | Z ")
print("-------|----|----|----")
for i, vertex in enumerate(self.vertices):
print(" {} | {:2} | {:2} | {:2}".format(i, vertex[0], vertex[1], vertex[2]))
# Display edges
print("\nEdges (Connecting Vertex Pairs):")
edge_names = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L']
for i, (v1, v2) in enumerate(self.edges):
print("Edge {}: Vertex {} ↔ Vertex {}".format(edge_names[i], v1, v2))
# Display current rotation
rotated_vertices = self.get_rotated_vertices()
print("\nCurrent Rotation Angle: {}°".format(self.rotation_angle))
print("\nRotated Vertices (Current Frame):")
print("Vertex | X | Y | Z ")
print("-------|---------|---------|--------")
for i, vertex in enumerate(rotated_vertices):
print(" {} | {:7.3f} | {:7.3f} | {:7.3f}".format(i, vertex[0], vertex[1], vertex[2]))
def simple_projection(self, vertex):
"""
Simple 2D projection for text visualization
"""
x, y, z = vertex
# Simple orthographic projection (ignore z for 2D display)
screen_x = int(x * 10 + 20) # Scale and center
screen_y = int(-y * 5 + 10) # Scale, flip Y, and center
return screen_x, screen_y
def draw_ascii_cube(self):
"""
Draw a simple ASCII representation of the cube
"""
print("\nASCII Cube Projection (Top View):")
print("(Simulating pygame.display and OpenGL rendering)")
# Create a simple grid
grid = [[' ' for _ in range(40)] for _ in range(20)]
rotated_vertices = self.get_rotated_vertices()
# Mark vertices on the grid
for i, vertex in enumerate(rotated_vertices):
x, y = self.simple_projection(vertex)
if 0 <= x < 40 and 0 <= y < 20:
grid[y][x] = str(i)
# Draw the grid
for row in grid:
print(''.join(row))
print("\nNumbers 0-7 represent the cube vertices")
print("This simulates what you would see in the OpenGL window")
def simulate_pygame_loop():
"""
Step 11: Simulate the main pygame event loop
"""
cube = Cube3D()
print("Starting IT2202 Lab Exercise 1 Simulation...")
print("(This simulates pygame.init() and OpenGL setup)")
print("\nSimulating continuous rotation...")
print("In real OpenGL: glRotatef(1, 1, 1, 1) would rotate 1° around vector (1,1,1)")
print("\nPress Ctrl+C to stop the simulation")
try:
# Simulate the main loop (show 5 frames instead of infinite)
for frame in range(5):
print("\n{} FRAME {} {}".format("="*20, frame + 1, "="*20))
# Step 16: Simulate glRotatef(1, 1, 1, 1)
cube.rotation_angle += 15 # Increase by 15° each frame for visibility
# Step 11: Simulate glClear() and drawing
cube.display_cube_info()
cube.draw_ascii_cube()
# Step 11: Simulate pygame.time.wait(15)
if frame < 4: # Don't wait on last frame
print("\n[Simulating pygame.time.wait(15)...]")
time.sleep(1) # Reduced delay for demo
print("\n{}".format("="*60))
print("Simulation complete!")
print("In real OpenGL, this would show a smoothly rotating 3D wireframe cube")
print("{}".format("="*60))
except KeyboardInterrupt:
print("\nSimulation stopped by user")
print("(Simulates pygame.quit() when window is closed)")
def main():
"""
Main function demonstrating all lab concepts
"""
print("IT2202 - 03 Laboratory Exercise 1")
print("Pygame and OpenGL Simulation for Online Compilers")
print("="*60)
# Show what would normally require package installation
required_packages = ["pygame", "numpy", "PyOpenGL", "PyOpenGL_accelerate"]
print("Required packages (not available in online compilers): {}".format(', '.join(required_packages)))
print("Install locally with: py -m pip install {}".format(" ".join(required_packages)))
# Demonstrate the lab concepts
simulate_pygame_loop()
if __name__ == "__main__":
main()
IyBJVDIyMDIgLSAwMyBMYWJvcmF0b3J5IEV4ZXJjaXNlIDE6IFB5Z2FtZSBhbmQgT3BlbkdMCiMgVGV4dC1iYXNlZCBzaW11bGF0aW9uIGZvciBvbmxpbmUgY29tcGlsZXJzIChPbmVDb21waWxlciBjb21wYXRpYmxlKQojIFRoaXMgdmVyc2lvbiBkZW1vbnN0cmF0ZXMgdGhlIGN1YmUgc3RydWN0dXJlIHdpdGhvdXQgZ3JhcGhpY3MgbGlicmFyaWVzCiAKaW1wb3J0IG1hdGgKaW1wb3J0IHRpbWUKIApjbGFzcyBDdWJlM0Q6CiAgICAiIiIKICAgIFNpbXVsYXRlcyBhIDNEIGN1YmUgd2l0aCByb3RhdGlvbiBjYXBhYmlsaXRpZXMgdXNpbmcgdGV4dCBvdXRwdXQKICAgICIiIgogCiAgICBkZWYgX19pbml0X18oc2VsZik6CiAgICAgICAgIyBTdGVwIDE0OiBEZWZpbmUgdGhlIDggdmVydGljZXMgb2YgdGhlIGN1YmUgKHNhbWUgYXMgbGFiIG1hbnVhbCkKICAgICAgICBzZWxmLnZlcnRpY2VzID0gWwogICAgICAgICAgICBbMSwgMSwgMV0sICAgICAgIyBWZXJ0ZXggMDogWD0xLCBZPTEsIFo9MQogICAgICAgICAgICBbMSwgMSwgLTFdLCAgICAgIyBWZXJ0ZXggMTogWD0xLCBZPTEsIFo9LTEKICAgICAgICAgICAgWzEsIC0xLCAtMV0sICAgICMgVmVydGV4IDI6IFg9MSwgWT0tMSwgWj0tMQogICAgICAgICAgICBbMSwgLTEsIDFdLCAgICAgIyBWZXJ0ZXggMzogWD0xLCBZPS0xLCBaPTEKICAgICAgICAgICAgWy0xLCAxLCAxXSwgICAgICMgVmVydGV4IDQ6IFg9LTEsIFk9MSwgWj0xCiAgICAgICAgICAgIFstMSwgLTEsIC0xXSwgICAjIFZlcnRleCA1OiBYPS0xLCBZPS0xLCBaPS0xCiAgICAgICAgICAgIFstMSwgLTEsIDFdLCAgICAjIFZlcnRleCA2OiBYPS0xLCBZPS0xLCBaPTEKICAgICAgICAgICAgWy0xLCAxLCAtMV0gICAgICMgVmVydGV4IDc6IFg9LTEsIFk9MSwgWj0tMQogICAgICAgIF0KIAogICAgICAgICMgU3RlcCAxNTogRGVmaW5lIHRoZSBlZGdlcyBjb25uZWN0aW5nIHBhaXJzIG9mIHZlcnRpY2VzCiAgICAgICAgc2VsZi5lZGdlcyA9IFsKICAgICAgICAgICAgKDAsIDEpLCAgIyBFZGdlIEE6IFZlcnRleCAwIHRvIFZlcnRleCAxCiAgICAgICAgICAgICgxLCAyKSwgICMgRWRnZSBCOiBWZXJ0ZXggMSB0byBWZXJ0ZXggMgogICAgICAgICAgICAoMiwgMyksICAjIEVkZ2UgQzogVmVydGV4IDIgdG8gVmVydGV4IDMKICAgICAgICAgICAgKDMsIDApLCAgIyBFZGdlIEQ6IFZlcnRleCAzIHRvIFZlcnRleCAwCiAgICAgICAgICAgICg0LCA3KSwgICMgRWRnZSBFOiBWZXJ0ZXggNCB0byBWZXJ0ZXggNwogICAgICAgICAgICAoNywgNSksICAjIEVkZ2UgRjogVmVydGV4IDcgdG8gVmVydGV4IDUKICAgICAgICAgICAgKDUsIDYpLCAgIyBFZGdlIEc6IFZlcnRleCA1IHRvIFZlcnRleCA2CiAgICAgICAgICAgICg2LCA0KSwgICMgRWRnZSBIOiBWZXJ0ZXggNiB0byBWZXJ0ZXggNAogICAgICAgICAgICAoMywgNiksICAjIEVkZ2UgSTogVmVydGV4IDMgdG8gVmVydGV4IDYKICAgICAgICAgICAgKDAsIDQpLCAgIyBFZGdlIEo6IFZlcnRleCAwIHRvIFZlcnRleCA0CiAgICAgICAgICAgICgyLCA1KSwgICMgRWRnZSBLOiBWZXJ0ZXggMiB0byBWZXJ0ZXggNQogICAgICAgICAgICAoMSwgNykgICAjIEVkZ2UgTDogVmVydGV4IDEgdG8gVmVydGV4IDcKICAgICAgICBdCiAKICAgICAgICBzZWxmLnJvdGF0aW9uX2FuZ2xlID0gMAogCiAgICBkZWYgcm90YXRlX3ZlcnRleChzZWxmLCB2ZXJ0ZXgsIGFuZ2xlX3gsIGFuZ2xlX3ksIGFuZ2xlX3opOgogICAgICAgICIiIgogICAgICAgIFN0ZXAgMTY6IFNpbXVsYXRlIGdsUm90YXRlZigpIC0gUm90YXRlIGEgdmVydGV4IGFyb3VuZCB4LCB5LCB6IGF4ZXMKICAgICAgICAiIiIKICAgICAgICB4LCB5LCB6ID0gdmVydGV4CiAKICAgICAgICAjIFJvdGF0aW9uIGFyb3VuZCBYLWF4aXMKICAgICAgICBjb3NfeCwgc2luX3ggPSBtYXRoLmNvcyhhbmdsZV94KSwgbWF0aC5zaW4oYW5nbGVfeCkKICAgICAgICB5X25ldyA9IHkgKiBjb3NfeCAtIHogKiBzaW5feAogICAgICAgIHpfbmV3ID0geSAqIHNpbl94ICsgeiAqIGNvc194CiAgICAgICAgeSwgeiA9IHlfbmV3LCB6X25ldwogCiAgICAgICAgIyBSb3RhdGlvbiBhcm91bmQgWS1heGlzCiAgICAgICAgY29zX3ksIHNpbl95ID0gbWF0aC5jb3MoYW5nbGVfeSksIG1hdGguc2luKGFuZ2xlX3kpCiAgICAgICAgeF9uZXcgPSB4ICogY29zX3kgKyB6ICogc2luX3kKICAgICAgICB6X25ldyA9IC14ICogc2luX3kgKyB6ICogY29zX3kKICAgICAgICB4LCB6ID0geF9uZXcsIHpfbmV3CiAKICAgICAgICAjIFJvdGF0aW9uIGFyb3VuZCBaLWF4aXMKICAgICAgICBjb3Nfeiwgc2luX3ogPSBtYXRoLmNvcyhhbmdsZV96KSwgbWF0aC5zaW4oYW5nbGVfeikKICAgICAgICB4X25ldyA9IHggKiBjb3NfeiAtIHkgKiBzaW5fegogICAgICAgIHlfbmV3ID0geCAqIHNpbl96ICsgeSAqIGNvc196CiAgICAgICAgeCwgeSA9IHhfbmV3LCB5X25ldwogCiAgICAgICAgcmV0dXJuIFt4LCB5LCB6XQogCiAgICBkZWYgZ2V0X3JvdGF0ZWRfdmVydGljZXMoc2VsZik6CiAgICAgICAgIiIiCiAgICAgICAgQXBwbHkgcm90YXRpb24gdG8gYWxsIHZlcnRpY2VzCiAgICAgICAgIiIiCiAgICAgICAgYW5nbGUgPSBtYXRoLnJhZGlhbnMoc2VsZi5yb3RhdGlvbl9hbmdsZSkKICAgICAgICByb3RhdGVkID0gW10KIAogICAgICAgIGZvciB2ZXJ0ZXggaW4gc2VsZi52ZXJ0aWNlczoKICAgICAgICAgICAgcm90YXRlZF92ZXJ0ZXggPSBzZWxmLnJvdGF0ZV92ZXJ0ZXgodmVydGV4LCBhbmdsZSwgYW5nbGUsIGFuZ2xlKQogICAgICAgICAgICByb3RhdGVkLmFwcGVuZChyb3RhdGVkX3ZlcnRleCkKIAogICAgICAgIHJldHVybiByb3RhdGVkCiAKICAgIGRlZiBkaXNwbGF5X2N1YmVfaW5mbyhzZWxmKToKICAgICAgICAiIiIKICAgICAgICBEaXNwbGF5IGN1YmUgc3RydWN0dXJlIGFuZCBjdXJyZW50IHN0YXRlCiAgICAgICAgIiIiCiAgICAgICAgcHJpbnQoIlxuIiArICI9Iio2MCkKICAgICAgICBwcmludCgiSVQyMjAyIC0gTGFiIEV4ZXJjaXNlIDE6IDNEIFdpcmVmcmFtZSBDdWJlIikKICAgICAgICBwcmludCgiPSIqNjApCiAKICAgICAgICAjIERpc3BsYXkgb3JpZ2luYWwgdmVydGljZXMgKGFzIHNwZWNpZmllZCBpbiBsYWIgbWFudWFsKQogICAgICAgIHByaW50KCJcbk9yaWdpbmFsIFZlcnRpY2VzIChMYWIgTWFudWFsIFRhYmxlKToiKQogICAgICAgIHByaW50KCJWZXJ0ZXggfCBYICB8IFkgIHwgWiAiKQogICAgICAgIHByaW50KCItLS0tLS0tfC0tLS18LS0tLXwtLS0tIikKICAgICAgICBmb3IgaSwgdmVydGV4IGluIGVudW1lcmF0ZShzZWxmLnZlcnRpY2VzKToKICAgICAgICAgICAgcHJpbnQoIiAgIHt9ICAgfCB7OjJ9IHwgezoyfSB8IHs6Mn0iLmZvcm1hdChpLCB2ZXJ0ZXhbMF0sIHZlcnRleFsxXSwgdmVydGV4WzJdKSkKIAogICAgICAgICMgRGlzcGxheSBlZGdlcwogICAgICAgIHByaW50KCJcbkVkZ2VzIChDb25uZWN0aW5nIFZlcnRleCBQYWlycyk6IikKICAgICAgICBlZGdlX25hbWVzID0gWydBJywgJ0InLCAnQycsICdEJywgJ0UnLCAnRicsICdHJywgJ0gnLCAnSScsICdKJywgJ0snLCAnTCddCiAgICAgICAgZm9yIGksICh2MSwgdjIpIGluIGVudW1lcmF0ZShzZWxmLmVkZ2VzKToKICAgICAgICAgICAgcHJpbnQoIkVkZ2Uge306IFZlcnRleCB7fSDihpQgVmVydGV4IHt9Ii5mb3JtYXQoZWRnZV9uYW1lc1tpXSwgdjEsIHYyKSkKIAogICAgICAgICMgRGlzcGxheSBjdXJyZW50IHJvdGF0aW9uCiAgICAgICAgcm90YXRlZF92ZXJ0aWNlcyA9IHNlbGYuZ2V0X3JvdGF0ZWRfdmVydGljZXMoKQogICAgICAgIHByaW50KCJcbkN1cnJlbnQgUm90YXRpb24gQW5nbGU6IHt9wrAiLmZvcm1hdChzZWxmLnJvdGF0aW9uX2FuZ2xlKSkKICAgICAgICBwcmludCgiXG5Sb3RhdGVkIFZlcnRpY2VzIChDdXJyZW50IEZyYW1lKToiKQogICAgICAgIHByaW50KCJWZXJ0ZXggfCAgICBYICAgIHwgICAgWSAgICB8ICAgIFogICAiKQogICAgICAgIHByaW50KCItLS0tLS0tfC0tLS0tLS0tLXwtLS0tLS0tLS18LS0tLS0tLS0iKQogICAgICAgIGZvciBpLCB2ZXJ0ZXggaW4gZW51bWVyYXRlKHJvdGF0ZWRfdmVydGljZXMpOgogICAgICAgICAgICBwcmludCgiICAge30gICB8IHs6Ny4zZn0gfCB7OjcuM2Z9IHwgezo3LjNmfSIuZm9ybWF0KGksIHZlcnRleFswXSwgdmVydGV4WzFdLCB2ZXJ0ZXhbMl0pKQogCiAgICBkZWYgc2ltcGxlX3Byb2plY3Rpb24oc2VsZiwgdmVydGV4KToKICAgICAgICAiIiIKICAgICAgICBTaW1wbGUgMkQgcHJvamVjdGlvbiBmb3IgdGV4dCB2aXN1YWxpemF0aW9uCiAgICAgICAgIiIiCiAgICAgICAgeCwgeSwgeiA9IHZlcnRleAogICAgICAgICMgU2ltcGxlIG9ydGhvZ3JhcGhpYyBwcm9qZWN0aW9uIChpZ25vcmUgeiBmb3IgMkQgZGlzcGxheSkKICAgICAgICBzY3JlZW5feCA9IGludCh4ICogMTAgKyAyMCkgICMgU2NhbGUgYW5kIGNlbnRlcgogICAgICAgIHNjcmVlbl95ID0gaW50KC15ICogNSArIDEwKSAgICMgU2NhbGUsIGZsaXAgWSwgYW5kIGNlbnRlcgogICAgICAgIHJldHVybiBzY3JlZW5feCwgc2NyZWVuX3kKIAogICAgZGVmIGRyYXdfYXNjaWlfY3ViZShzZWxmKToKICAgICAgICAiIiIKICAgICAgICBEcmF3IGEgc2ltcGxlIEFTQ0lJIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjdWJlCiAgICAgICAgIiIiCiAgICAgICAgcHJpbnQoIlxuQVNDSUkgQ3ViZSBQcm9qZWN0aW9uIChUb3AgVmlldyk6IikKICAgICAgICBwcmludCgiKFNpbXVsYXRpbmcgcHlnYW1lLmRpc3BsYXkgYW5kIE9wZW5HTCByZW5kZXJpbmcpIikKIAogICAgICAgICMgQ3JlYXRlIGEgc2ltcGxlIGdyaWQKICAgICAgICBncmlkID0gW1snICcgZm9yIF8gaW4gcmFuZ2UoNDApXSBmb3IgXyBpbiByYW5nZSgyMCldCiAKICAgICAgICByb3RhdGVkX3ZlcnRpY2VzID0gc2VsZi5nZXRfcm90YXRlZF92ZXJ0aWNlcygpCiAKICAgICAgICAjIE1hcmsgdmVydGljZXMgb24gdGhlIGdyaWQKICAgICAgICBmb3IgaSwgdmVydGV4IGluIGVudW1lcmF0ZShyb3RhdGVkX3ZlcnRpY2VzKToKICAgICAgICAgICAgeCwgeSA9IHNlbGYuc2ltcGxlX3Byb2plY3Rpb24odmVydGV4KQogICAgICAgICAgICBpZiAwIDw9IHggPCA0MCBhbmQgMCA8PSB5IDwgMjA6CiAgICAgICAgICAgICAgICBncmlkW3ldW3hdID0gc3RyKGkpCiAKICAgICAgICAjIERyYXcgdGhlIGdyaWQKICAgICAgICBmb3Igcm93IGluIGdyaWQ6CiAgICAgICAgICAgIHByaW50KCcnLmpvaW4ocm93KSkKIAogICAgICAgIHByaW50KCJcbk51bWJlcnMgMC03IHJlcHJlc2VudCB0aGUgY3ViZSB2ZXJ0aWNlcyIpCiAgICAgICAgcHJpbnQoIlRoaXMgc2ltdWxhdGVzIHdoYXQgeW91IHdvdWxkIHNlZSBpbiB0aGUgT3BlbkdMIHdpbmRvdyIpCiAKZGVmIHNpbXVsYXRlX3B5Z2FtZV9sb29wKCk6CiAgICAiIiIKICAgIFN0ZXAgMTE6IFNpbXVsYXRlIHRoZSBtYWluIHB5Z2FtZSBldmVudCBsb29wCiAgICAiIiIKICAgIGN1YmUgPSBDdWJlM0QoKQogCiAgICBwcmludCgiU3RhcnRpbmcgSVQyMjAyIExhYiBFeGVyY2lzZSAxIFNpbXVsYXRpb24uLi4iKQogICAgcHJpbnQoIihUaGlzIHNpbXVsYXRlcyBweWdhbWUuaW5pdCgpIGFuZCBPcGVuR0wgc2V0dXApIikKICAgIHByaW50KCJcblNpbXVsYXRpbmcgY29udGludW91cyByb3RhdGlvbi4uLiIpCiAgICBwcmludCgiSW4gcmVhbCBPcGVuR0w6IGdsUm90YXRlZigxLCAxLCAxLCAxKSB3b3VsZCByb3RhdGUgMcKwIGFyb3VuZCB2ZWN0b3IgKDEsMSwxKSIpCiAgICBwcmludCgiXG5QcmVzcyBDdHJsK0MgdG8gc3RvcCB0aGUgc2ltdWxhdGlvbiIpCiAKICAgIHRyeToKICAgICAgICAjIFNpbXVsYXRlIHRoZSBtYWluIGxvb3AgKHNob3cgNSBmcmFtZXMgaW5zdGVhZCBvZiBpbmZpbml0ZSkKICAgICAgICBmb3IgZnJhbWUgaW4gcmFuZ2UoNSk6CiAgICAgICAgICAgIHByaW50KCJcbnt9IEZSQU1FIHt9IHt9Ii5mb3JtYXQoIj0iKjIwLCBmcmFtZSArIDEsICI9IioyMCkpCiAKICAgICAgICAgICAgIyBTdGVwIDE2OiBTaW11bGF0ZSBnbFJvdGF0ZWYoMSwgMSwgMSwgMSkKICAgICAgICAgICAgY3ViZS5yb3RhdGlvbl9hbmdsZSArPSAxNSAgIyBJbmNyZWFzZSBieSAxNcKwIGVhY2ggZnJhbWUgZm9yIHZpc2liaWxpdHkKIAogICAgICAgICAgICAjIFN0ZXAgMTE6IFNpbXVsYXRlIGdsQ2xlYXIoKSBhbmQgZHJhd2luZwogICAgICAgICAgICBjdWJlLmRpc3BsYXlfY3ViZV9pbmZvKCkKICAgICAgICAgICAgY3ViZS5kcmF3X2FzY2lpX2N1YmUoKQogCiAgICAgICAgICAgICMgU3RlcCAxMTogU2ltdWxhdGUgcHlnYW1lLnRpbWUud2FpdCgxNSkKICAgICAgICAgICAgaWYgZnJhbWUgPCA0OiAgIyBEb24ndCB3YWl0IG9uIGxhc3QgZnJhbWUKICAgICAgICAgICAgICAgIHByaW50KCJcbltTaW11bGF0aW5nIHB5Z2FtZS50aW1lLndhaXQoMTUpLi4uXSIpCiAgICAgICAgICAgICAgICB0aW1lLnNsZWVwKDEpICAjIFJlZHVjZWQgZGVsYXkgZm9yIGRlbW8KIAogICAgICAgIHByaW50KCJcbnt9Ii5mb3JtYXQoIj0iKjYwKSkKICAgICAgICBwcmludCgiU2ltdWxhdGlvbiBjb21wbGV0ZSEiKQogICAgICAgIHByaW50KCJJbiByZWFsIE9wZW5HTCwgdGhpcyB3b3VsZCBzaG93IGEgc21vb3RobHkgcm90YXRpbmcgM0Qgd2lyZWZyYW1lIGN1YmUiKQogICAgICAgIHByaW50KCJ7fSIuZm9ybWF0KCI9Iio2MCkpCiAKICAgIGV4Y2VwdCBLZXlib2FyZEludGVycnVwdDoKICAgICAgICBwcmludCgiXG5TaW11bGF0aW9uIHN0b3BwZWQgYnkgdXNlciIpCiAgICAgICAgcHJpbnQoIihTaW11bGF0ZXMgcHlnYW1lLnF1aXQoKSB3aGVuIHdpbmRvdyBpcyBjbG9zZWQpIikKIApkZWYgbWFpbigpOgogICAgIiIiCiAgICBNYWluIGZ1bmN0aW9uIGRlbW9uc3RyYXRpbmcgYWxsIGxhYiBjb25jZXB0cwogICAgIiIiCiAgICBwcmludCgiSVQyMjAyIC0gMDMgTGFib3JhdG9yeSBFeGVyY2lzZSAxIikKICAgIHByaW50KCJQeWdhbWUgYW5kIE9wZW5HTCBTaW11bGF0aW9uIGZvciBPbmxpbmUgQ29tcGlsZXJzIikKICAgIHByaW50KCI9Iio2MCkKIAogICAgIyBTaG93IHdoYXQgd291bGQgbm9ybWFsbHkgcmVxdWlyZSBwYWNrYWdlIGluc3RhbGxhdGlvbgogICAgcmVxdWlyZWRfcGFja2FnZXMgPSBbInB5Z2FtZSIsICJudW1weSIsICJQeU9wZW5HTCIsICJQeU9wZW5HTF9hY2NlbGVyYXRlIl0KICAgIHByaW50KCJSZXF1aXJlZCBwYWNrYWdlcyAobm90IGF2YWlsYWJsZSBpbiBvbmxpbmUgY29tcGlsZXJzKToge30iLmZvcm1hdCgnLCAnLmpvaW4ocmVxdWlyZWRfcGFja2FnZXMpKSkKICAgIHByaW50KCJJbnN0YWxsIGxvY2FsbHkgd2l0aDogcHkgLW0gcGlwIGluc3RhbGwge30iLmZvcm1hdCgiICIuam9pbihyZXF1aXJlZF9wYWNrYWdlcykpKQogCiAgICAjIERlbW9uc3RyYXRlIHRoZSBsYWIgY29uY2VwdHMKICAgIHNpbXVsYXRlX3B5Z2FtZV9sb29wKCkKIAppZiBfX25hbWVfXyA9PSAiX19tYWluX18iOgogICAgbWFpbigp