<commit_before># Copyright (c) 2001, Stanford University
# All rights reserved.
#
# See the file LICENSE.txt for information on redistributing this software.
#
# Authors:
#   <NAME>

""" lightning2_template.py
    Template for setting up Lightning-2 (tile-reassembly) configurations.
"""


# Known issues:
# 1. Tiles must all be same size
# 2. Tiles cannot overlap
# 3. No support for the Lightning-2 border pixel / reassembly codes



import string, cPickle, os.path, re, sys
from wxPython.wx import *
import crtypes, crutils, intdialog, hostdialog, configio
sys.path.append( "../server" )
import tilelayout
import templatebase
import textdialog
sys.path.append("../server")
import crconfig


class LightningParameters:
	"""This class describes the parameters of a Lightning-2 configuration.
	When we begin editing a Lightning-2 config we init these values from
	the mothership (number of servers, etc) and/or the initial create-
	lightning-2 dialog.
	When we finish editing, we update the mothership config."""
	def __init__(self, rows=1, cols=2):
		assert rows >= 1
		assert cols >= 1
		self.NumServers = 4
		self.ServerHosts = ["localhost"]
		self.ServerPattern = ("localhost", 1)
		self.Columns = cols
		self.Rows = rows
		self.TileWidth = 256
		self.TileHeight = 256
		self.ScreenWidth = 1280  # server screen
		self.ScreenHeight = 1024
		self.Layout = 0
		self.DynamicSize = 0   # 0, 1, or 2
		self.Reassembly = 0  # 0, 1, o

	def Clone(self):
		"""Return a clone of this object."""
		# We're not using the copy.copy() function since it's flakey
		p = LightningParameters()
		p.NumServers = self.NumServers
		p.ServerHosts = self.ServerHosts[:]
		p.ServerPattern = self.ServerPattern
		p.Columns = self.Columns
		p.Rows = self.Rows
		p.TileWidth = self.TileWidth
		p.TileHeight = self.TileHeight
		p.ScreenWidth = self.ScreenWidth
		p.ScreenHeight = self.ScreenHeight
		p.Layout = self.Layout
		p.DynamicSize = self.DynamicSize
		p.Reassembly = self.Reassembly
		return p

	def UpdateFromMothership(self, mothership):
		"""Update template values by examining the mothership/graph."""
		serverNode = FindServerNode(mothership)
		clientNode = FindClientNode(mothership)
		self.NumServers = serverNode.GetCount()
		self.ServerHosts = serverNode.GetHosts()[:] # [:] makes a copy
		self.ServerPattern = serverNode.GetHostNamePattern()
		#self.Columns = ??
		#self.Rows = ??
		#self.TileWidth = ??
		#self.TileHeight = ??
		#self.Layout = ??
		#self.DynamicSize = ??
		#self.Reassembly = ??
		
	def UpdateMothership(self, mothership):
		"""Update the mothership/graph from the template parameters."""
		clientNode = FindClientNode(mothership)
		serverNode = FindServerNode(mothership)
		serverNode.SetCount(self.NumServers)
		serverNode.SetHostNamePattern(self.ServerPattern)
		serverNode.SetHosts(self.ServerHosts)
		renderSPU = FindReassemblySPU(mothership)
		
		for i in range(serverNode.GetCount()):
			serverNode.SetTiles(self.MuralTiles[i], i)
		if self.DynamicSize:
			clientNode.Conf('track_window_size', 1)
			renderSPU.Conf('resizable', 1)
		else:
			clientNode.Conf('track_window_size', 0)
			renderSPU.Conf('resizable', 0)
			geom = renderSPU.GetOption('window_geometry')
			assert len(geom) == 4
			geom[2] = self.TileWidth * self.Columns
			geom[3] = self.TileHeight * self.Rows
			renderSPU.Conf('window_geometry', geom)
		if self.Reassembly == 2:
			renderSPU.Conf('render_to_app_window', 1)
		else:
			renderSPU.Conf('render_to_app_window', 0)


	def __AllocTiles(self, numServers, tiles):
		"""Allocate space for the tiles on the servers.  This is where
		we'll determine if there's enough space in the server's rendering
		window to accomodate all the tiles.
		Input: tiles is a list of tuples (server, x, y, w, h).
		Result: self.MuralTiles and self.ServerTiles will be filled in.
		Return 1 for success, 0 if we run out of room on the server."""
		# XXX we're assuming all tiles are the same height here!

		# initialize tile lists
		self.MuralTiles = []   # array [server] of array of (x, y, w, h)
		nextTile = []          # array [server] of (x, y)
		for i in range(numServers):
			self.MuralTiles.append( [] )
			nextTile.append( (0, 0) )

		self.ServerTiles = tiles[:] # copy the list

		for (server, x, y, w, h) in tiles:
			assert server >= 0
			assert server < numServers
			assert numServers == len(self.MuralTiles)
			assert len(self.MuralTiles) == len(nextTile)
			# Check if tile of size (w, h) will fit on this server
			# We allocate tiles in raster order, as in the crserver.
			# (nextX, nextY) = position on server's screen
			(nextX, nextY) = nextTile[server]
			if nextY + h > self.ScreenHeight:
				# ran out of room on this server!!!
				return 0
			elif nextX + w > self.ScreenWidth:
				# go to next row
				nextX = 0
				nextY += h
				if nextY + h > self.ScreenHeight:
					# ran out of room on this server!!!
					return 0
			# It'll fit, save it
			muralTile = (x, y, w, h)  # omit server
			self.MuralTiles[server].append( muralTile )
			# Update NextTile position for this server
			nextX += w
			nextTile[server] = (nextX, nextY)
		return 1


	def PrintTiles(self):
		# for debug only
		for i in range(len(self.MuralTiles)):
			print "server %d" % i
			for tile in self.MuralTiles[i]:
				print "  (%d, %d, %d, %d)" % tile

	def LayoutTiles(self):
		"""Compute locations and hosts for the tiles."""

		# begin layout
		if self.Layout == 0:
			# Simple raster order layout
			muralWidth = self.TileWidth * self.Columns
			muralHeight = self.TileHeight * self.Rows
			tiles = tilelayout.LayoutRaster(muralWidth, muralHeight,
											self.NumServers,
											self.TileWidth, self.TileHeight,
											self.Rows, self.Columns)
		elif self.Layout == 1:
			# Zig-zag raster order layout
			muralWidth = self.TileWidth * self.Columns
			muralHeight = self.TileHeight * self.Rows
			tiles = tilelayout.LayoutZigZag(muralWidth, muralHeight,
											self.NumServers,
											self.TileWidth, self.TileHeight,
											self.Rows, self.Columns)
		else:
			assert self.Layout == 2
			# Spiral outward from the center
			muralWidth = self.TileWidth * self.Columns
			muralHeight = self.TileHeight * self.Rows
			tiles = tilelayout.LayoutSpiral(muralWidth, muralHeight,
											self.NumServers,
											self.TileWidth, self.TileHeight,
											self.Rows, self.Columns)
		# Allocate tiles on the server
		self.__AllocTiles(self.NumServers, tiles)
		return


# Predefined tile sizes shown in the wxChoice widget (feel free to change)
CommonTileSizes = [ [32, 32],
					[64, 64],
					[128, 128],
					[256, 256],
					[512, 512] ]

BackgroundColor = wxColor(70, 170, 130)

ServerColors = [
	wxColor(255, 50, 50),   # red
	wxColor(50, 255, 50),   # green
	wxColor(150, 150, 255), # blue
	wxColor(0, 200, 200),   # cyan
	wxColor(200, 0, 200),   # purple
	wxColor(255, 255, 0),   # yellow
	wxColor(255, 100, 0),   # orange
	wxColor(255, 150, 130), # pink
	wxColor(139, 115, 85),  # burlywood4
	wxColor(152, 251, 152), # pale green
	wxColor(205, 92, 92),   # indian red
	wxColor(102, 139, 139), # PaleTurquoise4
	wxColor(255, 236, 139), # light goldenrod
	wxColor(159, 154, 98),  # khaki4
	wxColor(149, 81, 147),  # orchid4
	wxColor(0, 139, 69),    # SpringGreen4
]
	

#----------------------------------------------------------------------------

_ImportsSection = """
import string, sys, getopt
sys.path.append( "../server" )
from mothership import *
import tilelayout

"""

# This is the guts of the configuration script.
# It's simply appended to the file after we write all the configuration options
_ConfigBody = """
def Usage():
	print "Usage:"
	print "  %s [--help] [-c columns] [-r rows] [-w tileWidth]" % sys.argv[0]

	print "     [-h tileHeight] [-l layout] [-d dynamicResize] [-s servers] [program]"
	print "Where layout is 0, 1 or 2"
	print "Where dynamicSize is 0, 1 or 2"
	sys.exit(0)


PROGRAM = ""
ZEROTH_ARG = ""
AUTO_START_SERVERS = 0
AUTO_START_APPS = 0


# Look for some special options
for (name, value) in APP_OPTIONS:
	if name == "application":
		PROGRAM = value
	elif name == "zeroth_arg":
		ZEROTH_ARG = value
for (name, value) in MOTHERSHIP_OPTIONS:
	if name == "auto_start":
		AUTO_START_SERVERS = value
	elif name == "auto_start_apps":
		AUTO_START_APPS = value

# Process command line args
try:
	(opts, args) = getopt.getopt(sys.argv[1:], "c:r:w:h:l:s:d:", ["help"])
except getopt.GetoptError:
	Usage()

for (name, value) in opts:
	if name == "--help":
		Usage()
	elif name == "-c":
		TILE_COLS = int(value)
	elif name == "-r":
		TILE_ROWS = int(value)
	elif name == "-w":
		TILE_WIDTH = int(value)
	elif name == "-h":
		TILE_HEIGHT = int(value)
	elif name == "-s":
		SERVER_HOSTS = str.split(value, ",")
	elif name == "-l":
		LAYOUT = int(value)
	elif name == "-d":
		DYNAMIC_SIZE = int(value)

if len(args) > 0:
	PROGRAM = args[0]

print "--- Image Reassembly Template ---"
print "Mural size: %d cols x %d rows" % (TILE_COLS, TILE_ROWS)
print "Tile size: %d x %d" % (TILE_WIDTH, TILE_HEIGHT)
print "Total size: %d x %d" % (TILE_WIDTH * TILE_COLS, TILE_HEIGHT * TILE_ROWS)
print "Layout mode: %s" % ["Raster", "ZigZag", "Spiral"][LAYOUT]
print "Dynamic size: %s" % ["No", "Yes (variable rows/cols)", "Yes (variable tiel size)"][DYNAMIC_SIZE]
print "Servers: %s" % SERVER_HOSTS
print "Program: %s" % PROGRAM
print "---------------------------------"


def LayoutTiles(muralWidth, muralHeight):
	if DYNAMIC_SIZE == 1:
		# variable rows/cols, fixed tile size
		tileWidth = TILE_WIDTH
		tileHeight = TILE_HEIGHT
		rows = 0
		cols = 0
	else:
		# fixed rows/cols, variable tile size
		assert DYNAMIC_SIZE == 2
		tileWidth = 0
		tileHeight = 0
		rows = TILE_ROWS
		cols = TILE_COLS

	if LAYOUT == 0:
		tiles = tilelayout.LayoutRaster(muralWidth, muralHeight,
										NUM_SERVERS,
										tileWidth, tileHeight,
										rows, cols)
	elif LAYOUT == 1:
		tiles = tilelayout.LayoutZigZag(muralWidth, muralHeight,
										NUM_SERVERS,
										tileWidth, tileHeight,
										rows, cols)
	else:
		tiles = tilelayout.LayoutSpiral(muralWidth, muralHeight,
										NUM_SERVERS,
										tileWidth, tileHeight,
										rows, cols)
	return tiles


localHostname = os.uname()[1]

cr = CR()

tilesortSPUs = []
clientNodes = []

for i in range(NUM_APP_NODES):
	tilesortspu = SPU('tilesort')
	for (name, value) in TILESORT_OPTIONS:
		tilesortspu.Conf( name, value )
	if DYNAMIC_SIZE:
		tilesortspu.TileLayoutFunction(LayoutTiles)
		tilesortspu.Conf('optimize_bucket', 0)
	tilesortSPUs.append(tilesortspu)

	clientnode = CRApplicationNode()
	clientnode.AddSPU(tilesortspu)
	for (name, value) in APP_OPTIONS:
		clientnode.Conf(name, value)

	# argument substitutions
	if PROGRAM != "":
		if i == 0 and ZEROTH_ARG != "":
			app_string = string.replace( PROGRAM, '%0', ZEROTH_ARG)
		else:
			app_string = string.replace( PROGRAM, '%0', '' )
		app_string = string.replace( app_string, '%I', str(i) )
		app_string = string.replace( app_string, '%N', str(NUM_APP_NODES) )
		clientnode.Conf( 'application', app_string )

		if AUTO_START_APPS:
			clientnode.AutoStart( ["/bin/sh", "-c",
					"LD_LIBRARY_PATH=%s /usr/local/bin/crappfaker" % crlibdir] )

	clientNodes.append(clientnode)



if REASSEMBLY:
	reassembleNode = CRNetworkNode(REASSEMBLE_HOST)
	reassembleSPU = SPU('render')
	reassembleNode.AddSPU(reassembleSPU)
	for (name, value) in REASSEMBLE_OPTIONS:
		reassembleSPU.Conf( name, value )
	if AUTO_START_SERVERS:
		reassembleNode.AutoStart( ["/usr/bin/rsh", REASSEMBLE_HOST,
								"/bin/sh -c 'DISPLAY=:0.0  CRMOTHERSHIP=%s  LD_LIBRARY_PATH=%s  crserver'" % (REASSEMBLE_HOST, crlibdir) ] )

# Loop over servers
for serverIndex in range(NUM_SERVERS):

	serverTiles = TILES[serverIndex]
	if len(serverTiles) == 0:
		continue

	# Create this server's readback/render SPU
	if REASSEMBLY:
		renderspu = SPU('readback')<commit_msg>set shared_windows option<commit_after># Copyright (c) 2001, Stanford University
# All rights reserved.
#
# See the file LICENSE.txt for information on redistributing this software.
#
# Authors:
#   <NAME>

""" lightning2_template.py
    Template for setting up Lightning-2 (tile-reassembly) configurations.
"""


# Known issues:
# 1. Tiles must all be same size
# 2. Tiles cannot overlap
# 3. No support for the Lightning-2 border pixel / reassembly codes



import string, cPickle, os.path, re, sys
from wxPython.wx import *
import crtypes, crutils, intdialog, hostdialog, configio
sys.path.append( "../server" )
import tilelayout
import templatebase
import textdialog
sys.path.append("../server")
import crconfig


class LightningParameters:
	"""This class describes the parameters of a Lightning-2 configuration.
	When we begin editing a Lightning-2 config we init these values from
	the mothership (number of servers, etc) and/or the initial create-
	lightning-2 dialog.
	When we finish editing, we update the mothership config."""
	def __init__(self, rows=1, cols=2):
		assert rows >= 1
		assert cols >= 1
		self.NumServers = 4
		self.ServerHosts = ["localhost"]
		self.ServerPattern = ("localhost", 1)
		self.Columns = cols
		self.Rows = rows
		self.TileWidth = 256
		self.TileHeight = 256
		self.ScreenWidth = 1280  # server screen
		self.ScreenHeight = 1024
		self.Layout = 0
		self.DynamicSize = 0   # 0, 1, or 2
		self.Reassembly = 0  # 0, 1, o

	def Clone(self):
		"""Return a clone of this object."""
		# We're not using the copy.copy() function since it's flakey
		p = LightningParameters()
		p.NumServers = self.NumServers
		p.ServerHosts = self.ServerHosts[:]
		p.ServerPattern = self.ServerPattern
		p.Columns = self.Columns
		p.Rows = self.Rows
		p.TileWidth = self.TileWidth
		p.TileHeight = self.TileHeight
		p.ScreenWidth = self.ScreenWidth
		p.ScreenHeight = self.ScreenHeight
		p.Layout = self.Layout
		p.DynamicSize = self.DynamicSize
		p.Reassembly = self.Reassembly
		return p

	def UpdateFromMothership(self, mothership):
		"""Update template values by examining the mothership/graph."""
		serverNode = FindServerNode(mothership)
		clientNode = FindClientNode(mothership)
		self.NumServers = serverNode.GetCount()
		self.ServerHosts = serverNode.GetHosts()[:] # [:] makes a copy
		self.ServerPattern = serverNode.GetHostNamePattern()
		#self.Columns = ??
		#self.Rows = ??
		#self.TileWidth = ??
		#self.TileHeight = ??
		#self.Layout = ??
		#self.DynamicSize = ??
		#self.Reassembly = ??
		
	def UpdateMothership(self, mothership):
		"""Update the mothership/graph from the template parameters."""
		clientNode = FindClientNode(mothership)
		serverNode = FindServerNode(mothership)
		serverNode.SetCount(self.NumServers)
		serverNode.SetHostNamePattern(self.ServerPattern)
		serverNode.SetHosts(self.ServerHosts)
		renderSPU = FindReassemblySPU(mothership)
		
		for i in range(serverNode.GetCount()):
			serverNode.SetTiles(self.MuralTiles[i], i)
		if self.DynamicSize:
			clientNode.Conf('track_window_size', 1)
			renderSPU.Conf('resizable', 1)
		else:
			clientNode.Conf('track_window_size', 0)
			renderSPU.Conf('resizable', 0)
			geom = renderSPU.GetOption('window_geometry')
			assert len(geom) == 4
			geom[2] = self.TileWidth * self.Columns
			geom[3] = self.TileHeight * self.Rows
			renderSPU.Conf('window_geometry', geom)
		if self.Reassembly == 2:
			renderSPU.Conf('render_to_app_window', 1)
		else:
			renderSPU.Conf('render_to_app_window', 0)


	def __AllocTiles(self, numServers, tiles):
		"""Allocate space for the tiles on the servers.  This is where
		we'll determine if there's enough space in the server's rendering
		window to accomodate all the tiles.
		Input: tiles is a list of tuples (server, x, y, w, h).
		Result: self.MuralTiles and self.ServerTiles will be filled in.
		Return 1 for success, 0 if we run out of room on the server."""
		# XXX we're assuming all tiles are the same height here!

		# initialize tile lists
		self.MuralTiles = []   # array [server] of array of (x, y, w, h)
		nextTile = []          # array [server] of (x, y)
		for i in range(numServers):
			self.MuralTiles.append( [] )
			nextTile.append( (0, 0) )

		self.ServerTiles = tiles[:] # copy the list

		for (server, x, y, w, h) in tiles:
			assert server >= 0
			assert server < numServers
			assert numServers == len(self.MuralTiles)
			assert len(self.MuralTiles) == len(nextTile)
			# Check if tile of size (w, h) will fit on this server
			# We allocate tiles in raster order, as in the crserver.
			# (nextX, nextY) = position on server's screen
			(nextX, nextY) = nextTile[server]
			if nextY + h > self.ScreenHeight:
				# ran out of room on this server!!!
				return 0
			elif nextX + w > self.ScreenWidth:
				# go to next row
				nextX = 0
				nextY += h
				if nextY + h > self.ScreenHeight:
					# ran out of room on this server!!!
					return 0
			# It'll fit, save it
			muralTile = (x, y, w, h)  # omit server
			self.MuralTiles[server].append( muralTile )
			# Update NextTile position for this server
			nextX += w
			nextTile[server] = (nextX, nextY)
		return 1


	def PrintTiles(self):
		# for debug only
		for i in range(len(self.MuralTiles)):
			print "server %d" % i
			for tile in self.MuralTiles[i]:
				print "  (%d, %d, %d, %d)" % tile

	def LayoutTiles(self):
		"""Compute locations and hosts for the tiles."""

		# begin layout
		if self.Layout == 0:
			# Simple raster order layout
			muralWidth = self.TileWidth * self.Columns
			muralHeight = self.TileHeight * self.Rows
			tiles = tilelayout.LayoutRaster(muralWidth, muralHeight,
											self.NumServers,
											self.TileWidth, self.TileHeight,
											self.Rows, self.Columns)
		elif self.Layout == 1:
			# Zig-zag raster order layout
			muralWidth = self.TileWidth * self.Columns
			muralHeight = self.TileHeight * self.Rows
			tiles = tilelayout.LayoutZigZag(muralWidth, muralHeight,
											self.NumServers,
											self.TileWidth, self.TileHeight,
											self.Rows, self.Columns)
		else:
			assert self.Layout == 2
			# Spiral outward from the center
			muralWidth = self.TileWidth * self.Columns
			muralHeight = self.TileHeight * self.Rows
			tiles = tilelayout.LayoutSpiral(muralWidth, muralHeight,
											self.NumServers,
											self.TileWidth, self.TileHeight,
											self.Rows, self.Columns)
		# Allocate tiles on the server
		self.__AllocTiles(self.NumServers, tiles)
		return


# Predefined tile sizes shown in the wxChoice widget (feel free to change)
CommonTileSizes = [ [32, 32],
					[64, 64],
					[128, 128],
					[256, 256],
					[512, 512] ]

BackgroundColor = wxColor(70, 170, 130)

ServerColors = [
	wxColor(255, 50, 50),   # red
	wxColor(50, 255, 50),   # green
	wxColor(150, 150, 255), # blue
	wxColor(0, 200, 200),   # cyan
	wxColor(200, 0, 200),   # purple
	wxColor(255, 255, 0),   # yellow
	wxColor(255, 100, 0),   # orange
	wxColor(255, 150, 130), # pink
	wxColor(139, 115, 85),  # burlywood4
	wxColor(152, 251, 152), # pale green
	wxColor(205, 92, 92),   # indian red
	wxColor(102, 139, 139), # PaleTurquoise4
	wxColor(255, 236, 139), # light goldenrod
	wxColor(159, 154, 98),  # khaki4
	wxColor(149, 81, 147),  # orchid4
	wxColor(0, 139, 69),    # SpringGreen4
]
	

#----------------------------------------------------------------------------

_ImportsSection = """
import string, sys, getopt
sys.path.append( "../server" )
from mothership import *
import tilelayout

"""

# This is the guts of the configuration script.
# It's simply appended to the file after we write all the configuration options
_ConfigBody = """
def Usage():
	print "Usage:"
	print "  %s [--help] [-c columns] [-r rows] [-w tileWidth]" % sys.argv[0]

	print "     [-h tileHeight] [-l layout] [-d dynamicResize] [-s servers] [program]"
	print "Where layout is 0, 1 or 2"
	print "Where dynamicSize is 0, 1 or 2"
	sys.exit(0)


PROGRAM = ""
ZEROTH_ARG = ""
AUTO_START_SERVERS = 0
AUTO_START_APPS = 0


# Look for some special options
for (name, value) in APP_OPTIONS:
	if name == "application":
		PROGRAM = value
	elif name == "zeroth_arg":
		ZEROTH_ARG = value
for (name, value) in MOTHERSHIP_OPTIONS:
	if name == "auto_start":
		AUTO_START_SERVERS = value
	elif name == "auto_start_apps":
		AUTO_START_APPS = value

# Process command line args
try:
	(opts, args) = getopt.getopt(sys.argv[1:], "c:r:w:h:l:s:d:", ["help"])
except getopt.GetoptError:
	Usage()

for (name, value) in opts:
	if name == "--help":
		Usage()
	elif name == "-c":
		TILE_COLS = int(value)
	elif name == "-r":
		TILE_ROWS = int(value)
	elif name == "-w":
		TILE_WIDTH = int(value)
	elif name == "-h":
		TILE_HEIGHT = int(value)
	elif name == "-s":
		SERVER_HOSTS = str.split(value, ",")
	elif name == "-l":
		LAYOUT = int(value)
	elif name == "-d":
		DYNAMIC_SIZE = int(value)

if len(args) > 0:
	PROGRAM = args[0]

print "--- Image Reassembly Template ---"
print "Mural size: %d cols x %d rows" % (TILE_COLS, TILE_ROWS)
print "Tile size: %d x %d" % (TILE_WIDTH, TILE_HEIGHT)
print "Total size: %d x %d" % (TILE_WIDTH * TILE_COLS, TILE_HEIGHT * TILE_ROWS)
print "Layout mode: %s" % ["Raster", "ZigZag", "Spiral"][LAYOUT]
print "Dynamic size: %s" % ["No", "Yes (variable rows/cols)", "Yes (variable tiel size)"][DYNAMIC_SIZE]
print "Servers: %s" % SERVER_HOSTS
print "Program: %s" % PROGRAM
print "---------------------------------"


def LayoutTiles(muralWidth, muralHeight):
	if DYNAMIC_SIZE == 1:
		# variable rows/cols, fixed tile size
		tileWidth = TILE_WIDTH
		tileHeight = TILE_HEIGHT
		rows = 0
		cols = 0
	else:
		# fixed rows/cols, variable tile size
		assert DYNAMIC_SIZE == 2
		tileWidth = 0
		tileHeight = 0
		rows = TILE_ROWS
		cols = TILE_COLS

	if LAYOUT == 0:
		tiles = tilelayout.LayoutRaster(muralWidth, muralHeight,
										NUM_SERVERS,
										tileWidth, tileHeight,
										rows, cols)
	elif LAYOUT == 1:
		tiles = tilelayout.LayoutZigZag(muralWidth, muralHeight,
										NUM_SERVERS,
										tileWidth, tileHeight,
										rows, cols)
	else:
		tiles = tilelayout.LayoutSpiral(muralWidth, muralHeight,
										NUM_SERVERS,
										tileWidth, tileHeight,
										rows, cols)
	return tiles


localHostname = os.uname()[1]

cr = CR()

tilesortSPUs = []
clientNodes = []

for i in range(NUM_APP_NODES):
	tilesortspu = SPU('tilesort')
	for (name, value) in TILESORT_OPTIONS:
		tilesortspu.Conf( name, value )
	if DYNAMIC_SIZE:
		tilesortspu.TileLayoutFunction(LayoutTiles)
		tilesortspu.Conf('optimize_bucket', 0)
	tilesortSPUs.append(tilesortspu)

	clientnode = CRApplicationNode()
	clientnode.AddSPU(tilesortspu)
	for (name, value) in APP_OPTIONS:
		clientnode.Conf(name, value)

	# argument substitutions
	if PROGRAM != "":
		if i == 0 and ZEROTH_ARG != "":
			app_string = string.replace( PROGRAM, '%0', ZEROTH_ARG)
		else:
			app_string = string.replace( PROGRAM, '%0', '' )
		app_string = string.replace( app_string, '%I', str(i) )
		app_string = string.replace( app_string, '%N', str(NUM_APP_NODES) )
		clientnode.Conf( 'application', app_string )

		if AUTO_START_APPS:
			clientnode.AutoStart( ["/bin/sh", "-c",
					"LD_LIBRARY_PATH=%s /usr/local/bin/crappfaker" % crlibdir] )

	clientNodes.append(clientnode)



if REASSEMBLY:
	reassembleNode = CRNetworkNode(REASSEMBLE_HOST)
	reassembleNode.Conf('shared_windows', 1)
	reassembleSPU = SPU('render')
	reassembleNode.AddSPU(reassembleSPU)
	for (name, value) in REASSEMBLE_OPTIONS:
		reassembleSPU.Conf( name, value )
	if AUTO_START_SERVERS:
		reassembleNode.AutoStart( ["/usr/bin/rsh", REASSEMBLE_HOST,
								"/bin/sh -c 'DISPLAY=:0.0  CRMOTHERSHIP=%s  LD_LIBRARY_PATH=%s  crserver'" % (REASSEMBLE_HOST, crlibdir) ] )

# Loop over servers
for serverIndex in range(NUM_SERVERS):

	serverTiles = TILES[serverIndex]
	if len(serverTiles) == 0:
		continue

	# Create this server's readback/render SPU
	if REASSEMBLY:
		renderspu = SPU('readback')
{'fraction_non_alphanumeric': 0.12995352767215884, 'fraction_numerical': 0.021588508660752008, 'mean_word_length': 3.5130600571973307, 'pattern_counts': {'":': 28, '<': 7, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4540640', 'n_tokens_mistral': 9723, 'n_tokens_neox': 8245, 'n_words': 2317}