Esempio n. 1
0
def open_file2(file):
    if not os.path.exists(file):
        oldfile = file
        file = g.opendialog("Please locate " + file + ":", "Text files (*.txt)|*.txt", "", file)     
        if not os.path.exists(file):
            g.exit("Could not find '" + oldfile + "' or '" + file + "'.")
    f = open(file, 'r')
    f1 = f.read()
    f1 = f1.replace('b3/s23', 'B3/S23')
    while '\n\n\n' in f1:
        f1 = f1.replace('\n\n\n', '\n\n')
    f1 = f1.split('\n\n')
    #f1 = f1[:-2] #last two are larger than column width and will cause infinite loop
    for i in f1:
        #try:
        #    i = i[i.index('x ='):]
        #except ValueError:
        #    print('No "x =": ' + i)
        patterns.append(i)
        show_message("Pass 1 of 3: processing pattern #" + str(len(patterns)),0.001)
    show_message('Total number of patterns: %s' % len(patterns),0.5)
Esempio n. 2
0
def cygdir():
    # Find the Cygwin64 installation directory

    if (cygwin_dir is not None) and os.path.exists(cygwin_dir):
        return cygwin_dir
    elif os.path.exists('C:\\cygwin64'):
        return 'C:\\cygwin64'
    elif os.path.exists('C:\\cygwin'):
        return 'C:\\cygwin'

    if within_golly:
        dirname = g.opendialog(
            "Please find the Cygwin64 install directory (e.g. C:\\cygwin64)",
            "dir")
    else:
        dirname = raw_input(
            "Please type the Cygwin64 install directory (e.g. C:\\cygwin64): ")

    if os.path.exists(dirname):
        cygwin_dir = dirname
        return cygwin_dir
    else:
        raise ValueError("No Cygwin installation directory specified.")
import model_functions as mfunc
import model_parameters as mparam
import random as rand
import time
import pickle
import os
#
# Open a dialog window and ask the user to select two pickles.
#
g.note("View Contest\n\n" + \
  "You will be presented with two dialog menus:\n" + \
  "     (1) Select a file of pickled seeds.\n" + \
  "     (2) Select another file of pickled seeds.\n" + \
  "Two seeds, chosen randomly from each pickle, will then compete.")
#
path1 = g.opendialog("Select the first pickled seed file (*.bin)", \
  "(*.bin)|*.bin", g.getdir("app"))
path2 = g.opendialog("Select the second pickled seed file (*.bin)", \
  "(*.bin)|*.bin", g.getdir("app"))
#
# Some info to display to the user, in the header of the main window.
#
[head1, tail1] = os.path.split(path1)
[head2, tail2] = os.path.split(path2)
#
g.show("Red: " + path1 + "    Blue: " + path2)
#
# Load pickles and randomly select a seed from each pickle.
# The seeds are in order of decreasing fitness.
#
handle1 = open(path1, "rb")  # rb = read binary
pickle1 = pickle.load(handle1)
Esempio n. 4
0
import golly
import os
from glife.ReadRuleTable import *
from glife.RuleTree import *
from glife.EmulateTriangular import *
from glife.EmulateMargolus import *
from glife.EmulateOneDimensional import *
from glife.EmulateHexagonal import *

# ask user to select .table file
filename = golly.opendialog('Open a rule table to convert:',
                      'Rule tables (*.table)|*.table',
                      golly.getdir('rules'))

if len(filename) == 0: golly.exit()    # user hit Cancel

# add new converters here as they become available:
Converters = {
    "vonNeumann":ConvertRuleTableTransitionsToRuleTree,
    "Moore":ConvertRuleTableTransitionsToRuleTree,
    "triangularVonNeumann":EmulateTriangular,
    "triangularMoore":EmulateTriangular,
    "Margolus":EmulateMargolus,
    "square4_figure8v":EmulateMargolus,
    "square4_figure8h":EmulateMargolus,
    "square4_cyclic":EmulateMargolus,
    "oneDimensional":EmulateOneDimensional,
    "hexagonal":EmulateHexagonal,
}

golly.show("Reading from rule table file...")
Esempio n. 5
0
import golly
import os
from glife.ReadRuleTable import *
from glife.RuleTree import *
from glife.EmulateTriangular import *
from glife.EmulateMargolus import *
from glife.EmulateOneDimensional import *
from glife.EmulateHexagonal import *

# ask user to select .table file
filename = golly.opendialog('Open a rule table to convert:',
                      'Rule tables (*.table)|*.table',
                      golly.getdir('rules'))

if len(filename) == 0: golly.exit()    # user hit Cancel

# add new converters here as they become available:
Converters = {
    "vonNeumann":ConvertRuleTableTransitionsToRuleTree,
    "Moore":ConvertRuleTableTransitionsToRuleTree,
    "triangularVonNeumann":EmulateTriangular,
    "triangularMoore":EmulateTriangular,
    "Margolus":EmulateMargolus,
    "square4_figure8v":EmulateMargolus,
    "square4_figure8h":EmulateMargolus,
    "square4_cyclic":EmulateMargolus,
    "oneDimensional":EmulateOneDimensional,
    "hexagonal":EmulateHexagonal,
}

golly.show("Reading from rule table file...")
Esempio n. 6
0
def golly_grills():

    bounding_box = g.getrect()
    celllist = g.getcells(bounding_box)

    g.show('Creating problem...')
    gr = interpret_problem(celllist)

    if gr.easy_unsat():
        g.exit('Problem is trivially unsatisfiable')

    gr.update_golly()

    solve_problem = yn2bool(
        g.getstring('Would you like to run the SAT solver now?', 'yes'))
    save_dimacs = solve_problem or yn2bool(
        g.getstring('Would you like to save a DIMACS file to solve later?',
                    'yes'))
    solution_file = None
    dimacs_out = None

    if save_dimacs:
        dimacs_out = g.savedialog('Save DIMACS file',
                                  'DIMACS CNF files (*.cnf)|*.cnf',
                                  g.getdir('data'), 'problem.cnf')

    if solve_problem:
        ss = g.getstring(
            'Please specify maximum duration (in seconds) for lingeling optimisation',
            '300')
        dimacs_dir = dimacs_out[:-4] + '_dir'
        g.show('Invoking lingeling for at most %s seconds...' % ss)

        simp_status = gr.write_and_simplify(dimacs_dir=dimacs_dir,
                                            dimacs_out=dimacs_out,
                                            simptime=int(ss))

        if (simp_status == 'SAT'):
            g.show('Problem is satisfiable')
            solution_file = os.path.join(dimacs_dir, 'solution.txt')
        elif (simp_status == 'UNSAT'):
            g.exit('Problem is unsatisfiable')
        else:
            g.show('Generated head and tail files.')

            if yn2bool(
                    g.getstring(
                        'Would you like to run this in single-CPU iglucose?',
                        'yes')):
                g.show('Running iglucose in single-CPU mode...')
                solution_file = os.path.join(dimacs_dir, 'solution.txt')
                runbash(os.path.join(scriptdir, 'scripts',
                                     'iglucose.sh'), '-stop-at-sat',
                        os.path.join(dimacs_dir, 'full.icnf'), solution_file)

    elif dimacs_out:

        gr.write_dimacs(dimacs_out)

    if solution_file is None:
        if yn2bool(
                g.getstring('Would you like to load a solution file?', 'yes')):
            solution_file = g.opendialog('Load SAT solution',
                                         'All files (*)|*', g.getdir('data'))

    if solution_file:
        gr.load_solution(solution_file)
        gr.update_golly()
Esempio n. 7
0
import golly as g
from bitstring import BitArray

try:
	from PIL import Image
	from PIL import ImageSequence
except:
	g.exit("You need to install PIL (Python Imaging Library).")
	 
fname = g.opendialog("Open File", "*.gif", "", "")
if not len(fname):
  g.exit("")
  
outfile = g.savedialog("Save RAW Data File", "*.*", "", "ROM.dat")
if not len(outfile):
	g.exit("")
	
image = Image.open(fname)
buff = BitArray()

for frame in ImageSequence.Iterator(image):
	frame = list(frame.convert("1").getdata())
	for i in range(len(frame)):
		buff.append('0b0' if frame[i] & 0x1 else '0b1')

# normalize to 256k
if buff.length < 1 << 18:
	for i in range ((1 << 18 - 3) - (buff.length >> 3)):
		buff.append('0x00')
elif buff.length > 1 << 18:
	del buff[(1 << 18) + 1 : buff.length]
Esempio n. 8
0
      cursorX += chars.find(data[i + 1]) + 4
      i += 1
    elif data[i] == 'z':
      cursorX = 0
      cursorY += 5
    else:
      col = chars.find(data[i])
      if col & 1 != 0: cellList += [cursorX, cursorY]
      if col & 2 != 0: cellList += [cursorX, cursorY + 1]
      if col & 4 != 0: cellList += [cursorX, cursorY + 2]
      if col & 8 != 0: cellList += [cursorX, cursorY + 3]
      if col & 16 != 0: cellList += [cursorX, cursorY + 4]
      cursorX += 1
    i += 1
  return cellList

filename = golly.opendialog('Choose an apgsearch log file')
dirname = golly.opendialog('Choose a folder for the output', 'dir')
with open(filename) as f:
  line = f.readline()
  while line:
    if not line.isspace() and line[0] != '@':
      code = line.split()[0]
      try:
        cellList = readApg(code)
      except Exception, args:
        golly.warn(args[0])
      else:
        golly.store(cellList, dirname + code + '.rle')
    line = f.readline()
Esempio n. 9
0
        rl_x = rl_i[0]
        rl_y = rl_i[1]

    if rle_len == 1: rle_strA = ""
    else: rle_strA = str(rle_len)
    rle_res = rle_res[2:] + rle_strA + "o"

    return rle_res + "!"


# --------------------------------------------------------------------
glider = g.parse("3o$o$bo!")

# backup way for the script to work:  have user choose a text file containing constellations
if constellation_fname == "/YOUR/PATH/HERE/constellations.txt":  # don't edit the path in this line
    constellation_fname = g.opendialog("Open constellation list", "Text files (*.txt)|*.txt", \
                                       defaultfolder, "constellations.txt", False)
    if constellation_fname == "":
        g.exit("No constellation list found.  Script has exited.")

if output_fname == "/YOUR/PATH/HERE/output-collisions.rle":  # don't edit the path in this line
    output_fname = g.savedialog("Pick a place for the output file", "RLE files (*.rle)|*.rle", \
                                       defaultfolder, "output-collisions.rle", False)
    if output_fname == "":
        g.exit("No output filename provided.  Script has exited.")

# create an empty output file to append results to
with open(output_fname, "w") as outf:
    outf.write("x = 0, y = 0, rule = B3/S23\n")

x, y, count, match = 0, 0, 0, 0
Esempio n. 10
0
    g.note("Stdin:\n" + stdin_str + "\n\nStdout:\n" + stdout_str)


s4 = g.getstring("""Enter the coordinates of the top pixel of the hive (the following pattern) at the top-left in the most top-left RAM cell:
(Note: These values change when a pattern with a different ROM size (i.e. a pattern with a different height) is metafied)
_*_
*_*
*_*
_*_""", "-65648599,-13895568")

t4 = tuple(map(int, s4.split(",")))
p_init = (t4[0] + 130, t4[1] + 13)


write_bytes_filepath = g.opendialog("Open CSV for the Initial RAM Values", "CSV files (*.csv)|*.csv")

if write_bytes_filepath:
    with open(write_bytes_filepath, "rt") as f:
        write_bytes = [map(int, line.split(",")) for line in f.readlines()]

    g.show("Writing initial RAM bytes...")
    for t in write_bytes:
        write_byte_at(*t)
    g.show("Done.")
    g.note("Wrote {} initial RAM bytes.".format(len(write_bytes)))
else:
    g.note("Skipped writing initial RAM bytes.")

show_raw_ram_region()
Esempio n. 11
0
# emulate-Margolus-table.py
# reads a Margolus rule table, and produces a Moore-nhood rule table that
# emulates it.

import golly
import os

# ask user to select .table file
fn = golly.opendialog('Open a Margolus table to emulate',
                      'Rule tables (*.table)|*.table',
                      golly.getdir('rules'))

if len(fn) == 0: golly.exit()    # user hit Cancel

# state s becomes 1+2s and 2+2s, the first for when the cell is currently
# the top-left square of the Margolus partition, the other for when it isn't.

def as_top_left(s):
    return 1+2*s
def as_not_top_left(s):
    return 2+2*s

# for the various symmetries we need to remap the inputs and outputs:
symm = {
'none':[[0,1,2,3,4,5,6,7]],
'reflect_horizontal':[[0,1,2,3,4,5,6,7],[1,0,3,2,5,4,7,6]],
'reflect_vertical':[[0,1,2,3,4,5,6,7],[2,3,0,1,6,7,4,5]],
'rotate4':
    [[0,1,2,3,4,5,6,7],[2,0,3,1,6,4,7,5],[3,2,1,0,7,6,5,4],[1,3,0,2,5,7,4,6]],
'rotate4reflect':[
    [0,1,2,3,4,5,6,7],[2,0,3,1,6,4,7,5],[3,2,1,0,7,6,5,4],[1,3,0,2,5,7,4,6],
Esempio n. 12
0
import pickle
import os
import sys
#
# -----------------------------------------------------------------
# Open a dialog window and ask the user to select three folders.
# -----------------------------------------------------------------
#
g.note("Analyze Pickles\n\n" + \
       "You will be presented with three dialog menus:\n\n" + \
       "     (1) Select a FOLDER of pickled seeds of type 1.\n" + \
       "     (2) Select a FOLDER of pickled seeds of type 2.\n" + \
       "     (3) Select a FOLDER for storing the analysis results.\n\n" + \
       "The pickles will be analyzed and the results will be stored.\n")
#
pickle_dir1 = g.opendialog("Choose a folder of pickled seeds of type 1.", \
             "dir", g.getdir("app"))
pickle_dir2 = g.opendialog("Choose a folder of pickled seeds of type 2.", \
             "dir", g.getdir("app"))
analysis_dir = g.opendialog("Choose a folder for the analysis.", \
             "dir", g.getdir("app"))
#
g.note("Verify Selection\n\n" + \
       "The chosen folder of pickled seeds of type 1:\n\n" + \
       "   " + pickle_dir1 + "\n\n" + \
       "The chosen folder of pickled seeds of type 2:\n\n" + \
       "   " + pickle_dir2 + "\n\n" + \
       "The chosen folder for the analysis results:\n\n" + \
       "   " + analysis_dir + "\n\n" + \
       "Exit now if these folders are incorrect.")
#
# Make a list of the pickles in pickle_dir1.
Esempio n. 13
0
import golly
import os
from glife.ReadRuleTable import *
from glife.RuleTree import *
from glife.EmulateTriangular import *
from glife.EmulateMargolus import *
from glife.EmulateOneDimensional import *
from glife.EmulateHexagonal import *

rulefilenames = "C:/PUT/YOUR/FILE/PATH/HERE/tablelist.txt"
reportfile = "C:/PUT/YOUR/LOG/FILE/PATH/HERE/errorreportfile.txt"
outfolder = "C:/PUT/YOUR/FOLDER/PATH/HERE/outtrees/"

if rulefilenames == "C:/PUT/YOUR/FILE/PATH/HERE.txt":
    rulefilenames = golly.opendialog(
        'Open a newline-delimited list of .table filenames (with paths)',
        'Text files (*.txt)|*.txt')
    if len(rulefilenames) == 0: golly.exit()  # user hit Cancel

with open(rulefilenames, "r") as f:
    rulefileslist = f.readlines()

for item in rulefileslist:
    # do rule @TREE creation for each item in rule list
    filename = item.replace("\n", "")
    golly.show("Processing " + filename)

    # DMG: now this hacked script can proceed in the same way as the original RuleTableToTree.py

    # add new converters here as they become available:
    Converters = {
Esempio n. 14
0
import golly
import os
from glife.ReadRuleTable import *
from glife.RuleTree import *
from glife.EmulateTriangular import *
from glife.EmulateMargolus import *
from glife.EmulateOneDimensional import *
from glife.EmulateHexagonal import *

# ask user to select .table file
filename = golly.opendialog("Open a rule table to convert:", "Rule tables (*.table)|*.table", golly.getdir("rules"))

if len(filename) == 0:
    golly.exit()  # user hit Cancel

# add new converters here as they become available:
Converters = {
    "vonNeumann": ConvertRuleTableTransitionsToRuleTree,
    "Moore": ConvertRuleTableTransitionsToRuleTree,
    "triangularVonNeumann": EmulateTriangular,
    "triangularMoore": EmulateTriangular,
    "Margolus": EmulateMargolus,
    "square4_figure8v": EmulateMargolus,
    "square4_figure8h": EmulateMargolus,
    "square4_cyclic": EmulateMargolus,
    "oneDimensional": EmulateOneDimensional,
    "hexagonal": EmulateHexagonal,
}

golly.show("Reading from rule table file...")
n_states, neighborhood, transitions = ReadRuleTable(filename)
Esempio n. 15
0
import golly as g
import glife
import operator

ptbdir = "/home/scorbie/Apps/ptbsearch-test"
catfilename = g.opendialog("Choose catalyst file to verify", "All files(*)|*", ptbdir)
cats = []
size = 20


def iscomment(line):
    return line.strip() == "" or line.lstrip().startswith("#")


g.setrule("LifeHistory")

try:
    currcats = []

    with open(catfilename) as catfile:
        for line in catfile:
            if iscomment(line):
                # Organize all the previous cats.
                if currcats:
                    currcat = reduce(operator.add, (cat.translate(0, idx * size) for idx, cat in enumerate(currcats)))
                    cats.append(currcat)
                # Prepare new cat container
                currcats = []
            else:
                currcats.append(glife.pattern(line))
        currcat = reduce(operator.add, (cat.translate(0, idx * size) for idx, cat in enumerate(currcats)))
Esempio n. 16
0
def choose_pickles(g):
    """
  Present a GUI to ask the users which folder of pickles they
  would like to analyze.
  """
    #
    # Open a dialog window and ask the user to select two folders.
    #
    g.note("Analyze Pickles\n\n" + \
           "You will be presented with two dialog menus:\n\n" + \
           "     (1) Select a FOLDER of pickled seeds.\n" + \
           "     (2) Select a FOLDER for storing the analysis results.\n\n" + \
           "The pickles will be analyzed and the results will be stored.\n")
    #
    pickle_dir = g.opendialog("Choose a folder of pickled seeds", \
                 "dir", g.getdir("app"))
    analysis_dir = g.opendialog("Choose a folder for the analysis", \
                 "dir", g.getdir("app"))
    #
    g.note("Verify Selection\n\n" + \
           "The chosen folder of pickled seeds:\n\n" + \
           "   " + pickle_dir + "\n\n" + \
           "The chosen folder for the analysis results:\n\n" + \
           "   " + analysis_dir + "\n\n" + \
           "Exit now if these folders are incorrect.")
    #
    # Make a list of the pickles in pickle_dir.
    #
    pickle_list = []
    for file in os.listdir(pickle_dir):
        if file.endswith(".bin"):
            pickle_list.append(file)
    #
    # Verify that there are some ".bin" files in the list.
    #
    if (len(pickle_list) == 0):
        g.note("No pickles were found in the directory:\n\n" + \
               "   " + pickle_dir + "\n\n" + \
               "Exiting now.")
        sys.exit(0)
    #
    # Make a hash table that maps pickle names to the last
    # generation number of the given group of pickles.
    #
    pickle_hash = hash_pickles(pickle_list)
    #
    # Calculate the size of the smallest group of pickles.
    #
    smallest_pickle_size = min(pickle_hash.values())
    #
    # Report the base parts of the pickles and their maximum
    # values
    #
    sorted_pickle_names = sorted(pickle_hash.keys())
    pickle_note = ""
    for pickle_base in sorted_pickle_names:
        pickle_note = pickle_note + \
          pickle_base + " ranges from 0 to " + \
          str(pickle_hash[pickle_base]) + "\n"
    g.note("These pickles were found:\n\n" +
      pickle_note + "\n" + \
      "The analysis will range from 0 to " + \
      str(smallest_pickle_size) + "\n\n" + \
      "Exit now if this is not what you expected.")
    #
    return [pickle_dir, analysis_dir, \
      sorted_pickle_names, smallest_pickle_size]
import model_functions as mfunc
import model_parameters as mparam
import random as rand
import time
import pickle
import os
#
# Open a dialog window and ask the user to select two seeds.
#
g.note("View Contest\n\n" + \
  "You will be presented with two dialog menus:\n" + \
  "     (1) Select a file with one human-designed pattern.\n" + \
  "     (2) Select a file of pickled seeds (the fittest seed will be used).\n" + \
  "The two seeds will then compete.")
#
path1 = g.opendialog("Select a human-designed Life pattern file (*.rle)", \
  "(*.rle)|*.rle", g.getdir("app"))
path2 = g.opendialog("Select a machine-evolved Life seed file (*.bin)", \
  "(*.bin)|*.bin", g.getdir("app"))
#
# Some info to display to the user, in the header of the main window.
#
[head1, tail1] = os.path.split(path1)
[head2, tail2] = os.path.split(path2)
#
g.show("Red: " + path1 + "    Blue: " + path2)
#
# Load the human-designed Life pattern file.
#
seed1 = mfunc.load_designed_seed(g, path1)
#
# Load machine-evolved Life seeds in the pickle.
Esempio n. 18
0
import sys
import golly

visual_execution = True  #False for faster programs, True required for infinitely looping ones

file = golly.opendialog()
f = open(file).read()

golly.new("Executing " + file.split("/")[-1])
golly.setrule("B/S012345678")

golly.autoupdate(visual_execution)

commands = []

for line in f.splitlines():
    important = line.split("#")[0].strip()
    if not important:
        continue

    important = important.split()[0:5]
    commands.append((important[0], int(important[1]), int(important[2]),
                     important[3], important[4]))

pointer = [0, 0]
instruction_pointer = "start"

while True:
    command = commands[[i[0] for i in commands].index(instruction_pointer)]
    pointer = [pointer[0] + command[1], pointer[1] + command[2]]
    x = pointer[0]
Esempio n. 19
0
    if not r:
        return
    if not g.visrect(r):
        g.setpos(str(r[0] + r[2] / 2), str(r[1] + r[3] / 2))
        if not g.visrect(r):
            g.setmag(g.getmag() - 1)


# regex for sss format ships
sssFormat = re.compile(
    r'(\d+), (B[0-9aceijknqrtwyz-]+/S[0-9aceijknqrtwyz-]*), (\d+), (\d+), (\d+), ([0-9ob$]+!)'
)

sssPatterns = []
filetypes = "sss Files (*.sss.txt;*.txt)|*.sss.txt;*.txt"
sssFile = g.opendialog("Choose spaceship file", filetypes)

# Grab a string containing all the sss format patterns
if sssFile:
    with open(sssFile, 'r') as F:
        sssFileLines = F.readlines()
else:
    sssFileLines = g.getclipstr().splitlines()

for line in sssFileLines:
    m = sssFormat.match(line)
    if m:
        # Format: (minpop, 'rulestr', dx, dy, period, 'shiprle')
        s = m.groups()
        sssPatterns.append(
            (int(s[0]), s[1], int(s[2]), int(s[3]), int(s[4]), s[5]))
Esempio n. 20
0
import model_functions as mfunc
import model_parameters as mparam
import pickle
#
# Set the colours so they are suitable for printing.
# The background should be light and the foreground
# should be dark.
#
g.setcolors([0, 255, 255, 255, 1, 0, 0, 0])
#
# Ask the user to select a pickle.
#
g.note("You will be asked to select a pickled seed file.\n" + \
       "The top seed in the file will be inserted into Golly.")
#
pickle_path = g.opendialog("Select a pickled seed file (*.bin)", \
  "(*.bin)|*.bin", g.getdir("app"))
#
# Read the pickle file.
#
pickle_handle = open(pickle_path, "rb")  # rb = read binary
pickle = pickle.load(pickle_handle)
pickle_handle.close()
#
# Select the top seed from the pickle file.
#
seed = pickle[0]
#
# Write the seed into Golly.
#
for x in range(seed.xspan):
    for y in range(seed.yspan):
                Optional(comment)).setParseAction(lambda t: [t])
        self.program = ZeroOrMore(inst)

    def parse_string(self, string):
        return self.program.parseString(string)


# g.show("Loading code from clipboard...")

# rawcode = g.getclipstr()

# g.show("Parsing clipboard...")

g.show("Reading code from an input QFTASM file...")

rom_qftasm_filepath = g.opendialog("Open the ROM qftasm file",
                                   "QFTASM files (*.qftasm)|*.qftasm")

if rom_qftasm_filepath:
    with open(rom_qftasm_filepath, "rt") as f:
        rawcode = f.read()
else:
    g.exit("No input file provided - exiting.")

g.show("Parsing QFTASM...")

parser = Parser()
parsed = parser.parse_string(rawcode)

l_binstring = []