[
  {
    "path": ".dockerignore",
    "content": "vncdriver/logs\n.git\n*.pyc\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.ropeproject\n*.pyc\ntags\n*.swo\n*.swp\n*.sqlite\nupload/\nvenv\ndist\n*.egg-info\n.idea\n/logs\n/dist\nbuild/\n/.gitfiles\n/.tox\n/.cache\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: python\npython:\n  - \"3.5\"\nservices:\n  - docker\nbefore_install:\n  - docker build -f test.dockerfile -t quay.io/openai/universe:test .\nscript:\n  - docker run -v /usr/bin/docker:/usr/bin/docker -v /root/.docker:/root/.docker -v /var/run/docker.sock:/var/run/docker.sock --net=host quay.io/openai/universe:test\nnotifications:\n  slack:\n    secure: HtkwTGU+cQbpQuRaMuC2ZcuaaJfUBEZxSaChkj74lFulHAc6g/Xj1ztzj/roR/kMl3dycYPl5QL5AkxPPD/x8BweOJmgabe9boPbU9+80tpa0ueZnt0q6vX23ZA7EcqIAOwQqHiaklxoCkSflpV2N9GP20yBf5YNneHWsbFc8RDuJmNsg8s+1sZIrT3aOcvAJmu8WrNVclKvnpH/qCtvkK6npXZvdMvGpQPT/uCYOyPcbURqelk7qzNpT0oJmkrutbkT3Hp03NRDEQgS47pTPMC5pklea5zDkyh++ETEMpXU75UgN3CURKhuf/oyq7JorG/lXQaz6HBYbcT9EhPVpTzPZEczk50VAp3RWWcN6NczJJ9rVL0h+bGZmcOlJz9igNl838ziL6nxMFO9W3psXQUoBvEDo+vXPDEOUxeBrtLqUN1vfQmMw7KKiGIimInWigW19WfVQhSt47+xKKmbvBKtQ/w8lCDlwO5h7QbApv6TiaGzxtzdJMAyhNOZE7KxqvtFCJgKL4ZfmVzziLlbdbr582Cc0wxvGLDC341+CqkYVv83oimM8Ks3wHRT/ABoO1uXOSsZniUU/+oU/mzyrhrkGNNSDCwdJ0mVEWRGTYZs26IcBIeYGsLJrv3J9ZgfiyD2Knl4/yVI0IbTs7qAzhBzsXvt9aH7kH7tXYZH9QQ=\n  webhooks:\n    urls:\n      - https://hooks.zapier.com/hooks/catch/1711022/6ztmzh/\n      - https://hooks.zapier.com/hooks/catch/1711022/6zhc8p/\n    on_success: always\n    on_failure: always\nafter_success:\n  - export BRANCH=$(if [ \"$TRAVIS_PULL_REQUEST\" == \"false\" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)\n  - echo \"TRAVIS_BRANCH=$TRAVIS_BRANCH, PR=$PR, BRANCH=$BRANCH\"\n  - docker login quay.io -u=\"$DOCKER_USERNAME\" -p=\"$DOCKER_PASSWORD\"\n  - docker tag quay.io/openai/universe:test quay.io/openai/universe-travis:passed-ci\n  - if [ \"$BRANCH\" == \"master\" ]; then ( while true; do echo '.'; sleep 60; done ) & docker push quay.io/openai/universe-travis:passed-ci; fi # This repo is used by universe-envs to run integration test. We echo in order to keep travis alive during a slow push\n"
  },
  {
    "path": "CODE_OF_CONDUCT.rst",
    "content": "OpenAI is dedicated to providing a harassment-free experience for\neveryone, regardless of gender, gender identity and expression, sexual\norientation, disability, physical appearance, body size, age, race, or\nreligion. We do not tolerate harassment of participants in any form.\n\nThis code of conduct applies to all OpenAI spaces both online and\noff. Anyone who violates this code of conduct may be sanctioned or\nexpelled from these spaces at the discretion of the OpenAI team.\n\nWe may add additional rules over time, which will be made clearly\navailable to participants. Participants are responsible for knowing\nand abiding by these rules.\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM ubuntu:16.04\n\nRUN apt-get update \\\n    && apt-get install -y libav-tools \\\n    python3-numpy \\\n    python3-scipy \\\n    python3-setuptools \\\n    python3-pip \\\n    libpq-dev \\\n    libjpeg-dev \\\n    curl \\\n    cmake \\\n    swig \\\n    python3-opengl \\\n    libboost-all-dev \\\n    libsdl2-dev \\\n    wget \\\n    unzip \\\n    git \\\n    golang \\\n    net-tools \\\n    iptables \\\n    libvncserver-dev \\\n    software-properties-common \\\n    && apt-get clean \\\n    && rm -rf /var/lib/apt/lists/*\n\nRUN ln -sf /usr/bin/pip3 /usr/local/bin/pip \\\n    && ln -sf /usr/bin/python3 /usr/local/bin/python \\\n    && pip install -U pip\n\n# Install gym\nRUN pip install gym[all]\n\n# Get the faster VNC driver\nRUN pip install go-vncdriver>=0.4.0\n\n# Install pytest (for running test cases)\nRUN pip install pytest\n\n# Force the container to use the go vnc driver\nENV UNIVERSE_VNCDRIVER='go'\n\nWORKDIR /usr/local/universe/\n\n# Cachebusting\nCOPY ./setup.py ./\nCOPY ./tox.ini ./\n\nRUN pip install -e .\n\n# Upload our actual code\nCOPY . ./\n\n# Just in case any python cache files were carried over from the source directory, remove them\nRUN py3clean .\n"
  },
  {
    "path": "ISSUE_TEMPLATE",
    "content": "\n(First, please check https://github.com/openai/universe/wiki/Solutions-to-common-problems for solutions to many common problems)\n\n### Expected behavior\n\n### Actual behavior\n\n### Versions\nPlease include the result of running\n```\n$ uname -a ; python --version; pip show universe gym tensorflow numpy go-vncdriver Pillow\n```\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License\n\nCopyright (c) 2016 OpenAI (http://openai.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "upload:\n\trm -rf dist\n\tpython setup.py sdist\n\ttwine upload dist/*\n\ntest:\n\tfind . -name '*.pyc' -delete\n\tdocker build -f test.dockerfile -t quay.io/openai/universe:test .\n\tdocker run -v /usr/bin/docker:/usr/bin/docker -v /root/.docker:/root/.docker -v /var/run/docker.sock:/var/run/docker.sock --net=host quay.io/openai/universe:test\n\nbuild:\n\tfind . -name '*.pyc' -delete\n\tdocker build -t quay.io/openai/universe .\n\tdocker build -f test.dockerfile -t quay.io/openai/universe:test .\n\npush:\n\tfind . -name '*.pyc' -delete\n\tdocker build -t quay.io/openai/universe .\n\tdocker build -f test.dockerfile -t quay.io/openai/universe:test .\n\n\tdocker push quay.io/openai/universe\n\tdocker push quay.io/openai/universe:test\n\ntest-push:\n\tdocker build -f test.dockerfile -t quay.io/openai/universe:test .\n\tdocker push quay.io/openai/universe:test\n"
  },
  {
    "path": "README.rst",
    "content": "**This repository has been deprecated in favor of the Retro (https://github.com/openai/retro) library. See our Retro Contest (https://blog.openai.com/retro-contest) blog post for detalis.**\n\nuniverse\n***************\n\n`Universe <https://openai.com/blog/universe/>`_ is a software\nplatform for measuring and training an AI's general intelligence\nacross the world's supply of games, websites and other\napplications. This is the ``universe`` open-source library, which\nprovides a simple `Gym <https://github.com/openai/gym>`__\ninterface to each Universe environment.\n\nUniverse allows anyone to train and evaluate AI agents on an extremely\nwide range of real-time, complex environments.\n\nUniverse makes it possible for any existing program to become an\nOpenAI Gym environment, without needing special access to the\nprogram's internals, source code, or APIs. It does this by packaging\nthe program into a Docker container, and presenting the AI with the\nsame interface a human uses: sending keyboard and mouse events, and\nreceiving screen pixels. Our initial release contains over 1,000\nenvironments in which an AI agent can take actions and gather\nobservations.\n\nAdditionally, some environments include a reward signal sent to the\nagent, to guide reinforcement learning. We've included a few hundred\nenvironments with reward signals. These environments also include\nautomated start menu clickthroughs, allowing your agent to skip to the\ninteresting part of the environment.\n\nWe'd like the community's `help <https://openai.com/blog/universe/#help>`_\nto grow the number of available environments, including integrating\nincreasingly large and complex games.\n\nThe following classes of tasks are packaged inside of\npublicly-available Docker containers, and can be run today with no\nwork on your part:\n\n- Atari and CartPole environments over VNC: ``gym-core.Pong-v3``, ``gym-core.CartPole-v0``, etc.\n- Flashgames over VNC: ``flashgames.DuskDrive-v0``, etc.\n- Browser tasks (\"World of Bits\") over VNC: ``wob.mini.TicTacToe-v0``, etc.\n\nWe've scoped out integrations for many other games, including\ncompleting a high-quality GTA V integration (thanks to `Craig Quiter <http://deepdrive.io/>`_ and NVIDIA), but these aren't included in today's release.\n\n.. contents:: **Contents of this document**\n   :depth: 2\n\n\nGetting started\n===============\n\nInstallation\n------------\n\nSupported systems\n~~~~~~~~~~~~~~~~~\n\nWe currently support Linux and OSX running Python 2.7 or 3.5.\n\nWe recommend setting up a `conda environment <http://conda.pydata.org/docs/using/envs.html>`__\nbefore getting started, to keep all your Universe-related packages in the same place.\n\nInstall Universe\n~~~~~~~~~~~~~~~~\nTo get started, first install ``universe``:\n\n.. code:: shell\n\n    git clone https://github.com/openai/universe.git\n    cd universe\n    pip install -e .\n\nIf this errors out, you may be missing some required packages. Here's\nthe list of required packages we know about so far (please let us know\nif you had to install any others).\n\nOn Ubuntu 16.04:\n\n.. code:: shell\n\n    pip install numpy\n    sudo apt-get install golang libjpeg-turbo8-dev make\n\nOn Ubuntu 14.04:\n\n.. code:: shell\n\n    sudo add-apt-repository ppa:ubuntu-lxc/lxd-stable  # for newer golang\n    sudo apt-get update\n    sudo apt-get install golang libjpeg-turbo8-dev make\n\nOn OSX:\n\nYou might need to install Command Line Tools by running:\n\n.. code:: shell\n\n    xcode-select --install\n\nOr ``numpy``, ``libjpeg-turbo`` and ``incremental`` packages:\n\n.. code:: shell\n\n    pip install numpy incremental\n    brew install golang libjpeg-turbo\n\nInstall Docker\n~~~~~~~~~~~~~~\n\nThe majority of the environments in Universe run inside Docker\ncontainers, so you will need to `install Docker\n<https://docs.docker.com/engine/installation/>`__ (on OSX, we\nrecommend `Docker for Mac\n<https://docs.docker.com/docker-for-mac/>`__). You should be able to\nrun ``docker ps`` and get something like this:\n\n.. code:: shell\n\n     $ docker ps\n     CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES\n\nAlternate configuration - running the agent in docker\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe above instructions result in an agent that runs as a regular python process in your OS, and launches docker containers as needed for the remotes.\nAlternatively, you can build a docker image for the agent and run it as a container as well.\nYou can do this in any operating system that has a recent version of docker installed, and the git client.\n\nTo get started, clone the ``universe`` repo:\n\n.. code:: shell\n\n    git clone https://github.com/openai/universe.git\n    cd universe\n\t\nBuild a docker image, tag it as 'universe':\n\n.. code:: shell\n\n    docker build -t universe .\n\nThis may take a while the first time, as the docker image layers are pulled from docker hub.\n\nOnce the image is built, you can do a quick run of the test cases to make sure everything is working:\n\n.. code:: shell\n\n    docker run --privileged --rm -e DOCKER_NET_HOST=172.17.0.1 -v /var/run/docker.sock:/var/run/docker.sock universe pytest\n\nHere's a breakdown of that command:\n\n* ``docker run`` - launch a docker container\n* ``--rm`` - delete the container once the launched process finishes\n* ``-e DOCKER_NET_HOST=172.17.0.1`` - tells the universe remote (when launched) to make its VNC connection back to this docker-allocated IP\n* ``-v /var/run/docker.sock:/var/run/docker.sock`` - makes the docker unix socket from the host available to the container. This is a common technique used to allow containers to launch other containers alongside itself.\n* ``universe`` - use the imaged named 'universe' built above\n* ``pytest`` - run 'pytest' in the container, which runs all the tests\n\nAt this point, you'll see a bunch of tests run and hopefully all pass.\n\nTo do some actual development work, you probably want to do another volume map from the universe repo on your host into the container, then shell in interactively:\n\n.. code:: shell\n\n    docker run --privileged --rm -it -e DOCKER_NET_HOST=172.17.0.1 -v /var/run/docker.sock:/var/run/docker.sock -v (full path to cloned repo above):/usr/local/universe universe python\n\nAs you edit the files in your cloned git repo, they will be changed in your docker container and you'll be able to run them in python.\n\nNote if you are using docker for Windows, you'll need to enable the relevant shared drive for this to work.\n\n\nNotes on installation\n~~~~~~~~~~~~~~~~~~~~~\n\n* When installing ``universe``, you may see ``warning`` messages.  These lines occur when installing numpy and are normal.\n* You'll need a ``go version`` of at least 1.5. Ubuntu 14.04 has an older Go, so you'll need to `upgrade <https://golang.org/doc/install>`_ your Go installation.\n* We run Python 3.5 internally, so the Python 3.5 variants will be much more thoroughly performance tested. Please let us know if you see any issues on 2.7.\n* While we don't officially support Windows, we expect our code to be very close to working there. We'd be happy to take pull requests that take our Windows compatibility to 100%. In the meantime, the easiest way for Windows users to run universe is to use the alternate configuration described above.\n\nSystem overview\n---------------\n\nA Universe **environment** is similar to any other Gym environment:\nthe agent submits actions and receives observations using the ``step()``\nmethod.\n\nInternally, a Universe environment consists of two pieces: a **client** and a **remote**:\n\n* The **client** is a `VNCEnv\n  <https://github.com/openai/universe/blob/master/universe/envs/vnc_env.py>`_\n  instance which lives in the same process as the agent. It performs\n  functions like receiving the agent's actions, proxying them to the\n  **remote**, queuing up rewards for the agent, and maintaining a\n  local view of the current episode state.\n* The **remote** is the running environment dynamics, usually a\n  program running inside of a Docker container. It can run anywhere --\n  locally, on a remote server, or in the cloud. (We have a separate\n  page describing how to manage `remotes <doc/remotes.rst>`__.)\n* The client and the remote communicate with one another using the\n  `VNC <https://en.wikipedia.org/wiki/Virtual_Network_Computing>`__\n  remote desktop system, as well as over an auxiliary WebSocket\n  channel for reward, diagnostic, and control messages. (For more\n  information on client-remote communication, see the separate page on\n  the `Universe internal communication protocols\n  <doc/protocols.rst>`__.)\n\nThe code in this repository corresponds to the **client** side of the\nUniverse environments. Additionally, you can freely access the Docker\nimages for the **remotes**. We'll release the source repositories for\nthe remotes in the future, along with tools to enable users to\nintegrate new environments. Please sign up for our `beta\n<https://docs.google.com/forms/d/e/1FAIpQLScAiW-kIS0mz6hdzzFZJJFlXlicDvQs1TX9XMEkipNwjV5VlA/viewform>`_\nif you'd like early access.\n\nRun your first agent\n--------------------\n\nNow that you've installed the ``universe`` library, you should make\nsure it actually works. You can paste the example below into your\n``python`` REPL. (You may need to press enter an extra time to make\nsure the ``while`` loop is executing.)\n\n.. code:: python\n\n  import gym\n  import universe  # register the universe environments\n\n  env = gym.make('flashgames.DuskDrive-v0')\n  env.configure(remotes=1)  # automatically creates a local docker container\n  observation_n = env.reset()\n\n  while True:\n    action_n = [[('KeyEvent', 'ArrowUp', True)] for ob in observation_n]  # your agent here\n    observation_n, reward_n, done_n, info = env.step(action_n)\n    env.render()\n\nThe example will instantiate a client in your Python process,\nautomatically pull the ``quay.io/openai/universe.flashgames`` image,\nand will start that image as the remote. (In our `remotes\n<doc/remotes.rst>`__ documentation page, we explain other ways you can run\nremotes.)\n\nIt will take a few minutes for the image to pull the first time. After that,\nif all goes well, a window like the one below will soon pop up. Your\nagent, which is just pressing the up arrow repeatedly, is now\nplaying a Flash racing game called `Dusk Drive\n<http://www.kongregate.com/games/longanimals/dusk-drive>`__. Your agent\nis programmatically controlling a VNC client, connected to a VNC\nserver running inside of a Docker container in the cloud, rendering a\nheadless Chrome with Flash enabled:\n\n.. image:: https://github.com/openai/universe/blob/master/doc/dusk-drive.png?raw=true\n     :width: 600px\n\nYou can even connect your own VNC client to the environment, either\njust to observe or to interfere with your agent. Our ``flashgames``\nand ``gym-core`` images conveniently bundle a browser-based VNC\nclient, which can be accessed at\n``http://localhost:15900/viewer/?password=openai``. If you're on Mac,\nconnecting to a VNC server is as easy as running: ``open\nvnc://localhost:5900``.\n\n(If using docker-machine, you'll need to replace \"localhost\" with the\nIP address of your Docker daemon, and use ``openai`` as the password.)\n\nBreaking down the example\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSo we managed to run an agent, what did all the code actually\nmean? We'll go line-by-line through the example.\n\n* First, we import the `gym <https://github.com/openai/gym>`__ library,\n  which is the base on which Universe is built. We also import\n  ``universe``, which `registers\n  <https://github.com/openai/universe/blob/master/universe/__init__.py>`__\n  all the Universe environments.\n\n.. code:: python\n\n  import gym\n  import universe # register the universe environments\n\n* Next, we create the environment instance. Behind the scenes, ``gym``\n  looks up the `registration\n  <https://github.com/openai/universe/blob/master/universe/__init__.py>`__\n  for ``flashgames.DuskDrive-v0``, and instantiates a `VNCEnv\n  <https://github.com/openai/universe/blob/master/universe/envs/vnc_env.py#L88>`__\n  object which has been `wrapped\n  <https://github.com/openai/universe/blob/master/universe/wrappers/__init__.py#L42>`__\n  to add a few useful diagnostics and utilities. The ``VNCEnv`` object\n  is the *client* part of the environment, and it is not yet connected\n  to a *remote*.\n\n.. code:: python\n\n  env = gym.make('flashgames.DuskDrive-v0')\n\n* The call to ``configure()`` connects the client to a remote\n  environment server. When called with ``configure(remotes=1)``,\n  Universe will automatically create a Docker image running locally on\n  your computer. The local client connects to the remote using VNC.\n  (More information on client-remote communication can be found in the\n  page on `universe internal communication protocols\n  <doc/protocols.rst>`__. More on configuring remotes is at `remotes <doc/remotes.rst>`__.)\n\n.. code:: python\n\n  env.configure(remotes=1)\n\n* When starting a new environment, you call ``env.reset()``. Universe\n  environments run in real-time, rather than stepping synchronously\n  with the agent's actions, so ``reset`` is asynchronous and returns\n  immediately. Since the environment will not have waited to finish\n  connecting to the VNC server before returning, the initial observations\n  from ``reset`` will be ``None`` to indicate that there is\n  not yet a valid observation.\n\n  Similarly, the environment keeps running in the background even\n  if the agent does not call ``env.step()``.  This means that an agent\n  that successfully learns from a Universe environment cannot take\n  \"thinking breaks\":  it must keep sending actions to the environment at all times.\n\n  Additionally, Universe introduces the *vectorized* Gym\n  API. Rather than controlling a single environment at a time, the agent\n  can control a fixed-size vector of ``n`` environments, each with its\n  own remote. The return value from ``reset`` is therefore a *vector*\n  of observations. For more information, see the separate page on\n  `environment semantics <doc/env_semantics.rst>`__)\n\n.. code:: python\n\n  observation_n = env.reset()\n\n* At each ``step()`` call, the agent submits a vector of actions; one for\n  each environment instance it is controlling. Each VNC action is a\n  list of events; above, each action is the single event \"press the\n  ``ArrowUp`` key\". The agent could press and release the key in one\n  action by instead submitting ``[('KeyEvent', 'ArrowUp', True),\n  ('KeyEvent', 'ArrowUp', False)]`` for each observation.\n\n  In fact, the agent could largely have the same effect by just\n  submitting ``('KeyEvent', 'ArrowUp', True)`` once and then calling\n  ``env.step([[] for ob in observation_n])`` thereafter, without ever\n  releasing the key using ``('KeyEvent', 'ArrowUp', False)``. The\n  browser running inside the remote would continue to statefully\n  represent the arrow key as being pressed. Sending other unrelated\n  keypresses would not disrupt the up arrow keypress; only explicitly\n  releasing the key would cancel it.  There's one slight subtlety:\n  when the episode resets, the browser will reset, and will forget\n  about the keypress; you'd need to submit a new ``ArrowUp`` at the\n  start of each episode.\n\n.. code:: python\n\n  action_n = [[('KeyEvent', 'ArrowUp', True)] for ob in observation_n]\n\n* After we submit the action to the environment and render one frame,\n  ``step()`` returns a list of *observations*, a list of *rewards*, a\n  list of *\"done\" booleans* indicating whether the episode has ended,\n  and then finally an *info dictionary* of the form ``{'n': [{},\n  ...]}``, in which you can access the info for environment ``i`` as\n  ``info['n'][i]``.\n\n  Each environment's ``info`` message contains useful diagnostic\n  information, including latency data, client and remote timings,\n  VNC update counts, and reward message counts.\n\n.. code:: python\n\n    observation_n, reward_n, done_n, info = env.step(action_n)\n    env.render()\n\n* We call ``step`` in what looks like a busy loop. In reality, there\n  is a `Throttle\n  <https://github.com/openai/universe/blob/master/universe/wrappers/__init__.py#L18>`__\n  wrapper on the client which defaults to a target frame rate of 60fps, or one\n  frame every 16.7ms. If you call it more frequently than that,\n  ``step`` will `sleep\n  <https://github.com/openai/universe/blob/master/universe/wrappers/throttle.py>`__\n  with any leftover time.\n\n\nTesting\n=======\n\nWe are using `pytest <http://doc.pytest.org/en/latest/>`__ for tests. You can run them via:\n\n.. code:: shell\n\n    pytest\n\nRun ``pytest --help`` for useful options, such as ``pytest -s`` (disables output capture) or ``pytest -k <expression>`` (runs only specific tests).\n\nAdditional documentation\n========================\n\nMore documentation not covered in this README can be found in the\n`doc folder <doc>`__ of this repository.\n\nGetting help\n============\n\nIf you encounter a problem that is not addressed in this README page\nor in the `extra docs <doc>`__, then try our wiki page of `solutions\nto common problems\n<https://github.com/openai/universe/wiki/Solutions-to-common-problems>`__ -\nand add to it if your solution isn't there!\n\nYou can also search through the `issues\n<https://github.com/openai/universe/issues?utf8=%E2%9C%93&q=is%3Aissue>`__\non this repository and our `discussion board\n<https://discuss.openai.com/c/Universe>`__ to see if another user has posted\nabout the same problem or to ask for help from the community.\n\nIf you still can't solve your problem after trying all of the above\nsteps, please post an issue on this repository.\n\nWhat's next?\n============\n\n* Get started training RL algorithms! You can try out the `Universe Starter Agent <https://github.com/openai/universe-starter-agent>`_, an implementation of the `A3C algorithm <https://arxiv.org/abs/1602.01783>`_ that can solve several VNC environments.\n\n* For more information on how to manage remotes, see the separate documentation page on `remotes <doc/remotes.rst>`__.\n\n* Sign up for a `beta <https://docs.google.com/forms/d/e/1FAIpQLScAiW-kIS0mz6hdzzFZJJFlXlicDvQs1TX9XMEkipNwjV5VlA/viewform>`_ to get early access to upcoming Universe releases, such as tools to integrate new Universe environments or a dataset of recorded human demonstrations.\n\n\nChangelog\n---------\n- 2017-02-08: The old location for wrappers.SafeActionSpace has been moved to wrappers.experimental.SafeActionSpace. SoftmaxClickMouse has also been moved to wrappers.experimental.SoftmaxClickMouse\n- 2017-01-08: The wrappers.SafeActionSpace has been moved to wrappers.experimental.SafeActionSpace. The old location will remain with a deprecation warning until 2017-02-08.\n- 2016-12-27: BACKWARDS INCOMPATIBILITY: The gym monitor is now a\n  wrapper. Rather than starting monitoring as\n  `env.monitor.start(directory)`, envs are now wrapped as follows:\n  `env = wrappers.Monitor(env, directory)`. This change is on master\n  and will be released with 0.21.0.\n"
  },
  {
    "path": "doc/env_semantics.rst",
    "content": "Environment semantics\n*********************\n  \nReal-time environments\n======================\n\nUniverse environments differ from other Gym environments in that the\nenvironment keeps running in real-time, even when the agent does not\ncall ``step``. This has a few important implications:\n\n* Actions and observations can no longer be considered to\n  occur on a \"clock tick\".\n* An explicit call to ``reset`` is asynchronous and returns\n  immediately, even though the environment has not yet finished\n  resetting. (If you would prefer the ``reset`` call to block\n  until the reset has finished, you can wrap\n  the client-side environment with a `BlockingReset <https://github.com/openai/universe/blob/master/universe/wrappers/blocking_reset.py>`__ wrapper)\n* Since the environment will not have waited to finish\n  connecting to the VNC server before returning, the initial return\n  values from ``reset`` will be ``None`` to indicate that there is\n  not yet a valid observation.\n* An agent that successfully learns from a Universe environment cannot\n  take \"thinking breaks\": it must keep sending actions to the\n  environment at all times.\n* Lag and latency play a major role in your agent's ability to\n  successfully learn in a given environment. The latency and profiling\n  numbers returned in the ``info`` dictionary can provide important\n  information for training.\n\nVectorized API\n==============\n\nThe vectorized Gym API allows a single client-side environment to\ncontrol a vector of remotes. The main difference with the\nnon-vectorized Gym API is that individual environments will\nautomatically reset upon reaching the end of an episode. (An episode\nis defined as ending when an agent has concretely succeeded or failed\nat the task, such as after clearing a level of a game, or losing the\ngame. Some environments without clearly delineated success and\nfailure conditions may not have episodes.)\n\nThere are two API methods, ``reset`` and ``step``. The semantics are:\n\n- ``reset`` takes no arguments and returns a vector of observations:\n\n.. code:: python\n\n  observation_n = env.reset()\n\n- ``step`` consumes a vector of actions, and returns a vector of\n  observations, vector of rewards, vector of done booleans, and an\n  info dictionary. The info dictionary has an ``n`` key, which\n  contains a vector of infos specific to each env:\n\n.. code:: python\n\n  observation_n, reward_n, done_n, info = env.step(action_n)\n  # len(info['n']) == len(observation_n)\n\nSome important notes:\n\n- At any given moment, some of the environments may be\n  resetting. Resetting environments will have a ``None`` value for\n  their observation. For example, an ``observation_n`` of ``[None,\n  {'vision': ...}, {'vision': ...}]`` indicates that the environment\n  at index 0 is resetting.\n- When an index returns ``done=True``, the corresponding environment\n  will automatically start resetting.\n- The user must call ``reset`` once before calling ``step``; undefined\n  behavior will result if ``reset`` is not called. Further ``reset``\n  calls are allowed, but generally are used only if the environment has\n  been idle for a while (such as with periodic evaluation), or when it\n  is important to start at the beginning \n\nVersioning\n==========\n\nThe remote is versioned and has fixed semantics, assuming sufficient\ncompute resources are applied (i.e. if you don't have enough CPU, your\nflash environments will likely behave differently). The client's exact\nsemantics will depend on the version of universe you have installed,\nand you should track the version of that together with the rest of\nyour agent code.\n\n"
  },
  {
    "path": "doc/protocols.rst",
    "content": "Universe internal communication protocols\n*****************************************\n\nNetwork architecture\n====================\n\nA Universe environment consists of two components that run in\nseparate processes and communicate over the network.  The agent's\nmachine runs the environment **client** code, which connects\nto the **remote** environment server.\n\nMany related environments can be served from the same **runtime**,\nusually packaged as a Docker container. For example, all the flash\ngames in Universe are served from the ``flashgames`` runtime, which\nconsists of the ``quay.io/openai/universe.flashgames`` Docker image\nand runs with its corresponding set of configuration flags.\n\nEach remote exposes two ports:\n\n- A VNC port (5900 by default). The remote runs an off-the-shelf VNC\n  server (usually TigerVNC), so that users can connect their own\n  VNC viewers to the environments for interactive use. VNC delivers\n  pixel observations to the agent, and the agent submits keyboard and\n  mouse inputs over VNC as well.\n\n- A rewarder port (15900 by default). The rewarder protocol is a\n  bi-directional JSON protocol runs over WebSockets. The rewarder\n  channel provides more than just a reward signal; in addition, it allows the\n  agent to submit control commands (such as to indicating which of\n  the available environments should be active for a given runtime) and\n  to receive structured information from the environment (such as latencies\n  and performance timings).\n\nVNC system and Remote Frame Buffer protocol\n===========================================\n \nKeyboard and mouse actions and pixel observations are sent between the\nclient and the remote using the `VNC\n<https://en.wikipedia.org/wiki/Virtual_Network_Computing>`__\nsystem. VNC is a pervasive standard for remote desktop operation. Many\nimplementations of VNC are available online, including VNC viewers\nthat make it easy to observe a running agent.\n\nTo achieve the performance we needed in order to train an\nagent on dozens of simultaneous remote environments at 60FPS, we wrote a\n`custom client-side VNC driver <https://github.com/openai/go-vncdriver>`__\nin go. The remote VNC server that we use in most of our runtimes is `TigerVNC <http://tigervnc.org/>`__\n\nMore information about the Remote Frame Buffer protocol can be found\nin the official `IETF RFC <https://tools.ietf.org/html/rfc6143>`__\nspec, and in other tutorials elsewhere on the internet.\n\nRewarder protocol\n=================\n\nThe Rewarder protocol is a Universe-specific bi-directional JSON\nprotocol run over WebSockets. In addition to the actions and\nobservations provided by the VNC connection, the rewarder connection\nallows the agent to submit control commands to the environment, and to\nreceive rewards and other informational messages. This section details\nthe format of the Rewarder protocol.\n\nMessage format\n--------------\n\nEach message is serialized as a JSON object with the following\nstructure:\n\n.. code::\n\t\t  \n    {\n      \"method\": [string],\n      \"headers\": [object],\n      \"body\": [object]\n    }\n\nFor example, a ``v0.env.describe`` message might look as follows:\n\n.. code::\n\n    {\n      \"method\": \"v0.env.describe\",\n      \"headers\": {\n        \"sent_at\": 1479493678.1937322617,\n        \"message_id\": 15,\n        \"episode_id\": \"1.2\",\n      },\n      \"body\": {\n        \"env_id\": \"internet.SlitherIO-v0\",\n        \"env_state\": \"running\",\n        \"fps\": 60\n      }\n    }\n\n\nEach message should have a unique ``message_id`` header and a ``sent_at``\nheader (which should be the current UNIX timestamp with at least\nmillisecond precision).\n\nServer to client messages\n-------------------------\n\nenv.describe\n~~~~~~~~~~~~\n\n.. code:: \n\t\t  \n    {\n      \"method\": \"v0.env.describe\",\n      \"headers\": {\n        \"sent_at\": 1479493678.1937322617,\n        \"message_id\": 15,\n        \"episode_id\": \"1.2\",\n      },\n      \"body\": {\n        \"env_id\": \"internet.SlitherIO-v0\",\n        \"env_state\": \"running\",\n      }\n    }\n\nenv.reward\n~~~~~~~~~~\n\n.. code::\n\t\t  \n    {\n      \"method\": \"v0.env.reward\",\n      \"headers\": {\n        \"sent_at\": 1479493678.1937322617,\n        \"message_id\": 15,\n        \"episode_id\": \"1.2\",\n      },\n      \"body\": {\n        \"reward\": -3,\n        \"done\": False,\n    \t\"info\": {},\n      }\n    }\n\nenv.text\n~~~~~~~~\n\n.. code::\n\t\t  \n    {\n      \"method\": \"v0.env.text\",\n      \"headers\": {\n        \"sent_at\": 1479493678.1937322617,\n        \"message_id\": 15,\n        \"episode_id\": \"1.2\",\n      },\n      \"body\": {\n        \"text\": \"this is some text\"\n      }\n    }\n\nenv.observation\n~~~~~~~~~~~~~~~\n\n.. code::\n\t\t  \n    {\n      \"method\": \"v0.env.observation\",\n      \"headers\": {\n        \"sent_at\": 1479493678.1937322617,\n        \"message_id\": 15,\n        \"episode_id\": \"1.2\"\n      },\n      \"body\": {\n        \"observation\": [0.12, 0.51, 2, 12]\n      }\n    }\n\nconnection.close\n~~~~~~~~~~~~~~~~\n\n.. code::\n\t\t  \n    {\n      \"method\": \"v0.connection.close\",\n      \"headers\": {\n        \"sent_at\": 1479493678.1937322617,\n        \"message_id\": 15\n      },\n      \"body\": {\n        \"message\": \"Disconnected since time limit reached\"\n      }\n    }\n\nreply.error\n~~~~~~~~~~~\n\n.. code::\n\t\t  \n    {\n      \"method\": \"v0.reply.error\",\n      \"headers\": {\n        \"sent_at\": 1479493678.1937322617,\n        \"message_id\": 15,\n    \t\"parent_message_id\": \"26\"\n      },\n      \"body\": {\n        \"message\": \"No such environment: llama\"\n      }\n    }\n\nreply.env.reset\n~~~~~~~~~~~~~~~\n\n.. code::\n\t\t  \n    {\n      \"method\": \"v0.reply.env.reset\",\n      \"headers\": {\n        \"sent_at\": 1479493678.1937322617,\n        \"message_id\": 15,\n    \t\"parent_message_id\": \"26\",\n    \t\"episode_id\": \"1.2\"\n    \t\n      },\n      \"body\": {}\n    }\n    \nreply.control.ping\n~~~~~~~~~~~~~~~~~~\n\n.. code::\n\t\t  \n    {\n      \"method\": \"v0.reply.control.ping\",\n      \"headers\": {\n        \"sent_at\": 1479493678.1937322617,\n        \"message_id\": 15,\n    \t\"parent_message_id\": \"26\"\n      },\n      \"body\": {}\n    }\n\nClient to server messages\n-------------------------\n\nagent.action\n~~~~~~~~~~~~\n\n.. code::\n\t\t  \n    {\n      \"method\": \"v0.agent.action\",\n      \"headers\": {\n        \"sent_at\": 1479493678.1937322617,\n        \"message_id\": 15\n      },\n      \"body\": {\n        \"action: [[\"JoystickAxisXEvent\", 0.1],\n                  [\"JoystickAxisZEvent\", 0.1]]\n      }\n    }\n\nenv.reset\n~~~~~~~~~\n\n.. code::\n\t\t  \n    {\n      \"method\": \"v0.env.reset\",\n      \"headers\": {\n        \"sent_at\": 1479493678.1937322617,\n        \"message_id\": 15\n      },\n      \"body\": {\n        \"env_id': \"flashgames.DuskDrive-v0\"\n      }\n    }\n\ncontrol.ping\n~~~~~~~~~~~~\n\n.. code::\n\t\t  \n    {\n      \"method\": \"v0.control.ping\",\n      \"headers\": {\n        \"sent_at\": 1479493678.1937322617,\n        \"message_id\": 15\n      },\n      \"body\": {}\n    }\n"
  },
  {
    "path": "doc/remotes.rst",
    "content": "Remotes\n*******\n\nSince the remote part of the environment runs in its own server\nprocess, managing remotes is an important task. The remote can run\nanywhere - locally, or in the cloud. This section will explain\nthree ways to set up remotes.\n\n.. contents:: **Contents of this document**\n   :depth: 2\n\nDocker installation\n===================\n\nThe majority of the remotes for Universe environments run inside\nDocker containers, so the first step to running your own remotes is\nto `install Docker <https://docs.docker.com/engine/installation/>`__ (on\nOSX, we recommend `Docker for Mac\n<https://docs.docker.com/docker-for-mac/>`__). You should be able to\nrun ``docker ps`` and get something like this:\n\n.. code:: shell\n\n     $ docker ps\n     CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES\n\n\nHow to start a remote\n=====================\n\nThere are currently three ways to start a remote:\n\n- Create an **automatic local remote** using ``env.configure(remotes=1)``.\n  In this case, ``universe`` automatically creates a remote locally by spinning\n  up a docker container for you.\n\n- Create a **manual remote** by spinning up your own Docker container,\n  locally or on a server you control.\n\n- Create a **starter cluster** in AWS, which will automatically provide you\n  with cloud-hosted remotes.\n\n\nAutomatic local remotes\n-----------------------\n\nTo create an **automatic local remote**, call\n``env.configure(remotes=1)`` (or ``4`` if you'd like 4 remotes).\nThis will download the ``quay.io/openai/universe.flashgames`` docker\ncontainer and start 1 copy of it locally.\n\n.. code:: python\n\n    import gym\n    import universe # register the universe environments\n\n    env = gym.make('flashgames.DuskDrive-v0')\n    env.configure(remotes=1) # downloads and starts a flashgames runtime\n    observation_n = env.reset()\n\n    while True:\n            action_n = [[('KeyEvent', 'ArrowUp', True)] for ob in observation_n] # your agent here\n            observation_n, reward_n, done_n, info = env.step(action_n)\n            env.render()\n\n\nAgents inside Docker\n~~~~~~~~~~~~~~~~~~~~\nIf you're running your agent inside a Docker container, it can still create automatic remotes by connecting\nto the docker daemon on the host. To do this, mount the docker binary and socket inside the agent container like this:\n\n.. code:: shell\n\n    $ docker run --privileged \\\n        -v /usr/bin/docker:/usr/bin/docker \\\n        -v /root/.docker:/root/.docker \\\n        -v /var/run/docker.sock:/var/run/docker.sock \\\n        -e DOCKER_NET_HOST=172.17.0.1 \\\n        ... \\\n        my/agent:latest\n\n\nThe Universe remote will use ``$DOCKER_NET_HOST`` when connecting to the VNC and rewarder ports.\n\n\nManual remotes\n--------------\n\nTo create a **manual remote**, start the remote Docker container\nmanually on the command line. Remotes can run locally on the same machine as\nthe client, or you can start them on servers you control.\n\nTo find the appropriate Docker command-line invocation for each\nenvironment, you can look at where we `register\n<https://github.com/openai/universe/blob/master/universe/runtimes/__init__.py>`__\nthe runtime for each environment. The command is also printed out\nconveniently when you run with ``remotes=1``:\n\n.. code:: shell\n\n    [2016-11-25 23:51:04,223] [0] Creating container:\n\timage=quay.io/openai/universe.flashgames:0.19.19. Run the same thing by hand as:\n\tdocker run -p 10000:5900 -p 10001:15900 --cap-add NET_ADMIN --cap-add SYS_ADMIN\n\t--ipc host quay.io/openai/universe.flashgames:0.19.19\n\nOnce you have started the docker container, configure your agent to\n  connect to the VNC server (port 5900 by default) and the reward/info channel\n  (port 15900 by default):\n\n.. code:: python\n\n    env.configure(remotes='vnc://localhost:5900+15900')\n\nTo connect manually to multiple remotes, separate them by commas:\n\n.. code:: python\n\n    env.configure(remotes='vnc://localhost:5900+15900,vnc://localhost:5901+15901')\n\nIf your docker container is running on a server rather than on localhost,\njust plug in the appropriate URL or IP address:\n\n.. code:: python\n\n    env.configure(remotes='vnc://your.host.here:5900+15900')\n\nVNC compression settings\n-----------------------------------------------\n\nThe VNC connection supports multiple compression settings that control the tradeoff\nbetween a fast but highly compressed, low quality data stream and slow, uncompressed\ndata stream. These can be configured by using the ``vnc_kwargs`` argument to\n``env.configure``. The default arguments are:\n\n.. code:: python\n\n    env.configure(vnc_kwargs={'encoding':'tight', 'fine_quality_level':50, 'subsample_level':2})\n\nHere, ``tight`` is a lossy encoding that uses JPEG for compression. We also support ``zrle`` instead, which is lossless.\nThe ``fine_quality_level`` controls the compression strength from high compression / low quality (0) to low compression / high quality (100).\nFor ``subsample_level``, 0 is highest quality, 2 is low quality and 3 is greyscale. You can investigate the effects\nof many of these options on the visual fidelity by connecting to an environment using TurboVNC, which allows you to\ntune these settings in the user interface.\n\nNote that the codecs always operate on deltas of the screen, so if large portions of your screen are not changing then\nyou might be able to afford higher quality settings. Conversely, if you're playing a racing game that takes up a large\nportion of the screen you should be more worried about bandwidth. The call to ``step`` is asynchronous with respect to\nnew frames arriving, so if the connection is too slow the environments will lag.\n\nAutomatic cloud-hosted remotes: starter cluster\n-----------------------------------------------\n\nIf you have an AWS account, you can spin up a **starter Docker cluster** to host your own remotes. First click the \"Launch Stack\" button and follow the steps on the AWS console to deploy your cluster.\n\n  .. image:: https://s3.amazonaws.com/cloudformation-examples/cloudformation-launch-stack.png\n     :target: https://console.aws.amazon.com/cloudformation/home#/stacks/new?stackName=OpenAI-Universe&templateURL=thttps://s3-us-west-2.amazonaws.com/openai-public/universe/starter-cluster-cf-0.1.0.json\n\nOnce your stack on AWS is ready, run `starter-cluster` to start your environments\n\n  .. code:: shell\n\n    $ example/starter-cluster/starter-cluster start -s [stack-name] -i [path-to-ssh-key] \\\n        --runtime [universe-runtime] -n [number-of-envs]\n\nor example, the follow will start two flashgames remotes:\n\n  .. code:: shell\n\n    $ pip install -r bin/starter-cluster-requirements.txt\n    $ bin/starter-cluster -v start -s OpenAI-Universe -i my-ec2-key.pem -r flashgames -n 2\n    Creating network \"flashgames_default\" with the default driver\n    Pulling flashgames-0 (quay.io/openai/universe.flashgames:0.19.36)...\n    ip-172-33-1-4: Pulling quay.io/openai/universe.flashgames:0.19.36... : downloaded\n    ip-172-33-28-242: Pulling quay.io/openai/universe.flashgames:0.19.36... : downloaded\n    Creating flashgames_flashgames-0_1\n    Creating flashgames_flashgames-1_1\n    Environments started.\n    Remotes:\n      vnc://54.245.154.123:5013+5015\n      vnc://54.245.154.123:5006+5008\n\nNow you can pass the IP address and ports for your remotes to your agent,\nas was described in the previous section on manual remotes. For example:\n\n  .. code:: shell\n\n    $ python bin/random_agent.py -e flashgames.DuskDrive-v0 -r vnc://54.245.154.123:5013+5015,54.245.154.123:5006+5008\n\nRunning ``bin/starter-cluster start`` again will restart your remotes. To stop them, run:\n\n  .. code:: shell\n\n    $ bin/starter-cluster stop -s OpenAI-Universe -i my-ec2-key.pem -r flashgames\n    Stopping flashgames_flashgames-1_1 ... done\n    Stopping flashgames_flashgames-0_1 ... done\n    Removing flashgames_flashgames-1_1 ... done\n    Removing flashgames_flashgames-0_1 ... done\n    Removing network flashgames_default\n    Environments stopped.\n\nRegion\n~~~~~~\n\nBy default, starter cluster remotes are spawned in AWS's ``us-west-2``\nregion. In our experience, the latencies of training over the public\ninternet are acceptable, but if you have trouble, it may make sense to\ntry running your agent code on an AWS server in the same region as the\nremote.\n\nScaling Up\n~~~~~~~~~~\n\nIf you encounter the following\n\n.. code:: shell\n\n  $ bin/starter-cluster -v start -s OpenAI-Universe -i my-ec2-key.pem -r flashgames   -n 2\n    Creating network \"flashgames_default\" with the default driver\n    Pulling flashgames-0 (quay.io/openai/universe.flashgames:0.19.36)...\n    ip-172-33-1-4: Pulling quay.io/openai/universe.flashgames:0.19.36... : downloaded\n    ip-172-33-28-242: Pulling quay.io/openai/universe.flashgames:0.19.36... :   downloaded\n    ip-172-33-9-51: Pulling quay.io/openai/universe.flashgames:0.19.36... :   downloaded\n    ip-172-33-27-141: Pulling quay.io/openai/universe.flashgames:0.19.36... :   downloaded\n    Creating flashgames_flashgames-2_1\n    Creating flashgames_flashgames-3_1\n    Creating flashgames_flashgames-0_1\n    Creating flashgames_flashgames-1_1\n    Creating flashgames_flashgames-4_1\n\n    ERROR: for flashgames-0  no resources available to schedule container\n\nthen it means you've run out of computing resources on your cluster, and\nhave to add more worker nodes. You can do so by going to the AWS\nCloudformation console:\n\n1. Select your stack\n2. Click \"Update Stack\" in the \"Actions\" dropdown\n3. Hit \"Next\" on the \"Select Template\" page\n4. Input the new swarm size and hit \"Next\"\n5. Hit \"Next\" on the \"Options\" page\n6. Hit \"Update\" on the \"Review\" page\n\n\nReusing remotes\n===============\n\nIf a consistent ``client_id`` is supplied to ``configure()``, then the\nclient will attempt to reuse the same remote for the new environment\nrather than spinning up a new one each time.\n\nSwitching between environments in the same *runtime*\n(i.e. environments that run on the same underlying docker container)\nis possible without creating a new remote; however, if you want to\nswitch to an environment in a different runtime, you will need to create\na new remote. For example, you can switch between\n``flashgames.DuskDrive-v0`` and ``flashgames.NeonRace-v0`` without\nstarting a new remote, because they both run in the ``flashgames``\nruntime, but if you want to switch to ``wob.mini.UseColorwheel2-v0``\nyou cannot re-use the same remote.\n\nThe configuration for the runtimes is defined in\n`universe/runtimes/__init__.py <https://github.com/openai/universe/blob/master/universe/runtimes/__init__.py>`__,\nand the specific version number tags for the corresponding Docker\nimages are specified in\n`runtimes.yml <https://github.com/openai/universe/blob/master/universe/runtimes.yml>`__.\n"
  },
  {
    "path": "example/diagnostic-agent/diagnostic-agent.py",
    "content": "#!/usr/bin/env python\nimport argparse\nimport logging\nimport time\n\nimport gym\nimport numpy as np\nimport universe\nfrom universe import pyprofile, wrappers, spaces\nfrom gym import wrappers as gym_wrappers\n\n# if not os.getenv(\"PYPROFILE_FREQUENCY\"):\n#     pyprofile.profile.print_frequency = 5\nfrom universe import vectorized\n\nlogger = logging.getLogger()\n\nCHROME_X_OFFSET = 18\nCHROME_Y_OFFSET = 84\n\nclass NoopSpace(gym.Space):\n    \"\"\" Null action space \"\"\"\n    def sample(self, seed=0):\n        return []\n    def contains(self, x):\n        return x == []\n\nclass ForwardSpace(gym.Space):\n    \"\"\" Only move forward action space \"\"\"\n    def __init__(self, key='w'):\n        self.key = [spaces.KeyEvent.by_name(key, down=True)]\n    def sample(self, seed=0):\n        return self.key\n    def contains(self, x):\n        return x == self.key\n\n# The world's simplest agent!\nclass RandomAgent(object):\n    \"\"\"\n    Example usage:\n\n        bin/random_agent.py -e gym-core.Pong-v3 --remote localhost:5900+15900\n\n    \"\"\"\n    def __init__(self, action_space, n, vectorized):\n        self.action_space = action_space\n        self.n = n\n        self.vectorized = vectorized\n\n    def __call__(self, observation, reward, done):\n        if self.vectorized:\n            return [self.action_space.sample() for _ in range(self.n)]\n        else:\n            return self.action_space.sample()\n\nif __name__ == '__main__':\n    # You can optionally set up the logger. Also fine to set the level\n    # to logging.DEBUG or logging.WARN if you want to change the\n    # amount of output.\n    logger.setLevel(logging.INFO)\n    universe.configure_logging()\n\n    # Actions this agent will take, 'random' is the default\n    action_choices = ['random', 'noop', 'forward', 'click']\n\n    parser = argparse.ArgumentParser(description=None)\n    parser.add_argument('-e', '--env_id', default='gym-core.Pong-v3', help='Which environment to run on.')\n    parser.add_argument('-m', '--monitor', action='store_true', help='Whether to activate the monitor.')\n    parser.add_argument('-r', '--remote', default=None, help='The number of environments to create (e.g. -r 20), or the address of pre-existing VNC servers and rewarders to use (e.g. -r vnc://localhost:5900+15900,localhost:5901+15901)')\n    parser.add_argument('-c', '--client-id', default='0', help='Set client id.')\n    parser.add_argument('-v', '--verbose', action='count', dest='verbosity', default=0, help='Set verbosity.')\n    parser.add_argument('-R', '--no-render', action='store_true', help='Do not render the environment locally.')\n    parser.add_argument('-A', '--actions', choices=action_choices, default='random', help='How to sample actions to send to remote environment')\n    parser.add_argument('-d', '--docker-image', help='Force a version of the docker_image used with --remote <int>. e.g --docker-image quay.io/openai/universe.gym-core:0.3')\n    parser.add_argument('-s', '--reuse', default=False, action='store_true', help='Reuse existing Docker container if present, and leave this one running after (only for \"-r n\")')\n    parser.add_argument('-f', '--fps', default=60., type=float, help='Desired frames per second')\n    parser.add_argument('-N', '--max-steps', type=int, default=10**7, help='Maximum number of steps to take')\n    parser.add_argument('-E', '--max-episodes', type=int, default=10**7, help='Maximum number of episodes')\n    parser.add_argument('-T', '--start-timeout', type=int, default=None, help='Rewarder session connection timeout (seconds)')\n    args = parser.parse_args()\n\n    logging.getLogger('gym').setLevel(logging.NOTSET)\n    logging.getLogger('universe').setLevel(logging.NOTSET)\n    if args.verbosity == 0:\n        logger.setLevel(logging.INFO)\n    elif args.verbosity >= 1:\n        logger.setLevel(logging.DEBUG)\n\n    if args.env_id is not None:\n        env = gym.make(args.env_id)\n    else:\n        env = wrappers.WrappedVNCEnv()\n    # env = wrappers.BlockingReset(env)\n    if not isinstance(env, wrappers.GymCoreAction):\n        # The GymCoreSyncEnv's try to mimic their core counterparts,\n        # and thus came pre-wrapped wth an action space\n        # translator. Everything else probably wants a SafeActionSpace\n        # wrapper to shield them from random-agent clicking around\n        # everywhere.\n        env = wrappers.experimental.SafeActionSpace(env)\n    else:\n        # Only gym-core are seedable\n        env.seed([0])\n    env = wrappers.Logger(env)\n\n    if args.monitor:\n        env = wrappers.Monitor(env, '/tmp/vnc_random_agent', force=True)\n\n    if args.actions == 'random':\n        action_space = env.action_space\n    elif args.actions == 'noop':\n        action_space = NoopSpace()\n    elif args.actions == 'forward':\n        action_space = ForwardSpace()\n    elif args.actions == 'click':\n        spec = universe.runtime_spec('flashgames').server_registry[args.env_id]\n        height = spec[\"height\"]\n        width = spec[\"width\"]\n        noclick_regions = [r['coordinates'] for r in spec['regions'] if r['type'] == 'noclick'] if spec.get('regions') else []\n        active_region = (CHROME_X_OFFSET, CHROME_Y_OFFSET, CHROME_X_OFFSET + width, CHROME_Y_OFFSET + height)\n        env = wrappers.SoftmaxClickMouse(env, active_region=active_region, noclick_regions=noclick_regions)\n        action_space = env.action_space\n    else:\n        logger.error(\"Invalid action choice: {}\".format(args.actions))\n        exit(1)\n\n    env.configure(\n        fps=args.fps,\n        # print_frequency=None,\n        # ignore_clock_skew=True,\n        remotes=args.remote,\n        client_id=args.client_id,\n        start_timeout=args.start_timeout,\n\n        # remotes=remote, docker_image=args.docker_image, reuse=args.reuse, ignore_clock_skew=True,\n        # vnc_session_driver='go', vnc_session_kwargs={\n        #     'compress_level': 0,\n        # },\n\n        vnc_driver='go', vnc_kwargs={\n            # 'encoding': 'tight', 'compress_level': 0, 'fine_quality_level': 50, 'subsample_level': 2,\n            'encoding': 'tight', 'compress_level': 0, 'fine_quality_level': 50, 'subsample_level': 0, 'quality_level': 5,\n        },\n    )\n\n    agent = RandomAgent(action_space, n=env.n, vectorized=env.metadata['runtime.vectorized'])\n\n    render = not args.no_render\n    observation_n = env.reset()\n    target = time.time()\n    reward_n = [0] * env.n\n    done_n = [False] * env.n\n\n    observation_count = np.zeros(env.n)\n    episode_length = np.zeros(env.n)\n    episode_score = np.zeros(env.n)\n\n    episodes_completed = 0\n\n    for i in range(args.max_steps):\n        # print(observation_n)\n        # user_input.handle_events()\n\n        if render:\n            # Note the first time you call render, it'll be relatively\n            # slow and you'll have some aggregated rewards. We could\n            # open the render() window before `reset()`, but that's\n            # confusing since it pops up a black window for the\n            # duration of the reset.\n            env.render()\n\n        action_n = agent(observation_n, reward_n, done_n)\n\n        # Take an action\n        with pyprofile.push('env.step'):\n            observation_n, reward_n, done_n, info = env.step(action_n)\n\n        episode_length += 1\n        if not all(r is None for r in reward_n): # checks if we connected the rewarder\n            episode_score += np.array(reward_n)\n        for i, ob in enumerate(observation_n):\n            if ob is not None and (not isinstance(ob, dict) or ob['vision'] is not None):\n                observation_count[i] += 1\n\n        scores = {}\n        lengths = {}\n        observations = {}\n        for i, done in enumerate(done_n):\n            if not done:\n                continue\n            scores[i] = episode_score[i]\n            lengths[i] = episode_length[i]\n            observations[i] = observation_count[i]\n\n            episode_score[i] = 0\n            episode_length[i] = 0\n            observation_count[i] = 0\n        if len(scores) > 0:\n            logger.info('Total for completed episodes: reward=%s length=%s observations=%s', scores, lengths, observations)\n\n        errored = [i for i, info_i in enumerate(info['n']) if 'error' in info_i]\n        if errored:\n            logger.info('had errored indexes: %s: %s', errored, info)\n\n        episodes_completed += len([d for d in done_n if d])\n        if episodes_completed >= args.max_episodes:\n            break\n\n        # if info.get('n') and info['n'][0].get('env_status.instruction'):\n        #     logger.info('received instruction = %s', info['n'][0]['env_status.instruction'])\n\n        # if observation_n[0].get('text'):\n        #     logger.info('message_n=%s', [observation['text'] for observation in observation_n])\n\n        # if any(done_n) or any(r != 0.0 and r is not None for r in reward_n):\n        #     logger.info('reward_n=%s done_n=%s info=%s', reward_n, done_n, info)\n\n    # We're done! clean up\n    env.close()\n"
  },
  {
    "path": "example/random-agent/random-agent.py",
    "content": "#!/usr/bin/env python\nimport argparse\nimport logging\nimport sys\n\nimport gym\nimport universe # register the universe environments\n\nfrom universe import wrappers\n\nlogger = logging.getLogger()\n\ndef main():\n    parser = argparse.ArgumentParser(description=None)\n    parser.add_argument('-v', '--verbose', action='count', dest='verbosity', default=0, help='Set verbosity.')\n    args = parser.parse_args()\n\n    if args.verbosity == 0:\n        logger.setLevel(logging.INFO)\n    elif args.verbosity >= 1:\n        logger.setLevel(logging.DEBUG)\n\n\n    env = gym.make('flashgames.NeonRace-v0')\n    env.configure(remotes=1)  # automatically creates a local docker container\n    \n    # Restrict the valid random actions. (Try removing this and see\n    # what happens when the agent is given full control of the\n    # keyboard/mouse.)\n    env = wrappers.experimental.SafeActionSpace(env)\n    observation_n = env.reset()\n\n    while True:\n        # your agent here\n        #\n        # Try sending this instead of a random action: ('KeyEvent', 'ArrowUp', True)\n        action_n = [env.action_space.sample() for ob in observation_n]\n        observation_n, reward_n, done_n, info = env.step(action_n)\n        env.render()\n\n    return 0\n\nif __name__ == '__main__':\n    sys.exit(main())\n"
  },
  {
    "path": "example/recorders/botaction_recorder.py",
    "content": "#!/usr/bin/env python\n\"\"\"\n  This is a small server that accepts connections on a websocket port and writes it to a file.\n\n  The purpose is to allow a universe-env with a built-in bot to record the actions it's taking\n  as a demonstration. So the demonstration includes a botactions.jsonl file that gets used instead\n  of the vnc client log. (The vnc client log is still recorded and needed to fully parse the VNC\n  protocol.)\n\n  It's much simpler than reward_recorder.py, because it doesn't have to also talk to the agent.\n  It just takes json messages over a websocket and appends them separated by newlines to the log file.\n\n  The ws port is 15986 unless overridden with --listen-address\n  The log file is /tmp/demo/botactions.jsonl unless overridden with --botaction-logfile\n\"\"\"\nimport argparse\nimport logging\nimport sys\nimport json\nfrom autobahn.twisted import websocket\nfrom universe.twisty import reactor\nlogger = logging.getLogger()\n\nclass BotactionRecordingServer(websocket.WebSocketServerProtocol, object):\n\n    _next_id = 1\n    @classmethod\n    def next_id(cls):\n        id = cls._next_id\n        cls._next_id += 1\n        return id\n\n    logfile_path='/tmp/demo/botactions.jsonl'\n\n    def __init__(self):\n        super(BotactionRecordingServer, self).__init__()\n        self.id = self.next_id()\n        self._closed = False\n        self.file = None\n\n        logger.info(\"[BotactionRecordingServer] [%d] Wrote version number\", self.id)\n\n    def _emit(self, rec):\n        if self.file:\n            self.file.write(json.dumps(rec) + '\\n');\n            self.file.flush()\n\n    def onConnect(self, request):\n        logger.info('[BotactionRecordingServer] [%d] Client connecting: %s. Writing to %s', self.id, request.peer, self.logfile_path)\n        self.file = open(self.logfile_path, 'w', encoding='utf-8')\n        self._emit({\n            'version': 1,\n            'session_id': self.id,\n            '_debug_version': '0.0.1',  # Give this an internal version for debugging corrupt reward.demo files # TODO, pull this from setup.py or the host docker image\n        })\n\n    def onOpen(self):\n        logger.info(\"[BotactionRecordingServer] [%d] Websocket connection established\", self.id)\n\n    def onClose(self, wasClean, code, reason):\n        logger.info('[BotactionRecordingServer] [%d] Client connection closed: %s', self.id, reason)\n        if self.file:\n            self.file.close()\n            self.file = None\n\n        self._closed = True\n\n    def onMessage(self, msg, binary):\n        logger.debug('[BotactionRecordingServer] [%d] Received message from client: %s', self.id, msg)\n\n        self._emit(json.loads(msg.decode('utf-8')));\n\ndef main():\n    parser = argparse.ArgumentParser(description=None)\n    parser.add_argument('-v', '--verbose', action='count', dest='verbosity', default=0, help='Set verbosity.')\n    parser.add_argument('-l', '--listen-address', default='127.0.0.1:15896', help='Address to listen on')\n    parser.add_argument('-o', '--botaction-logfile', default='/tmp/demo/botactions.jsonl', help='Filename for timestamped log of bot actions.')\n    args = parser.parse_args()\n\n    BotactionRecordingServer.logfile_path = args.botaction_logfile\n\n    if args.verbosity == 0:\n        logger.setLevel(logging.INFO)\n    elif args.verbosity >= 1:\n        logger.setLevel(logging.DEBUG)\n\n    factory = websocket.WebSocketServerFactory()\n    factory.protocol = BotactionRecordingServer\n\n    host, port = args.listen_address.split(':')\n    port = int(port)\n    logger.info('Listening on %s:%s', host, port)\n    reactor.listenTCP(port, factory)\n    reactor.run()\n    return 0\n\nif __name__ == '__main__':\n    sys.exit(main())\n"
  },
  {
    "path": "example/recorders/reward_recorder.py",
    "content": "#!/usr/bin/env python\nimport argparse\nimport logging\nimport sys\n\nfrom autobahn.twisted import websocket\nfrom universe.rewarder import reward_proxy_server\nfrom universe.twisty import reactor\n\nlogger = logging.getLogger()\n\n\ndef main():\n    parser = argparse.ArgumentParser(description=None)\n    parser.add_argument('-v', '--verbose', action='count', dest='verbosity', default=0, help='Set verbosity.')\n    parser.add_argument('-l', '--listen-address', default='0.0.0.0:15898', help='Address to listen on')\n    parser.add_argument('-s', '--rewarder-address', default='127.0.0.1:15900', help='Address of the reward server to run on.')\n    parser.add_argument('-d', '--logfile-dir', default=None, help='Base directory to write logs for each connection')\n    args = parser.parse_args()\n\n    if args.verbosity == 0:\n        logger.setLevel(logging.INFO)\n    elif args.verbosity >= 1:\n        logger.setLevel(logging.DEBUG)\n\n    factory = websocket.WebSocketServerFactory()\n    factory.protocol = reward_proxy_server.RewardProxyServer\n    factory.rewarder_address = args.rewarder_address\n    factory.logfile_dir = args.logfile_dir\n    factory.setProtocolOptions(maxConnections=1)  # We only write reward logs to one place, so only allow one connection\n\n    host, port = args.listen_address.split(':')\n    port = int(port)\n    logger.info('Listening on %s:%s', host, port)\n    reactor.listenTCP(port, factory)\n    reactor.run()\n    return 0\n\nif __name__ == '__main__':\n    sys.exit(main())\n"
  },
  {
    "path": "example/recorders/vnc_recorder.py",
    "content": "#!/usr/bin/env python\nimport argparse\nimport logging\nimport os\nimport re\nimport sys\n\nfrom universe import utils\nfrom universe.vncdriver import vnc_proxy_server\nfrom twisted.internet import protocol, reactor\n\nlogger = logging.getLogger()\n\ndef main():\n    parser = argparse.ArgumentParser(description=None)\n    parser.add_argument('-v', '--verbose', action='count', dest='verbosity', default=0, help='Set verbosity.')\n    parser.add_argument('-l', '--listen-address', default='0.0.0.0:5899', help='Address to listen on')\n    parser.add_argument('-s', '--vnc-address', default='127.0.0.1:5900', help='Address of the VNC server to run on.')\n    parser.add_argument('-d', '--logfile-dir', default=None, help='Base directory to write logs for each connection')\n    args = parser.parse_args()\n\n    if args.verbosity == 0:\n        logger.setLevel(logging.INFO)\n    elif args.verbosity >= 1:\n        logger.setLevel(logging.DEBUG)\n\n    factory = protocol.ServerFactory()\n    factory.protocol = vnc_proxy_server.VNCProxyServer\n    factory.vnc_address = 'tcp:{}'.format(args.vnc_address)\n    factory.logfile_dir = args.logfile_dir\n    factory.recorder_id = utils.random_alphanumeric().lower()\n\n    host, port = args.listen_address.split(':')\n    port = int(port)\n\n    logger.info('Listening on %s:%s', host, port)\n    reactor.listenTCP(port, factory, interface=host)\n    reactor.run()\n    return 0\n\nif __name__ == '__main__':\n    sys.exit(main())\n"
  },
  {
    "path": "example/starter-cluster/starter-cluster",
    "content": "#!/usr/bin/env python\nfrom contextlib import contextmanager\nimport logging\nimport math\nimport os\nimport os.path\nimport subprocess\nimport sys\n\nimport boto3\nimport click\nimport docker\nimport yaml\n\nimport universe\n\nlogger = logging.getLogger('cluster')\n\nDEBUG_LOGGING_MAP = {\n    0: logging.WARNING,\n    1: logging.INFO,\n    2: logging.DEBUG\n}\n\nVNC_PORT = 5900\nREWARDER_PORT = 15900\n\n\ndef get_ports(cli, n):\n    \"\"\"\n    returns a list of n ports that are available in the docker cluster\n    \"\"\"\n    used_ports = set()\n\n    containers = cli.containers()\n    for container in containers:\n        for port in container.get('Ports', []):\n            used_ports.add(port.get('PublicPort'))\n\n    ports = []\n    obtained = 0\n    for i in range(5000, 10000):\n        if i not in used_ports:\n            ports.append(i)\n            obtained += 1\n\n        if obtained == n:\n            break\n\n    return ports\n\n\ndef start_ssh_tunnel(host, local_port, remote_path, key_path):\n    cmd = [\n        'ssh', '-L', 'localhost:{}:{}'.format(local_port, remote_path),\n        '-o', 'stricthostkeychecking=no', '-o', 'UserKnownHostsFile=/dev/null']\n    if key_path:\n        cmd += ['-i', key_path]\n    cmd.append('ec2-user@{}'.format(host))\n    cmd.append('echo tunnel-ready; sleep 3600')\n\n    logger.debug('Starting SSH tunnel: %s', cmd)\n\n    process = subprocess.Popen(cmd, stdin=subprocess.PIPE,\n                               stdout=subprocess.PIPE,\n                               stderr=subprocess.PIPE)\n    return process\n\n\n@contextmanager\ndef docker_cli(host, local_port, remote_path='localhost:4000',\n               key_path=None):\n    ssh_tunnel = start_ssh_tunnel(host, local_port, remote_path, key_path)\n    for line in iter(ssh_tunnel.stdout.readline, ''):\n        if line.strip() == b'tunnel-ready':\n            break\n    logger.debug('SSH tunnel ready [pid: %s]', ssh_tunnel.pid)\n    try:\n        yield docker.Client(base_url='localhost:{}'.format(local_port))\n    finally:\n        logger.debug('SSH tunnel terminating')\n        ssh_tunnel.terminate()\n        for line in iter(ssh_tunnel.stderr.readline, ''):\n            line = line.strip()\n            if not line:\n                break\n            logger.debug('[SSH tunnel stderr] %s', line)\n\n\ndef get_compose_file(runtime):\n    dir_path = os.path.dirname(os.path.realpath(__file__))\n    return os.path.join(dir_path, 'gen', runtime, 'docker-compose.yaml')\n\n\ndef build_compose(cli, runtime, n):\n    spec = universe.runtime_spec(runtime)\n    expose = [VNC_PORT-1, VNC_PORT, REWARDER_PORT-1, REWARDER_PORT]\n    usable_ports = get_ports(cli, len(expose) * n)\n\n    output = {\n        'version': '2'\n    }\n\n    services = {}\n    for i in range(n):\n        service = {\n            'image': spec.image,\n            'command': spec.command,\n            'cap_add': spec.host_config.get('cap_add', [])\n        }\n        if spec.host_config.get('ipc_mode'):\n            service['ipc'] = spec.host_config['ipc_mode']\n\n        service['cpu_shares'] = int(math.ceil(spec.default_params.get('cpu', 4)))\n\n        service['ports'] = ['{host}:{container}'.format(container=port, host=usable_ports[i*len(expose)+j])\n                            for j, port in enumerate(expose)]\n\n        service['labels'] = {\n            'universe.runtime': runtime,\n            'universe.index': str(i)\n        }\n\n        services['{}-{}'.format(runtime, i)] = service\n\n    output['services'] = services\n    content = yaml.dump(output)\n\n    filepath = get_compose_file(runtime)\n\n    directory = os.path.dirname(filepath)\n    if not os.path.exists(directory):\n        logger.info('Creating directory: %s', directory)\n        os.makedirs(directory)\n\n    logger.info('Writing compose file to %s', filepath)\n    with open(filepath, 'w') as f:\n        f.write(content)\n\n    return filepath\n\n\ndef start_compose(cli, filepath):\n    subprocess.check_call(['docker-compose', '-H', cli.base_url, '-f', filepath, 'up', '-d', '--remove-orphans'])\n\n\ndef stop_compose(cli, filepath):\n    subprocess.check_call(['docker-compose', '-H', cli.base_url, '-f', filepath, 'down', '--remove-orphans'])\n\n\nclass Stack(object):\n    def __init__(self, data):\n        self.name = data['StackName']\n\n        outputs = {}\n        for output in data['Outputs']:\n            outputs[output['OutputKey']] = output['OutputValue']\n        self.docker_ip = outputs['DockerIP']\n        self.worker_asg = outputs['ASGName']\n\n\ndef get_stack(name):\n    client = boto3.client('cloudformation')\n    response = client.describe_stacks(StackName=name)\n    if len(response['Stacks']) == 0:\n        raise Exception('Failed to find CloudFormation stack {}'.format(name))\n\n    return Stack(response['Stacks'][0])\n\n\ndef get_worker_instances(stack_name):\n    instances = {}\n\n    client = boto3.client('ec2')\n    response = client.describe_instances(\n        Filters=[\n            {\n                'Name': 'tag:aws:cloudformation:stack-name',\n                'Values': [\n                    stack_name,\n                ]\n            },\n            {\n                'Name': 'instance-state-name',\n                'Values': [\n                    'running'\n                ]\n            }\n        ]\n    )\n    for reservation in response['Reservations']:\n        for instance in reservation['Instances']:\n            instances[instance['PrivateIpAddress']] = {\n                'id': instance['InstanceId'],\n                'public_ip': instance.get('PublicIpAddress')\n            }\n\n    return instances\n\n\ndef get_runtime_containers(cli, runtime):\n    containers_map = {}\n    filters = {\n        'label': ['universe.runtime={}'.format(runtime)]\n    }\n    containers = cli.containers(filters=filters)\n    for container in containers:\n        labels = container['Labels']\n        addr = None\n        for name in container['Names']:\n            if name.startswith('/ip-'):\n                addr = name.split('/')[1][3:].replace('-', '.')\n        containers_map[labels['com.docker.compose.service']] = {\n            'labels': labels,\n            'ports': container['Ports'],\n            'host': addr\n        }\n\n    return containers_map\n\n\n@click.group()\n@click.option('--verbose', '-v',\n              help='Sets the debug noise level, specify multiple times for more verbosity.',\n              type=click.IntRange(0, 3, clamp=True),\n              count=True)\ndef cli(verbose):\n    logger_handler = logging.StreamHandler(sys.stderr)\n    logger_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))\n    logger.addHandler(logger_handler)\n    logger.setLevel(DEBUG_LOGGING_MAP.get(verbose, logging.DEBUG))\n\n\n@cli.command()\n@click.option('--stack', '-s', 'stack_name', required=True,\n              help='AWS CloudFormation Stack name.')\n@click.option('--port', '-P', default=2374,\n              help='Local port to use for remote docker connection')\n@click.option('--key-path', '-i',\n              help='Path to private key for SSH connection to docker host')\n@click.option('--runtime', default='flashgames',\n              help='Runtime ID to start. (See universe/runtimes/__init__ for a starting list)')\n@click.option('-n', default=1,\n              help='Number of environments to start')\ndef start(stack_name, port, key_path, runtime, n):\n    stack = get_stack(stack_name)\n    with docker_cli(stack.docker_ip, port, key_path=key_path) as cli:\n        filepath = build_compose(cli, runtime, n)\n        start_compose(cli, filepath)\n\n        containers = get_runtime_containers(cli, runtime)\n        instances = get_worker_instances(stack.name)\n\n        endpoints = []\n        for name, container in containers.items():\n            for port in container['ports']:\n                if port['PrivatePort'] == VNC_PORT:\n                    vnc_port = port['PublicPort']\n                elif port['PrivatePort'] == REWARDER_PORT:\n                    rewarder_port = port['PublicPort']\n            if container['host'] in instances:\n                host_ip = instances[container['host']]['public_ip']\n                endpoints.append(\n                    'vnc://{}:{}+{}'.format(host_ip, vnc_port, rewarder_port))\n            else:\n                logger.warn(\n                    'Container %s on unknown host %s', name, container['host'])\n\n        print('Environments started.')\n        print('Remotes:')\n        for endpoint in endpoints:\n            print('\\t{}'.format(endpoint))\n\n\n@cli.command()\n@click.option('--stack', '-s', 'stack_name', required=True,\n              help='AWS CloudFormation Stack name.')\n@click.option('--port', '-P', default=2374,\n              help='Local port to use for remote docker connection')\n@click.option('--key-path', '-i',\n              help='Path to private key for SSH connection to docker host')\n@click.option('--runtime', default='flashgames',\n              help='Runtime ID to stop. (See universe/runtimes/__init__ for a starting list)')\ndef stop(stack_name, port, key_path, runtime):\n    stack = get_stack(stack_name)\n    with docker_cli(stack.docker_ip, port, key_path=key_path) as cli:\n        filepath = get_compose_file(runtime)\n        stop_compose(cli, filepath)\n\n        print('Environments stopped.')\n\nif __name__ == '__main__':\n    cli()\n"
  },
  {
    "path": "example/starter-cluster/starter-cluster-cf.json",
    "content": "{\n    \"AWSTemplateFormatVersion\": \"2010-09-09\",\n    \"Description\": \"Docker cluster for OpenAI Universe runtimes\",\n    \"Mappings\": {\n        \"AWSInstanceType2Arch\": {\n            \"c3.2xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"c3.4xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"c3.8xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"c3.large\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"c3.xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"c4.2xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"c4.4xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"c4.8xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"c4.large\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"c4.xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"cc2.8xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"cr1.8xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"d2.2xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"d2.4xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"d2.8xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"d2.xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"g2.2xlarge\": {\n                \"Arch\": \"HVMG2\"\n            },\n            \"hi1.4xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"hs1.8xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"i2.2xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"i2.4xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"i2.8xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"i2.xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"m3.2xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"m3.large\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"m3.medium\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"m3.xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"m4.10xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"m4.2xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"m4.4xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"m4.large\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"m4.xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"r3.2xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"r3.4xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"r3.8xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"r3.large\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"r3.xlarge\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"t2.large\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"t2.medium\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"t2.micro\": {\n                \"Arch\": \"HVM64\"\n            },\n            \"t2.small\": {\n                \"Arch\": \"HVM64\"\n            }\n        },\n        \"AWSRegionArch2AMI\" : {\n          \"us-east-1\"        : {\"PV64\" : \"ami-2a69aa47\", \"HVM64\" : \"ami-6869aa05\", \"HVMG2\" : \"ami-a41a3fb3\"},\n          \"us-west-2\"        : {\"PV64\" : \"ami-7f77b31f\", \"HVM64\" : \"ami-7172b611\", \"HVMG2\" : \"ami-caf253aa\"},\n          \"us-west-1\"        : {\"PV64\" : \"ami-a2490dc2\", \"HVM64\" : \"ami-31490d51\", \"HVMG2\" : \"ami-00347e60\"},\n          \"eu-west-1\"        : {\"PV64\" : \"ami-4cdd453f\", \"HVM64\" : \"ami-f9dd458a\", \"HVMG2\" : \"ami-e2f7bd91\"},\n          \"eu-central-1\"     : {\"PV64\" : \"ami-6527cf0a\", \"HVM64\" : \"ami-ea26ce85\", \"HVMG2\" : \"ami-d2ff04bd\"},\n          \"ap-northeast-1\"   : {\"PV64\" : \"ami-3e42b65f\", \"HVM64\" : \"ami-374db956\", \"HVMG2\" : \"ami-4c78d52d\"},\n          \"ap-northeast-2\"   : {\"PV64\" : \"NOT_SUPPORTED\", \"HVM64\" : \"ami-2b408b45\", \"HVMG2\" : \"NOT_SUPPORTED\"},\n          \"ap-southeast-1\"   : {\"PV64\" : \"ami-df9e4cbc\", \"HVM64\" : \"ami-a59b49c6\", \"HVMG2\" : \"ami-f3f95990\"},\n          \"ap-southeast-2\"   : {\"PV64\" : \"ami-63351d00\", \"HVM64\" : \"ami-dc361ebf\", \"HVMG2\" : \"ami-3a122e59\"},\n          \"ap-south-1\"       : {\"PV64\" : \"NOT_SUPPORTED\", \"HVM64\" : \"ami-ffbdd790\", \"HVMG2\" : \"ami-21a7d34e\"},\n          \"us-east-2\"        : {\"PV64\" : \"NOT_SUPPORTED\", \"HVM64\" : \"ami-f6035893\", \"HVMG2\" : \"NOT_SUPPORTED\"},\n          \"sa-east-1\"        : {\"PV64\" : \"ami-1ad34676\", \"HVM64\" : \"ami-6dd04501\", \"HVMG2\" : \"NOT_SUPPORTED\"},\n          \"cn-north-1\"       : {\"PV64\" : \"ami-77559f1a\", \"HVM64\" : \"ami-8e6aa0e3\", \"HVMG2\" : \"NOT_SUPPORTED\"}\n        },\n        \"VpcCidrs\": {\n            \"pubsubnet1\": {\n                \"cidr\": \"172.33.0.0/20\"\n            },\n            \"pubsubnet2\": {\n                \"cidr\": \"172.33.16.0/20\"\n            },\n            \"pubsubnet3\": {\n                \"cidr\": \"172.33.32.0/20\"\n            },\n            \"pubsubnet4\": {\n                \"cidr\": \"172.33.48.0/20\"\n            },\n            \"vpc\": {\n                \"cidr\": \"172.33.0.0/16\"\n            }\n        }\n    },\n    \"Metadata\": {\n        \"AWS::CloudFormation::Interface\": {\n            \"ParameterGroups\": [\n                {\n                    \"Label\": {\n                        \"default\": \"Swarm Size\"\n                    },\n                    \"Parameters\": [\n                        \"ClusterSize\"\n                    ]\n                },\n                {\n                    \"Label\": {\n                        \"default\": \"Swarm Properties\"\n                    },\n                    \"Parameters\": [\n                        \"KeyName\"\n                    ]\n                },\n                {\n                    \"Label\": {\n                        \"default\": \"Swarm Manager Properties\"\n                    },\n                    \"Parameters\": [\n                        \"ManagerInstanceType\",\n                        \"ManagerDiskSize\",\n                        \"ManagerDiskType\"\n                    ]\n                },\n                {\n                    \"Label\": {\n                        \"default\": \"Swarm Worker Properties\"\n                    },\n                    \"Parameters\": [\n                        \"InstanceType\",\n                        \"WorkerDiskSize\",\n                        \"WorkerDiskType\"\n                    ]\n                }\n            ],\n            \"ParameterLabels\": {\n                \"ClusterSize\": {\n                    \"default\": \"Number of Swarm worker nodes?\"\n                },\n                \"InstanceType\": {\n                    \"default\": \"Agent worker instance type?\"\n                },\n                \"KeyName\": {\n                    \"default\": \"Which SSH key to use?\"\n                },\n                \"ManagerDiskSize\": {\n                    \"default\": \"Manager ephemeral storage volume size?\"\n                },\n                \"ManagerDiskType\": {\n                    \"default\": \"Manager ephemeral storage volume type\"\n                },\n                \"ManagerInstanceType\": {\n                    \"default\": \"Swarm manager instance type?\"\n                },\n                \"WorkerDiskSize\": {\n                    \"default\": \"Worker ephemeral storage volume size?\"\n                },\n                \"WorkerDiskType\": {\n                    \"default\": \"Worker ephemeral storage volume type\"\n                }\n            }\n        }\n    },\n    \"Outputs\": {\n        \"ASGName\": {\n            \"Description\": \"Name of the worker AutoScalingGroup\",\n            \"Value\": {\n                \"Ref\": \"NodeAsg\"\n            }\n        },\n        \"DockerIP\": {\n            \"Description\": \"Public IP of the manager node that can be SSH'd into\",\n            \"Value\": {\n                \"Fn::GetAtt\": [\n                    \"ManagerInstance\",\n                    \"PublicIp\"\n                ]\n            }\n        }\n    },\n    \"Parameters\": {\n        \"ClusterSize\": {\n            \"Default\": \"4\",\n            \"Description\": \"Number of worker nodes in the Swarm (1-1000).\",\n            \"MaxValue\": \"1000\",\n            \"MinValue\": \"1\",\n            \"Type\": \"Number\"\n        },\n        \"InstanceType\": {\n            \"AllowedValues\": [\n                \"t2.micro\",\n                \"t2.small\",\n                \"t2.medium\",\n                \"t2.large\",\n                \"m4.large\",\n                \"m4.xlarge\",\n                \"m4.2xlarge\",\n                \"m4.4xlarge\",\n                \"m4.10xlarge\",\n                \"m3.medium\",\n                \"m3.large\",\n                \"m3.xlarge\",\n                \"m3.2xlarge\",\n                \"c4.large\",\n                \"c4.xlarge\",\n                \"c4.2xlarge\",\n                \"c4.4xlarge\",\n                \"c4.8xlarge\",\n                \"c3.large\",\n                \"c3.xlarge\",\n                \"c3.2xlarge\",\n                \"c3.4xlarge\",\n                \"c3.8xlarge\",\n                \"r3.large\",\n                \"r3.xlarge\",\n                \"r3.2xlarge\",\n                \"r3.4xlarge\",\n                \"r3.8xlarge\",\n                \"i2.xlarge\",\n                \"i2.2xlarge\",\n                \"i2.4xlarge\",\n                \"i2.8xlarge\"\n            ],\n            \"ConstraintDescription\": \"Must be a valid EC2 HVM instance type.\",\n            \"Default\": \"c4.xlarge\",\n            \"Description\": \"EC2 HVM instance type (t2.micro, m3.medium, etc).\",\n            \"Type\": \"String\"\n        },\n        \"KeyName\": {\n            \"ConstraintDescription\": \"must be the name of an existing EC2 KeyPair.\",\n            \"Description\": \"Name of an existing EC2 KeyPair to enable SSH access to the instances\",\n            \"MinLength\": \"1\",\n            \"Type\": \"AWS::EC2::KeyPair::KeyName\"\n        },\n        \"ManagerDiskSize\": {\n            \"Default\": \"20\",\n            \"Description\": \"Size of Manager's ephemeral storage volume in GiB\",\n            \"MaxValue\": \"1024\",\n            \"MinValue\": \"20\",\n            \"Type\": \"Number\"\n        },\n        \"ManagerDiskType\": {\n            \"AllowedValues\": [\n                \"standard\",\n                \"gp2\"\n            ],\n            \"Default\": \"standard\",\n            \"Description\": \"Manager ephemeral storage volume type\",\n            \"Type\": \"String\"\n        },\n        \"ManagerInstanceType\": {\n            \"AllowedValues\": [\n                \"t2.micro\",\n                \"t2.small\",\n                \"t2.medium\",\n                \"t2.large\",\n                \"m4.large\",\n                \"m4.xlarge\",\n                \"m4.2xlarge\",\n                \"m4.4xlarge\",\n                \"m4.10xlarge\",\n                \"m3.medium\",\n                \"m3.large\",\n                \"m3.xlarge\",\n                \"m3.2xlarge\",\n                \"c4.large\",\n                \"c4.xlarge\",\n                \"c4.2xlarge\",\n                \"c4.4xlarge\",\n                \"c4.8xlarge\",\n                \"c3.large\",\n                \"c3.xlarge\",\n                \"c3.2xlarge\",\n                \"c3.4xlarge\",\n                \"c3.8xlarge\",\n                \"r3.large\",\n                \"r3.xlarge\",\n                \"r3.2xlarge\",\n                \"r3.4xlarge\",\n                \"r3.8xlarge\",\n                \"i2.xlarge\",\n                \"i2.2xlarge\",\n                \"i2.4xlarge\",\n                \"i2.8xlarge\"\n            ],\n            \"ConstraintDescription\": \"Must be a valid EC2 HVM instance type.\",\n            \"Default\": \"t2.small\",\n            \"Description\": \"EC2 HVM instance type (t2.micro, m3.medium, etc).\",\n            \"Type\": \"String\"\n        },\n        \"WorkerDiskSize\": {\n            \"Default\": \"50\",\n            \"Description\": \"Size of Workers's ephemeral storage volume in GiB\",\n            \"MaxValue\": \"1024\",\n            \"MinValue\": \"20\",\n            \"Type\": \"Number\"\n        },\n        \"WorkerDiskType\": {\n            \"AllowedValues\": [\n                \"standard\",\n                \"gp2\"\n            ],\n            \"Default\": \"standard\",\n            \"Description\": \"Worker ephemeral storage volume type\",\n            \"Type\": \"String\"\n        }\n    },\n    \"Resources\": {\n        \"AttachGateway\": {\n            \"DependsOn\": [\n                \"Vpc\",\n                \"InternetGateway\"\n            ],\n            \"Properties\": {\n                \"InternetGatewayId\": {\n                    \"Ref\": \"InternetGateway\"\n                },\n                \"VpcId\": {\n                    \"Ref\": \"Vpc\"\n                }\n            },\n            \"Type\": \"AWS::EC2::VPCGatewayAttachment\"\n        },\n        \"DockerLogGroup\": {\n            \"Properties\": {\n                \"LogGroupName\": {\n                    \"Fn::Join\": [\n                        \"-\",\n                        [\n                            {\n                                \"Ref\": \"AWS::StackName\"\n                            },\n                            \"lg\"\n                        ]\n                    ]\n                },\n                \"RetentionInDays\": 7\n            },\n            \"Type\": \"AWS::Logs::LogGroup\"\n        },\n        \"InternetGateway\": {\n            \"DependsOn\": \"Vpc\",\n            \"Properties\": {\n                \"Tags\": [\n                    {\n                        \"Key\": \"Name\",\n                        \"Value\": {\n                            \"Fn::Join\": [\n                                \"-\",\n                                [\n                                    {\n                                        \"Ref\": \"AWS::StackName\"\n                                    },\n                                    \"IGW\"\n                                ]\n                            ]\n                        }\n                    }\n                ]\n            },\n            \"Type\": \"AWS::EC2::InternetGateway\"\n        },\n        \"ManagerInstance\": {\n            \"DependsOn\": [\n                \"PubSubnetAz1\",\n                \"PubSubnetAz2\"\n            ],\n            \"Properties\": {\n                \"Tags\": [\n                    {\n                        \"Key\": \"Name\",\n                        \"Value\": {\n                            \"Fn::Join\": [\n                                \"-\",\n                                [\n                                    {\n                                        \"Ref\": \"AWS::StackName\"\n                                    },\n                                    \"Manager\"\n                                ]\n                            ]\n                        }\n                    },\n                    {\n                        \"Key\": \"swarm-node-type\",\n                        \"Value\": \"manager\"\n                    },\n                    {\n                        \"Key\": \"swarm-stack-id\",\n                        \"Value\": {\n                            \"Ref\": \"AWS::StackId\"\n                        }\n                    }\n                ],\n                \"BlockDeviceMappings\": [\n                    {\n                        \"DeviceName\": \"/dev/xvdb\",\n                        \"Ebs\": {\n                            \"VolumeSize\": {\n                                \"Ref\": \"ManagerDiskSize\"\n                            },\n                            \"VolumeType\": {\n                                \"Ref\": \"ManagerDiskType\"\n                            }\n                        }\n                    }\n                ],\n                \"IamInstanceProfile\": {\n                    \"Ref\": \"ProxyInstanceProfile\"\n                },\n                \"ImageId\": {\n                    \"Fn::FindInMap\": [\n                        \"AWSRegionArch2AMI\",\n                        {\n                            \"Ref\": \"AWS::Region\"\n                        },\n                        {\n                            \"Fn::FindInMap\": [\n                                \"AWSInstanceType2Arch\",\n                                {\n                                    \"Ref\": \"ManagerInstanceType\"\n                                },\n                                \"Arch\"\n                            ]\n                        }\n                    ]\n                },\n                \"InstanceType\": {\n                    \"Ref\": \"ManagerInstanceType\"\n                },\n                \"KeyName\": {\n                    \"Ref\": \"KeyName\"\n                },\n                \"SecurityGroupIds\": [\n                    {\n                        \"Ref\": \"ManagerVpcSG\"\n                    },\n                    {\n                        \"Ref\": \"SwarmWideSG\"\n                    }\n                ],\n                \"SubnetId\": {\n                    \"Ref\": \"PubSubnetAz1\"\n                },\n                \"UserData\": {\n                    \"Fn::Base64\": {\n                        \"Fn::Join\": [\n                            \"\",\n                            [\n                                \"#!/bin/sh\\n\",\n                                \"sudo yum update -y\\n\",\n                                \"curl -sSL https://get.docker.com/ | sh\\n\",\n                                \"sed -i 's/OPTIONS=\\\"/OPTIONS=\\\"-H tcp:\\\\/\\\\/0\\\\.0\\\\.0\\\\.0:2375 -H unix:\\\\/\\\\/\\\\/var\\\\/run\\\\/docker\\\\.sock /' /etc/sysconfig/docker\\n\",\n                                \"sudo /etc/init.d/docker start\\n\",\n                                \"sudo usermod -aG docker ec2-user\\n\",\n                                \"\\n\",\n                                \"export LOCAL_IP=$(wget -qO- http://169.254.169.254/latest/meta-data/local-ipv4)\\n\",\n                                \"sleep 5\\n\",\n\n                                \"docker run -d -p 8500:8500 --name=consul progrium/consul -server -bootstrap -advertise=$LOCAL_IP\\n\",\n                                \"docker run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise $LOCAL_IP:4000 consul://$LOCAL_IP:8500\\n\"\n                            ]\n                        ]\n                    }\n                }\n            },\n            \"Type\": \"AWS::EC2::Instance\"\n        },\n        \"ManagerVpcSG\": {\n            \"DependsOn\": \"NodeVpcSG\",\n            \"Properties\": {\n                \"GroupDescription\": \"Manager SecurityGroup\",\n                \"SecurityGroupIngress\": [\n                    {\n                        \"CidrIp\": \"0.0.0.0/0\",\n                        \"FromPort\": \"22\",\n                        \"IpProtocol\": \"tcp\",\n                        \"ToPort\": \"22\"\n                    },\n                    {\n                        \"FromPort\": \"2377\",\n                        \"IpProtocol\": \"tcp\",\n                        \"SourceSecurityGroupId\": {\n                            \"Fn::GetAtt\": [\n                                \"NodeVpcSG\",\n                                \"GroupId\"\n                            ]\n                        },\n                        \"ToPort\": \"2377\"\n                    },\n                    {\n                        \"FromPort\": \"4789\",\n                        \"IpProtocol\": \"udp\",\n                        \"SourceSecurityGroupId\": {\n                            \"Fn::GetAtt\": [\n                                \"NodeVpcSG\",\n                                \"GroupId\"\n                            ]\n                        },\n                        \"ToPort\": \"4789\"\n                    },\n                    {\n                        \"FromPort\": \"7946\",\n                        \"IpProtocol\": \"tcp\",\n                        \"SourceSecurityGroupId\": {\n                            \"Fn::GetAtt\": [\n                                \"NodeVpcSG\",\n                                \"GroupId\"\n                            ]\n                        },\n                        \"ToPort\": \"7946\"\n                    },\n                    {\n                        \"FromPort\": \"7946\",\n                        \"IpProtocol\": \"udp\",\n                        \"SourceSecurityGroupId\": {\n                            \"Fn::GetAtt\": [\n                                \"NodeVpcSG\",\n                                \"GroupId\"\n                            ]\n                        },\n                        \"ToPort\": \"7946\"\n                    }\n                ],\n                \"VpcId\": {\n                    \"Ref\": \"Vpc\"\n                }\n            },\n            \"Type\": \"AWS::EC2::SecurityGroup\"\n        },\n        \"NodeAsg\": {\n            \"DependsOn\": \"ManagerInstance\",\n            \"Properties\": {\n                \"DesiredCapacity\": {\n                    \"Ref\": \"ClusterSize\"\n                },\n                \"LaunchConfigurationName\": {\n                    \"Ref\": \"NodeLaunchConfigBeta12\"\n                },\n                \"MaxSize\": \"1000\",\n                \"MinSize\": \"0\",\n                \"Tags\": [\n                    {\n                        \"Key\": \"Name\",\n                        \"PropagateAtLaunch\": \"true\",\n                        \"Value\": {\n                            \"Fn::Join\": [\n                                \"-\",\n                                [\n                                    {\n                                        \"Ref\": \"AWS::StackName\"\n                                    },\n                                    \"worker\"\n                                ]\n                            ]\n                        }\n                    },\n                    {\n                        \"Key\": \"swarm-node-type\",\n                        \"PropagateAtLaunch\": \"true\",\n                        \"Value\": \"worker\"\n                    },\n                    {\n                        \"Key\": \"swarm-stack-id\",\n                        \"PropagateAtLaunch\": \"true\",\n                        \"Value\": {\n                            \"Ref\": \"AWS::StackId\"\n                        }\n                    }\n                ],\n                \"VPCZoneIdentifier\": [\n                    {\n                        \"Fn::Join\": [\n                            \",\",\n                            [\n                                {\n                                    \"Ref\": \"PubSubnetAz1\"\n                                },\n                                {\n                                    \"Ref\": \"PubSubnetAz2\"\n                                }\n                            ]\n                        ]\n                    }\n                ]\n            },\n            \"Type\": \"AWS::AutoScaling::AutoScalingGroup\",\n            \"UpdatePolicy\": {\n                \"AutoScalingRollingUpdate\": {\n                    \"MaxBatchSize\": \"1\",\n                    \"MinInstancesInService\": \"1\"\n                }\n            }\n        },\n        \"NodeLaunchConfigBeta12\": {\n            \"DependsOn\": \"ManagerInstance\",\n            \"Properties\": {\n                \"AssociatePublicIpAddress\": \"true\",\n                \"BlockDeviceMappings\": [\n                    {\n                        \"DeviceName\": \"/dev/xvdb\",\n                        \"Ebs\": {\n                            \"VolumeSize\": {\n                                \"Ref\": \"WorkerDiskSize\"\n                            },\n                            \"VolumeType\": {\n                                \"Ref\": \"WorkerDiskType\"\n                            }\n                        }\n                    }\n                ],\n                \"IamInstanceProfile\": {\n                    \"Ref\": \"ProxyInstanceProfile\"\n                },\n                \"ImageId\": {\n                    \"Fn::FindInMap\": [\n                        \"AWSRegionArch2AMI\",\n                        {\n                            \"Ref\": \"AWS::Region\"\n                        },\n                        {\n                            \"Fn::FindInMap\": [\n                                \"AWSInstanceType2Arch\",\n                                {\n                                    \"Ref\": \"InstanceType\"\n                                },\n                                \"Arch\"\n                            ]\n                        }\n                    ]\n                },\n                \"InstanceType\": {\n                    \"Ref\": \"InstanceType\"\n                },\n                \"KeyName\": {\n                    \"Ref\": \"KeyName\"\n                },\n                \"SecurityGroups\": [\n                    {\n                        \"Ref\": \"NodeVpcSG\"\n                    },\n                    {\n                        \"Ref\": \"SwarmWideSG\"\n                    }\n                ],\n                \"UserData\": {\n                    \"Fn::Base64\": {\n                        \"Fn::Join\": [\n                            \"\",\n                            [\n                                \"#!/bin/sh\\n\",\n                                \"sudo yum update\\n\",\n                                \"curl -sSL https://get.docker.com/ | sh\\n\",\n                                \"export LOCAL_IP=$(wget -qO- http://169.254.169.254/latest/meta-data/local-ipv4)\\n\",\n                                \"sed -i \\\"s/OPTIONS=\\\\\\\"/OPTIONS=\\\\\\\"--cluster-store consul:\\\\/\\\\/\",\n                                {\n                                    \"Fn::GetAtt\": [\n                                        \"ManagerInstance\",\n                                        \"PrivateIp\"\n                                    ]\n                                },\n                                \":8500 --cluster-advertise=$LOCAL_IP:2375 -H tcp:\\\\/\\\\/0\\\\.0\\\\.0\\\\.0:2375 -H unix:\\\\/\\\\/\\\\/var\\\\/run\\\\/docker\\\\.sock /\\\" /etc/sysconfig/docker\\n\",\n\n                                \"sudo /etc/init.d/docker start\\n\",\n                                \"sudo usermod -aG docker ec2-user\\n\",\n                                \"\\n\",\n\n                                \"docker run -d swarm join --advertise=$LOCAL_IP:2375 consul://\",\n                                {\n                                    \"Fn::GetAtt\": [\n                                        \"ManagerInstance\",\n                                        \"PrivateIp\"\n                                    ]\n                                },\n                                \":8500\\n\"\n                            ]\n                        ]\n                    }\n                }\n            },\n            \"Type\": \"AWS::AutoScaling::LaunchConfiguration\"\n        },\n        \"NodeVpcSG\": {\n            \"DependsOn\": \"Vpc\",\n            \"Properties\": {\n                \"GroupDescription\": \"Node SecurityGroup\",\n                \"SecurityGroupEgress\": [\n                    {\n                        \"CidrIp\": \"0.0.0.0/0\",\n                        \"FromPort\": \"8\",\n                        \"IpProtocol\": \"icmp\",\n                        \"ToPort\": \"0\"\n                    },\n                    {\n                        \"CidrIp\": \"0.0.0.0/0\",\n                        \"FromPort\": \"0\",\n                        \"IpProtocol\": \"udp\",\n                        \"ToPort\": \"65535\"\n                    },\n                    {\n                        \"CidrIp\": \"0.0.0.0/0\",\n                        \"FromPort\": \"0\",\n                        \"IpProtocol\": \"tcp\",\n                        \"ToPort\": \"2374\"\n                    },\n                    {\n                        \"CidrIp\": \"0.0.0.0/0\",\n                        \"FromPort\": \"2376\",\n                        \"IpProtocol\": \"tcp\",\n                        \"ToPort\": \"65535\"\n                    }\n                ],\n                \"SecurityGroupIngress\": [\n                    {\n                        \"CidrIp\": {\n                            \"Fn::FindInMap\": [\n                                \"VpcCidrs\",\n                                \"vpc\",\n                                \"cidr\"\n                            ]\n                        },\n                        \"FromPort\": \"0\",\n                        \"IpProtocol\": \"-1\",\n                        \"ToPort\": \"65535\"\n                    }\n                ],\n                \"VpcId\": {\n                    \"Ref\": \"Vpc\"\n                }\n            },\n            \"Type\": \"AWS::EC2::SecurityGroup\"\n        },\n        \"ProxyInstanceProfile\": {\n            \"Properties\": {\n                \"Path\": \"/\",\n                \"Roles\": [\n                    {\n                        \"Ref\": \"ProxyRole\"\n                    }\n                ]\n            },\n            \"Type\": \"AWS::IAM::InstanceProfile\"\n        },\n        \"ProxyPolicies\": {\n            \"Properties\": {\n                \"PolicyDocument\": {\n                    \"Statement\": [\n                        {\n                            \"Action\": \"elasticloadbalancing:*\",\n                            \"Effect\": \"Allow\",\n                            \"Resource\": \"*\"\n                        }\n                    ],\n                    \"Version\": \"2012-10-17\"\n                },\n                \"PolicyName\": \"elb-update\",\n                \"Roles\": [\n                    {\n                        \"Ref\": \"ProxyRole\"\n                    }\n                ]\n            },\n            \"Type\": \"AWS::IAM::Policy\"\n        },\n        \"ProxyRole\": {\n            \"Properties\": {\n                \"AssumeRolePolicyDocument\": {\n                    \"Statement\": [\n                        {\n                            \"Action\": [\n                                \"sts:AssumeRole\"\n                            ],\n                            \"Effect\": \"Allow\",\n                            \"Principal\": {\n                                \"Service\": [\n                                    \"ec2.amazonaws.com\",\n                                    \"autoscaling.amazonaws.com\"\n                                ]\n                            }\n                        }\n                    ],\n                    \"Version\": \"2012-10-17\"\n                },\n                \"Path\": \"/\"\n            },\n            \"Type\": \"AWS::IAM::Role\"\n        },\n        \"PubSubnet1RouteTableAssociation\": {\n            \"DependsOn\": [\n                \"PubSubnetAz1\",\n                \"RouteViaIgw\"\n            ],\n            \"Properties\": {\n                \"RouteTableId\": {\n                    \"Ref\": \"RouteViaIgw\"\n                },\n                \"SubnetId\": {\n                    \"Ref\": \"PubSubnetAz1\"\n                }\n            },\n            \"Type\": \"AWS::EC2::SubnetRouteTableAssociation\"\n        },\n        \"PubSubnet2RouteTableAssociation\": {\n            \"DependsOn\": [\n                \"PubSubnetAz2\",\n                \"RouteViaIgw\"\n            ],\n            \"Properties\": {\n                \"RouteTableId\": {\n                    \"Ref\": \"RouteViaIgw\"\n                },\n                \"SubnetId\": {\n                    \"Ref\": \"PubSubnetAz2\"\n                }\n            },\n            \"Type\": \"AWS::EC2::SubnetRouteTableAssociation\"\n        },\n        \"PubSubnetAz1\": {\n            \"DependsOn\": \"Vpc\",\n            \"Properties\": {\n                \"AvailabilityZone\": {\n                    \"Fn::Select\": [\n                        \"0\",\n                        {\n                            \"Fn::GetAZs\": {\n                                \"Ref\": \"AWS::Region\"\n                            }\n                        }\n                    ]\n                },\n                \"CidrBlock\": {\n                    \"Fn::FindInMap\": [\n                        \"VpcCidrs\",\n                        \"pubsubnet1\",\n                        \"cidr\"\n                    ]\n                },\n                \"Tags\": [\n                    {\n                        \"Key\": \"Name\",\n                        \"Value\": {\n                            \"Fn::Join\": [\n                                \"-\",\n                                [\n                                    {\n                                        \"Ref\": \"AWS::StackName\"\n                                    },\n                                    \"Subnet1\"\n                                ]\n                            ]\n                        }\n                    }\n                ],\n                \"VpcId\": {\n                    \"Ref\": \"Vpc\"\n                },\n                \"MapPublicIpOnLaunch\": \"true\"\n            },\n            \"Type\": \"AWS::EC2::Subnet\"\n        },\n        \"PubSubnetAz2\": {\n            \"DependsOn\": \"Vpc\",\n            \"Properties\": {\n                \"AvailabilityZone\": {\n                    \"Fn::Select\": [\n                        \"1\",\n                        {\n                            \"Fn::GetAZs\": {\n                                \"Ref\": \"AWS::Region\"\n                            }\n                        }\n                    ]\n                },\n                \"CidrBlock\": {\n                    \"Fn::FindInMap\": [\n                        \"VpcCidrs\",\n                        \"pubsubnet2\",\n                        \"cidr\"\n                    ]\n                },\n                \"Tags\": [\n                    {\n                        \"Key\": \"Name\",\n                        \"Value\": {\n                            \"Fn::Join\": [\n                                \"-\",\n                                [\n                                    {\n                                        \"Ref\": \"AWS::StackName\"\n                                    },\n                                    \"Subnet2\"\n                                ]\n                            ]\n                        }\n                    }\n                ],\n                \"VpcId\": {\n                    \"Ref\": \"Vpc\"\n                },\n                \"MapPublicIpOnLaunch\": \"true\"\n            },\n            \"Type\": \"AWS::EC2::Subnet\"\n        },\n        \"PublicRouteViaIgw\": {\n            \"DependsOn\": [\n                \"AttachGateway\",\n                \"RouteViaIgw\"\n            ],\n            \"Properties\": {\n                \"DestinationCidrBlock\": \"0.0.0.0/0\",\n                \"GatewayId\": {\n                    \"Ref\": \"InternetGateway\"\n                },\n                \"RouteTableId\": {\n                    \"Ref\": \"RouteViaIgw\"\n                }\n            },\n            \"Type\": \"AWS::EC2::Route\"\n        },\n        \"RouteViaIgw\": {\n            \"DependsOn\": \"Vpc\",\n            \"Properties\": {\n                \"Tags\": [\n                    {\n                        \"Key\": \"Name\",\n                        \"Value\": {\n                            \"Fn::Join\": [\n                                \"-\",\n                                [\n                                    {\n                                        \"Ref\": \"AWS::StackName\"\n                                    },\n                                    \"RT\"\n                                ]\n                            ]\n                        }\n                    }\n                ],\n                \"VpcId\": {\n                    \"Ref\": \"Vpc\"\n                }\n            },\n            \"Type\": \"AWS::EC2::RouteTable\"\n        },\n        \"SwarmAPIPolicy\": {\n            \"DependsOn\": \"ProxyRole\",\n            \"Properties\": {\n                \"PolicyDocument\": {\n                    \"Statement\": [\n                        {\n                            \"Action\": [\n                                \"ec2:DescribeInstances\",\n                                \"ec2:DescribeVpcAttribute\",\n                                \"logs:CreateLogStream\",\n                                \"logs:PutLogEvents\"\n                            ],\n                            \"Effect\": \"Allow\",\n                            \"Resource\": \"*\"\n                        }\n                    ],\n                    \"Version\": \"2012-10-17\"\n                },\n                \"PolicyName\": \"swarm-policy\",\n                \"Roles\": [\n                    {\n                        \"Ref\": \"ProxyRole\"\n                    }\n                ]\n            },\n            \"Type\": \"AWS::IAM::Policy\"\n        },\n        \"SwarmAutoscalePolicy\": {\n            \"Properties\": {\n                \"PolicyDocument\": {\n                    \"Statement\": [\n                        {\n                            \"Action\": \"autoscaling:*\",\n                            \"Effect\": \"Allow\",\n                            \"Resource\": \"*\"\n                        }\n                    ],\n                    \"Version\": \"2012-10-17\"\n                },\n                \"PolicyName\": \"swarm-autoscale-policy\",\n                \"Roles\": [\n                    {\n                        \"Ref\": \"ProxyRole\"\n                    }\n                ]\n            },\n            \"Type\": \"AWS::IAM::Policy\"\n        },\n        \"SwarmWideSG\": {\n            \"DependsOn\": \"Vpc\",\n            \"Properties\": {\n                \"GroupDescription\": \"Swarm wide access\",\n                \"SecurityGroupIngress\": [\n                    {\n                        \"CidrIp\": {\n                            \"Fn::FindInMap\": [\n                                \"VpcCidrs\",\n                                \"vpc\",\n                                \"cidr\"\n                            ]\n                        },\n                        \"FromPort\": \"0\",\n                        \"IpProtocol\": \"-1\",\n                        \"ToPort\": \"65535\"\n                    },\n                    {\n                        \"CidrIp\": \"0.0.0.0/0\",\n                        \"FromPort\": \"5000\",\n                        \"IpProtocol\": \"tcp\",\n                        \"ToPort\": \"10000\"\n                    }\n                ],\n                \"VpcId\": {\n                    \"Ref\": \"Vpc\"\n                }\n            },\n            \"Type\": \"AWS::EC2::SecurityGroup\"\n        },\n        \"Vpc\": {\n            \"Properties\": {\n                \"CidrBlock\": {\n                    \"Fn::FindInMap\": [\n                        \"VpcCidrs\",\n                        \"vpc\",\n                        \"cidr\"\n                    ]\n                },\n                \"EnableDnsHostnames\": \"true\",\n                \"EnableDnsSupport\": \"true\",\n                \"Tags\": [\n                    {\n                        \"Key\": \"Name\",\n                        \"Value\": {\n                            \"Fn::Join\": [\n                                \"-\",\n                                [\n                                    {\n                                        \"Ref\": \"AWS::StackName\"\n                                    },\n                                    \"VPC\"\n                                ]\n                            ]\n                        }\n                    }\n                ]\n            },\n            \"Type\": \"AWS::EC2::VPC\"\n        }\n    }\n}"
  },
  {
    "path": "example/starter-cluster/starter-cluster-requirements.txt",
    "content": "boto3>=1.4.2\nclick>=6.6\ndocker-py==1.10.6\nPyYAML>=3.12\nuniverse>=0.1.0\ndocker-compose>=1.9.0\n"
  },
  {
    "path": "example/system-diagnostics/system_diagnostics_logger.py",
    "content": "#!/usr/bin/env python\n\nimport json\nimport psutil\nimport time\n\nclass DiagnosticsLogger(object):\n    def __init__(self, interval=5):\n        self.interval = interval\n        self.last_cpu_times = {}  # pid -> (user, sys)\n\n    def run(self):\n        while True:\n            cpu_times, chrome_reset = self.cpu_times()\n            print(json.dumps({\n                'time': time.time(),\n                'cpu_times': cpu_times,\n                'cpu_percent': psutil.cpu_percent(percpu=True),\n                'chrome_reset': chrome_reset,\n            }), flush=True)\n            self.chrome_reset = False\n            time.sleep(self.interval)\n\n    def get_chrome_procs(self):\n        def is_chrome(proc):\n            try:\n                return proc.name() == 'chrome'\n            except psutil.ZombieProcess:\n                return False\n        return [p for p in psutil.process_iter() if is_chrome(p)]\n\n    def cpu_times(self):\n        ''' return {pid: {'user': 0.0, 'sys': 0.0}}, chrome_reset '''\n        chrome_procs = self.get_chrome_procs()\n        new_pids = {p.pid for p in chrome_procs}\n        old_pids = {pid for pid in self.last_cpu_times}\n        try:\n            cpu_times = {p.pid: p.cpu_times() for p in chrome_procs}\n        except psutil.NoSuchProcess:\n            # Chrome restarted since fetching the new pids above. Better luck next time.\n            return {}, True\n        if new_pids != old_pids:\n            # We don't know when the Chrome procs were restarted, so don't\n            # return elapsed time until next run.\n            self.last_cpu_times = cpu_times\n            return {}, True\n        # Same chrome pids as last run: measure the elapsed cpu times\n        ordered_old_times = (self.last_cpu_times[p.pid] for p in chrome_procs)\n        ordered_new_times = (cpu_times[p.pid] for p in chrome_procs)\n        cpu_times_diff = {p.pid: {'user': (t[0] - l[0]) / self.interval, 'sys': (t[1] - l[1]) / self.interval}\n                for (p, t, l) in zip(chrome_procs, ordered_new_times, ordered_old_times)}\n        self.last_cpu_times = cpu_times\n        return cpu_times_diff, False\n\nif __name__ == '__main__':\n    DiagnosticsLogger().run()\n\n"
  },
  {
    "path": "setup.py",
    "content": "from setuptools import setup, find_packages\n\nsetup(name='universe',\n      version='0.21.5',\n      description=\"Universe: a software platform for measuring and training an AI's general intelligence across the world's supply of games, websites and other applications.\",\n      url='https://github.com/openai/universe',\n      author='OpenAI',\n      author_email='universe@openai.com',\n      packages=[package for package in find_packages()\n                if package.startswith('universe')],\n      install_requires=[\n          'autobahn>=0.16.0',\n          'docker-py==1.10.3',\n          'docker-pycreds==0.2.1',\n          'fastzbarlight>=0.0.13',\n          'go-vncdriver>=0.4.8',\n          'gym>=0.8.1',\n          'Pillow>=3.3.0',\n          'PyYAML>=3.12',\n          'six>=1.10.0',\n          'twisted>=16.5.0',\n          'ujson>=1.35',\n      ],\n      package_data={'universe': ['runtimes.yml', 'runtimes/flashgames.json']},\n      tests_require=['pytest'],\n      extras_require={\n          'atari': 'gym[atari]',\n      }\n      )\n"
  },
  {
    "path": "test.dockerfile",
    "content": "FROM quay.io/openai/universe\n\nRUN pip install tox\n\n# Upload our actual code\nWORKDIR /usr/local/universe/\nCOPY . ./\n\n# Run tox. Keep printing so Travis knows we're alive.\nCMD [\"bash\", \"-c\", \"( while true; do echo '.'; sleep 60; done ) & tox\"]\n"
  },
  {
    "path": "tests/functional/test_core_envs_semantics.py",
    "content": "import logging\nimport pytest\n\nimport gym\nimport numpy as np\nfrom PIL import Image\nfrom gym import spaces\nfrom universe import wrappers\nfrom universe.envs.vnc_core_env import translator\n\ndef show(obs):\n    Image.fromarray(obs).show()\n\nclass AtariMatcher(object):\n    def translator(self, env):\n        return translator.AtariTranslator(env)\n\n    def crop(self, obs):\n        return obs[20:210, :160, :]\n\n    def assert_match(self, obs, vnc_obs, extra_info=None, stage=None):\n        # Crop out the mouse\n        vnc_obs_cropped = self.crop(vnc_obs)\n        obs_cropped = self.crop(obs)\n\n        if not np.all(vnc_obs_cropped == obs_cropped):\n            show(vnc_obs_cropped)\n            show(obs_cropped)\n            show(vnc_obs_cropped - obs_cropped)\n            assert False, '[{}] Observations do not match: vnc_obs_cropped={} obs_cropped={} extra_info={}'.format(stage, vnc_obs_cropped, obs_cropped, extra_info)\n\n# Wraps an Atari-over-VNC env so that it behaves like a vectorized vanilla Atari env\ndef atari_vnc_wrapper(env):\n    env = wrappers.Vision(env)\n    env = wrappers.GymCoreAction(env)\n    return env\n\nclass CartPoleLowDMatcher(object):\n    def translator(self, env):\n        return translator.CartPoleTranslator(env)\n\n    def assert_match(self, obs, vnc_obs, extra_info=None, stage=None):\n        assert np.all(np.isclose(obs, vnc_obs)), '[{}] Observations do not match: vnc_obs={} obs={}'.format(stage, vnc_obs, obs)\n\ndef reset(matcher, env, vnc_env, stage=None):\n    obs = env.reset()\n    vnc_obs = vnc_env.reset()\n    matcher.assert_match(obs, vnc_obs, stage=stage)\n\ndef rollout(matcher, env, vnc_env, timestep_limit=None, stage=None):\n    count = 0\n    actions = matcher.translator(env)\n\n    done = None\n    while True:\n        action = env.action_space.sample()\n\n        obs, reward, done, info = env.step(action)\n        if done:\n            # Account for remote auto-reset\n            obs = env.reset()\n\n        vnc_obs, vnc_reward, vnc_done, vnc_info = vnc_env.step(action)\n        assert reward == vnc_reward\n        assert done == vnc_done\n        assert vnc_info['stats.reward.count'] == 1\n        matcher.assert_match(obs, vnc_obs, {'reward': reward, 'done': done}, stage=stage)\n\n        count += 1\n        if done or (timestep_limit is not None and count >= timestep_limit):\n            break\n\n# TODO: we should have auto-env spinup\nspecs = [\n    (gym.spec('gym-core.PongDeterministicSync-v3'), AtariMatcher(), atari_vnc_wrapper),\n    (gym.spec('gym-core.PitfallDeterministicSync-v3'), AtariMatcher(), atari_vnc_wrapper),\n\n    # This test is still broken. Looks like we're not piping the seed\n    # to the CartPole env behind VNC\n#    (gym.spec('gym-core.CartPoleLowDSync-v0'), CartPoleLowDMatcher())\n]\n\n@pytest.mark.parametrize(\"spec,matcher,wrapper\", specs)\ndef test_nice_vnc_semantics_match(spec, matcher, wrapper):\n    # Check that when running over VNC or using the raw environment,\n    # semantics match exactly.\n    gym.undo_logger_setup()\n    logging.getLogger().setLevel(logging.INFO)\n\n    spaces.seed(0)\n\n    vnc_env = spec.make()\n    if vnc_env.metadata.get('configure.required', False):\n        vnc_env.configure(remotes=1)\n    vnc_env = wrapper(vnc_env)\n    vnc_env = wrappers.Unvectorize(vnc_env)\n\n    env = gym.make(spec._kwargs['gym_core_id'])\n\n    env.seed(0)\n    vnc_env.seed(0)\n\n    # Check that reset observations work\n    reset(matcher, env, vnc_env, stage='initial reset')\n\n    # Check a full rollout\n    rollout(matcher, env, vnc_env, timestep_limit=50, stage='50 steps')\n\n    # Reset to start a new episode\n    reset(matcher, env, vnc_env, stage='reset to new episode')\n\n    # Check that a step into the next episode works\n    rollout(matcher, env, vnc_env, timestep_limit=1, stage='1 step in new episode')\n\n    # Make sure env can be reseeded\n    env.seed(1)\n    vnc_env.seed(1)\n    reset(matcher, env, vnc_env, 'reseeded reset')\n    rollout(matcher, env, vnc_env, timestep_limit=1, stage='reseeded step')\n"
  },
  {
    "path": "tests/functional/test_envs.py",
    "content": "import logging\nimport os\nimport pytest\nimport re\n\nimport gym\nfrom universe import wrappers\nfrom universe.runtimes import registration\n\nlogger = logging.getLogger(__name__)\n\n# Choose a sample from each category\n# TODO: Add more comprehensive test that runs all envs\ntest_envs = [\n    # 'gym-core.PongShortSync-v3',\n    # 'gym-core.CartPoleLowDSync-v0',\n    'flashgames.DuskDrive-v0',\n    'internet.SlitherIO-v0',\n    # 'wob.DragBox-v0',\n]\n\n@pytest.mark.parametrize('env_id', test_envs)\ndef test_smoke(env_id):\n    \"\"\"Check that environments start up without errors and that we can extract rewards and observations\"\"\"\n    gym.undo_logger_setup()\n    logging.getLogger().setLevel(logging.INFO)\n\n    env = gym.make(env_id)\n    if env.metadata.get('configure.required', False):\n        if os.environ.get('FORCE_LATEST_UNIVERSE_DOCKER_RUNTIMES'):  # Used to test universe-envs in CI\n            configure_with_latest_docker_runtime_tag(env)\n        else:\n            env.configure(remotes=1)\n\n    env = wrappers.Unvectorize(env)\n\n    env.reset()\n    _rollout(env, timestep_limit=60*30) # Check a rollout\n\ndef _rollout(env, timestep_limit=None):\n    \"\"\"\n    Test that a rollout follows our desired format. Includes the following checks:\n\n    1. The environment resets and provides an observation within our timestep_limit\n    2. Done signals map to the following:\n\n        done=True => Episode over (sent once at end of episode)\n        done=None => Resetting, agent takes no actions until done=False again\n        done=False => Episode is running, agent should take actions\n    \"\"\"\n    count = 0\n    episode_state = \"resetting\"\n\n    while True:\n        obs, reward, done, info = env.step([])  # Step with noop action\n        count += 1\n\n        if episode_state == 'resetting':\n            if done is None:  # Still resetting\n                assert obs is None\n                continue\n            elif done is False:\n                episode_state = 'running'\n\n        if episode_state == 'running':\n            assert done is False\n            assert isinstance(reward, float)\n            assert isinstance(done, bool), \"Received done=None before done=True\"\n            # TODO: Remove this None check after we fix done=None semantics\n            if obs is not None:\n                assert obs['vision'].shape == (768, 1024, 3)\n            break\n\n        if timestep_limit is not None and count >= timestep_limit:\n            assert episode_state == 'running', \"Failed to finish resetting in timestep limit\"\n            break\n\n        # if timestep_limit is not None and count >= timestep_limit:\n        #     self.assertTrue(completed_full_episode, \"Failed to complete a full episode in timestep limit\")\n        #     break\n\ndef configure_with_latest_docker_runtime_tag(env):\n    original_image = registration.runtime_spec(env.spec.tags['runtime']).image\n    latest_image = re.sub(r':.*', ':latest', original_image)\n    logger.info(\"Using latest image: {}\".format(latest_image))\n    env.configure(remotes=1, docker_image=latest_image)\n"
  },
  {
    "path": "tox.ini",
    "content": "# Tox (http://tox.testrun.org/) is a tool for running tests\n# in multiple virtualenvs. This configuration file will run the\n# test suite on all supported python versions. To use it, \"pip install tox\"\n# and then run \"tox\" from this directory.\n\n[tox]\nenvlist = py27, py35\nskipsdist=True\n\n[testenv]\npassenv=DISPLAY DOCKER_USERNAME DOCKER_PASSWORD FORCE_LATEST_UNIVERSE_DOCKER_RUNTIMES TRAVIS*\ndeps =\n    pytest\n    gym[atari]<0.9\n    docker-py==1.10.3\n    Pillow\n    autobahn\n    twisted\n    ujson\n    boto\ncommands =\n    pip install -e /usr/local/universe\n    pytest {posargs}\n"
  },
  {
    "path": "universe/__init__.py",
    "content": "# Welcome to Universe!\n#\n# This file contains the client-side registry of environments.\n\nimport logging\nimport os\n\n# Suppress Twisted's warning about service_identity not being installed.\n# We don't need service_identity right now and don't want to take it on\n# as a dependency just to suppress this warning.\nimport warnings\nwarnings.filterwarnings(\n    'ignore',\n    message='You do not have a working installation of the service_identity'\n)\n\n\nfrom gym.envs.registration import register\n\nimport universe.scoreboard\nimport universe.configuration\nfrom universe import error, envs\nfrom universe.remotes import docker_remote\nfrom universe.rewarder import merge_infos\nfrom universe.runtimes.registration import runtime_spec\n\n__all__ = [\n    'configuration', 'envs', 'error', 'kube', 'pyprofile', 'remotes', 'rewarder', 'runtimes',\n    'scoreboard', 'spaces', 'twisty', 'utils', 'vectorized', 'vncdriver', 'wrappers',\n    'configure_logging', 'docker_image', 'enable_logfile',\n    'logger', 'extra_logger']\n\ndef docker_image(runtime_id):\n    logger.warn('DEPRECATION WARNING: universe.docker_image(runtime_id) is deprecated and will be removed soon. Use runtime_spec(runtime_id).image instead. ')\n    return runtime_spec(runtime_id).image\n\n\n#################### Logging configuration ####################\n\nlogger = logging.getLogger(__name__)\nextra_logger = logging.getLogger('universe.extra.'+__name__)\n\n_logging_configured = False\n\ndef enable_logfile(path=None):\n    raise error.Error('Renamed to \"universe.configure_logging()\"')\n\ndef configure_logging(path=None):\n    \"\"\"\n    Set up log levels, and split verbose logs to a file\n\n        Configure the client-side environment logs to print\n        to stdout at \"info\" level, and also to print to a\n        verbose log file located at /tmp/universe-<pid>.log\n        or another path you specify at \"debug\" level.\n        We suggest calling this method at the beginning of\n        your script.\n    \"\"\"\n\n    global _logging_configured\n    if _logging_configured:\n        return\n    _logging_configured = True\n\n    if path is False:\n        # Disable logfile\n        return\n    elif path is None:\n        path = '/tmp/universe-{}.log'.format(os.getpid())\n\n    logger.info('Writing logs to file: %s', path)\n    # Turn up extra_logger level\n    extra_logger.setLevel(logging.DEBUG)\n    if path == '-':\n        return\n\n    # Add file handler to root logger\n    root_logger = logging.getLogger()\n    formatter = logging.Formatter('[%(asctime)s] %(message)s')\n    handler = logging.FileHandler(path, 'w', encoding='UTF-8')\n    handler.setFormatter(formatter)\n    root_logger.addHandler(handler)\n\n    # Set extra_logger to *only* use file handler\n    extra_logger.propagate = False\n    extra_logger.addHandler(handler)\n\n############### Environment registration and runtime specification ###############\n#\n#    Universe environments are registered with the gym\n#    environment registry when the universe module\n#    is imported. We use the \"tags\" field to store\n#    additional data specific to Universe.\n\n\n#------------------------ Gym core environments -----------------------#\n#     Asynchronous VNC versions of core gym environments,\n#     such as CartPole and Pong\n\n# Note on metadata:\n#    Environments send on-screen metadata: the current time, and the\n#    time the last action was received from the agent. This timestamp\n#    data is used to compute action and observation lags. For core\n#    environments, this data is sent using on-screen pixels that encode\n#    timestamps.\n\nmetadata_pixels = {\n    'type': 'pixels',\n}\n\n# Should be exactly the same as CartPole-v0\nregister(\n    id='gym-core.CartPoleLowDSync-v0',\n    entry_point='universe.wrappers:WrappedGymCoreSyncEnv',\n    max_episode_steps=500,\n    tags={\n        'vnc': True,\n        'runtime': 'gym-core',\n        'metadata_encoding': metadata_pixels,\n    },\n    kwargs={\n        'rewarder_observation': True,\n        'gym_core_id': 'CartPole-v0',\n},\n    trials=2,\n)\n\n# Dynamics should match CartPole-v0, but have pixel observations\nregister(\n    id='gym-core.CartPoleSync-v0',\n    entry_point='universe.wrappers:WrappedGymCoreSyncEnv',\n    max_episode_steps=500,\n    tags={\n        'vnc': True,\n        'runtime': 'gym-core',\n        'metadata_encoding': metadata_pixels,\n    },\n    kwargs={\n        'gym_core_id': 'CartPole-v0',\n    },\n    trials=2,\n)\n\n# Async cartpole with 4-d observations\nregister(\n    id='gym-core.CartPoleLowD-v0',\n    entry_point='universe.wrappers:WrappedGymCoreEnv',\n    max_episode_steps=500,\n    tags={\n        'vnc': True,\n        'runtime': 'gym-core',\n        'metadata_encoding': metadata_pixels,\n    },\n    kwargs={\n        'rewarder_observation': True,\n        'gym_core_id': 'CartPole-v0',\n    },\n    trials=2,\n)\n\nregister(\n    id='gym-core.CartPole-v0',\n    entry_point='universe.wrappers:WrappedGymCoreEnv',\n    max_episode_steps=500,\n    tags={\n        'vnc': True,\n        'runtime': 'gym-core',\n        'metadata_encoding': metadata_pixels,\n    },\n    kwargs={\n        'gym_core_id': 'CartPole-v0',\n    },\n    trials=2,\n)\n\n# gym-core.Atari\nfor game in ['air_raid', 'alien', 'amidar', 'assault', 'asterix',\n             'asteroids', 'atlantis', 'bank_heist', 'battle_zone',\n             'beam_rider', 'berzerk', 'bowling', 'boxing', 'breakout',\n             'carnival', 'centipede', 'chopper_command', 'crazy_climber',\n             'demon_attack', 'double_dunk', 'elevator_action', 'enduro',\n             'fishing_derby', 'freeway', 'frostbite', 'gopher', 'gravitar',\n             'ice_hockey', 'jamesbond', 'journey_escape', 'kangaroo', 'krull',\n             'kung_fu_master', 'montezuma_revenge', 'ms_pacman',\n             'name_this_game', 'phoenix', 'pitfall', 'pong', 'pooyan',\n             'private_eye', 'qbert', 'riverraid', 'road_runner', 'robotank',\n             'seaquest', 'skiing', 'solaris', 'space_invaders', 'star_gunner',\n             'tennis', 'time_pilot', 'tutankham', 'up_n_down', 'venture',\n             'video_pinball', 'wizard_of_wor', 'yars_revenge', 'zaxxon']:\n    # space_invaders should yield SpaceInvaders-v0 and SpaceInvaders-ram-v0\n    base = ''.join([g.capitalize() for g in game.split('_')]) # SpaceInvaders\n\n    for version in [0, 3]:\n        gym_core_id = '{}-v{}'.format(base, version) # e.g. SpaceInvaders-v3\n        register(\n            id='gym-core.{}'.format(gym_core_id),\n            entry_point='universe.wrappers:WrappedGymCoreEnv',\n            max_episode_steps=100000,\n            tags={\n                'vnc': True,\n                'atari': True,\n                'runtime': 'gym-core',\n                'metadata_encoding': metadata_pixels,\n            },\n            kwargs={\n                'gym_core_id': gym_core_id,\n            },\n        )\n\n        register(\n            id='gym-core.{}Sync-v{}'.format(base, version),\n            entry_point='universe.wrappers:WrappedGymCoreSyncEnv',\n            max_episode_steps=100000,\n            tags={\n                'vnc': True,\n                'atari': True,\n                'runtime': 'gym-core',\n                'metadata_encoding': metadata_pixels,\n            },\n            kwargs={\n                'gym_core_id': gym_core_id,\n            },\n        )\n\n        register(\n            id='gym-core.{}30FPS-v{}'.format(base, version),\n            entry_point='universe.wrappers:WrappedGymCoreEnv',\n            max_episode_steps=100000,\n            tags={\n                'vnc': True,\n                'atari': True,\n                'runtime': 'gym-core',\n                'metadata_encoding': metadata_pixels,\n            },\n            kwargs={\n                'gym_core_id': gym_core_id,\n                'fps': 30,\n            },\n        )\n\n        register(\n            id='gym-core.{}Slow-v{}'.format(base, version),\n            entry_point='universe.wrappers:WrappedGymCoreEnv',\n            max_episode_steps=100000,\n            tags={\n                'vnc': True,\n                'atari': True,\n                'runtime': 'gym-core',\n                'metadata_encoding': metadata_pixels,\n            },\n            kwargs={\n                'gym_core_id': gym_core_id,\n                'fps': 15,\n            },\n        )\n\n        deterministic_gym_core_id = '{}Deterministic-v{}'.format(base, version) # e.g. SpaceInvadersDeterministic-v3\n\n        register(\n            id='gym-core.{}Deterministic-v{}'.format(base, version),\n            entry_point='universe.wrappers:WrappedGymCoreEnv',\n            max_episode_steps=100000,\n            tags={\n                'vnc': True,\n                'atari': True,\n                'runtime': 'gym-core',\n                'metadata_encoding': metadata_pixels,\n            },\n            kwargs={\n                'gym_core_id': deterministic_gym_core_id,\n            },\n        )\n        register(\n            id='gym-core.{}DeterministicSlow-v{}'.format(base, version),\n            entry_point='universe.wrappers:WrappedGymCoreEnv',\n            max_episode_steps=75000,\n            tags={\n                'vnc': True,\n                'atari': True,\n                'runtime': 'gym-core',\n                'metadata_encoding': metadata_pixels,\n            },\n            kwargs={\n                'gym_core_id': deterministic_gym_core_id,\n                'fps': 15,\n            },\n        )\n        register(\n            id='gym-core.{}DeterministicSync-v{}'.format(base, version),\n            entry_point='universe.wrappers:WrappedGymCoreSyncEnv',\n            max_episode_steps=75000,\n            tags={\n                'vnc': True,\n                'atari': True,\n                'runtime': 'gym-core',\n                'metadata_encoding': metadata_pixels,\n            },\n            kwargs={\n                'gym_core_id': deterministic_gym_core_id,\n            },\n        )\n\n        no_frameskip_gym_core_id = '{}NoFrameskip-v{}'.format(base, version) # e.g. SpaceInvadersNoFrameskip-v3\n        register(\n            id='gym-core.{}NoFrameskip-v{}'.format(base, version),\n            entry_point='universe.wrappers:WrappedGymCoreEnv',\n            max_episode_steps=400000,\n            tags={\n                'vnc': True,\n                'atari': True,\n                'runtime': 'gym-core',\n                'metadata_encoding': metadata_pixels,\n            },\n            kwargs={\n                'gym_core_id': no_frameskip_gym_core_id,\n            },\n        )\n\n#------------------------ Flash game environments ------------------------#\n#     Browser-based flash games, run locally\n#     in Chrome within a Docker container\n\n# Note on metadata: flashgames send time metadata using\n# an on-screen QR code\n\nmetadata_v1 = {\n    'type': 'qrcode',\n    'x': 914,\n    'y': 658,\n    'width': 100,\n    'height': 100,\n}\n\n# Please keep this registry mirrored with the benchmarks in universe-envs/flashgames/gym_flashgames/__init__.py\n# You can use universe-envs/flashgames/bin/manage export_env_ids_for_registration to generate this list.\nfor game in [\n    'flashgames.1001ArabianNights-v0',\n    'flashgames.21Balloons-v0',\n    'flashgames.30Seconds-v0',\n    'flashgames.3FootNinja-v0',\n    'flashgames.3FootNinjaIi-v0',\n    'flashgames.3dBuggyRacing-v0',\n    'flashgames.3dClassicRacing-v0',\n    'flashgames.3dFlashRacer-v0',\n    'flashgames.3dFuriousDriver-v0',\n    'flashgames.3dLaSupercars-v0',\n    'flashgames.3dLaSupercars2-v0',\n    'flashgames.3dMuscleCarRacer-v0',\n    'flashgames.3dRallyFever-v0',\n    'flashgames.3dRookieCop-v0',\n    'flashgames.3dSpeedFever-v0',\n    'flashgames.3dSportRampage-v0',\n    'flashgames.3dSuperRide-v0',\n    'flashgames.3dTestDrive-v0',\n    'flashgames.3dTruckInTheWoods-v0',\n    'flashgames.3dUrbanMadness-v0',\n    'flashgames.3dUrbanMadness2-v0',\n    'flashgames.4x4Monster3-v0',\n    'flashgames.99BricksTheLegendOfGarry-v0',\n    'flashgames.AWeekendAtTweetys-v0',\n    'flashgames.AbductionGrannysVersion-v0',\n    'flashgames.AchilliaTheGame-v0',\n    'flashgames.AcidFactory-v0',\n    'flashgames.AdrenalineChaser-v0',\n    'flashgames.AdventuresOfBloo-v0',\n    'flashgames.AeroDefense-v0',\n    'flashgames.AerobaticMaster2-v0',\n    'flashgames.Aerorumble-v0',\n    'flashgames.AirWar1941-v0',\n    'flashgames.AircraftRace-v0',\n    'flashgames.AladdinAndTheWonderLamp-v0',\n    'flashgames.AlchemySwap-v0',\n    'flashgames.AliceNixsAdventure-v0',\n    'flashgames.Alien-v0',\n    'flashgames.AlienAssault-v0',\n    'flashgames.AlienTransporter-v0',\n    'flashgames.AmericanRacing-v0',\n    'flashgames.AmericanRacingLvl2-v0',\n    'flashgames.AmericanRacingLvl3-v0',\n    'flashgames.AmericanRacingLvl4-v0',\n    'flashgames.AmericanRacingLvl5-v0',\n    'flashgames.AmericanRacingLvl6-v0',\n    'flashgames.AmericanRacingLvl7-v0',\n    'flashgames.AmericanRacingLvl8-v0',\n    'flashgames.AmericanRacingLvl9-v0',\n    'flashgames.AmericanRacingLvl10-v0',\n    'flashgames.AmericanRacingLvl11-v0',\n    'flashgames.AmericanRacingLvl12-v0',\n    'flashgames.AmericanRacingLvl13-v0',\n    'flashgames.AmericanRacingLvl14-v0',\n    'flashgames.AmericanRacingLvl15-v0',\n    'flashgames.AmericanRacingLvl16-v0',\n    'flashgames.AmericanRacingLvl17-v0',\n    'flashgames.AmericanRacingLvl18-v0',\n    'flashgames.AmericanRacingLvl19-v0',\n    'flashgames.AmericanRacingLvl20-v0',\n    'flashgames.AmericanRacingLvl21-v0',\n    'flashgames.AmericanRacingLvl22-v0',\n    'flashgames.AmericanRacingLvl23-v0',\n    'flashgames.AmericanRacingLvl24-v0',\n    'flashgames.AmericanRacingLvl25-v0',\n    'flashgames.AmericanRacing2-v0',\n    'flashgames.AmigoPancho-v0',\n    'flashgames.AmigoPancho3SheriffSancho-v0',\n    'flashgames.AmigoPancho4Travel-v0',\n    'flashgames.AmigoPanchoInAfghanistan-v0',\n    'flashgames.AngryNewsVan-v0',\n    'flashgames.AnimeClicker2-v0',\n    'flashgames.AnotherLife2-v0',\n    'flashgames.AntsGlider-v0',\n    'flashgames.AnywayFish-v0',\n    'flashgames.ArkanoidGame-v0',\n    'flashgames.ArmyPursuit-v0',\n    'flashgames.ArmySpeeder-v0',\n    'flashgames.AspenSecret-v0',\n    'flashgames.AsphaltMadness-v0',\n    'flashgames.AssembleBots-v0',\n    'flashgames.Astroman-v0',\n    'flashgames.AtvRide-v0',\n    'flashgames.Autoattack-v0',\n    'flashgames.Avalancher-v0',\n    'flashgames.AwesomeRun2-v0',\n    'flashgames.BackHome-v0',\n    'flashgames.BaldEagleJigsawPuzzle-v0',\n    'flashgames.BalloonGods-v0',\n    'flashgames.BalloonHero-v0',\n    'flashgames.BalloonsPop-v0',\n    'flashgames.Basement-v0',\n    'flashgames.BeachCrazy-v0',\n    'flashgames.BearInSuperActionAdventure-v0',\n    'flashgames.BigWheelsTrial-v0',\n    'flashgames.BikeTrial-v0',\n    'flashgames.BikeTrial2-v0',\n    'flashgames.BikeTrial3-v0',\n    'flashgames.BikeTrial4-v0',\n    'flashgames.Bimmin2-v0',\n    'flashgames.BirdSlice-v0',\n    'flashgames.BirdsFeeding-v0',\n    'flashgames.BlackAndWhiteEscapeTheOffice-v0',\n    'flashgames.BlackForce-v0',\n    'flashgames.BlackInk-v0',\n    'flashgames.BlackRacerJigsawPuzzle-v0',\n    'flashgames.BlacksmithLab-v0',\n    'flashgames.BlastTheMooks-v0',\n    'flashgames.BlastTheMooksLevelPack-v0',\n    'flashgames.Blix-v0',\n    'flashgames.BlobsStory-v0',\n    'flashgames.BlockysEscape-v0',\n    'flashgames.BloodbathBay-v0',\n    'flashgames.BloodyMonstersPack2-v0',\n    'flashgames.Blosics2-v0',\n    'flashgames.Blosics2LevelPack-v0',\n    'flashgames.Blosics3-v0',\n    'flashgames.BoatDrive-v0',\n    'flashgames.BobbyNutcaseMotoJumping-v0',\n    'flashgames.BoltThrough-v0',\n    'flashgames.BombIt4-v0',\n    'flashgames.BombIt6-v0',\n    'flashgames.BombThePiratePigs-v0',\n    'flashgames.BottleCaps-v0',\n    'flashgames.BouncyCannon-v0',\n    'flashgames.BoxBlocks-v0',\n    'flashgames.BoxRacers-v0',\n    'flashgames.BoxingLiveRound2-v0',\n    'flashgames.BraveAstronaut-v0',\n    'flashgames.BraveHeads-v0',\n    'flashgames.BubbleAdventures-v0',\n    'flashgames.BubbleBlubbs-v0',\n    'flashgames.BubbleGlee-v0',\n    'flashgames.BubbleHit-v0',\n    'flashgames.BubbleHitChristmas-v0',\n    'flashgames.BubbleHitHalloween-v0',\n    'flashgames.BubbleHitPonyParade-v0',\n    'flashgames.BubbleHitValentine-v0',\n    'flashgames.BubbleMover-v0',\n    'flashgames.BubblePop-v0',\n    'flashgames.BubblePopAdventure-v0',\n    'flashgames.BubbleRubble-v0',\n    'flashgames.BubbleRubbleTheIsland-v0',\n    'flashgames.BubbleShooterChallenge-v0',\n    'flashgames.BubbleSlasher-v0',\n    'flashgames.BubbleTanksTd15-v0',\n    'flashgames.BubbleTub-v0',\n    'flashgames.BubblesInSpace-v0',\n    'flashgames.BugsGotGuns-v0',\n    'flashgames.BuildBalance2-v0',\n    'flashgames.BulletFury-v0',\n    'flashgames.BulletHeaven-v0',\n    'flashgames.BulletHeaven2-v0',\n    'flashgames.Bullets-v0',\n    'flashgames.BullfrogJigsawPuzzle-v0',\n    'flashgames.BumbleTumble-v0',\n    'flashgames.BunnyAndSquirt-v0',\n    'flashgames.BunnyCannon-v0',\n    'flashgames.BurgerBar-v0',\n    'flashgames.BushRoyalRampage-v0',\n    'flashgames.Business-v0',\n    'flashgames.BusinessmanSimulator-v0',\n    'flashgames.CableCapers2-v0',\n    'flashgames.CakeQuest-v0',\n    'flashgames.CandyMatch-v0',\n    'flashgames.CandyMatchCrush-v0',\n    'flashgames.CandySlider-v0',\n    'flashgames.Canopy-v0',\n    'flashgames.CanyonValleyRally-v0',\n    'flashgames.CaptainNutty-v0',\n    'flashgames.CaptainSteelbounce-v0',\n    'flashgames.CardinalQuest2-v0',\n    'flashgames.CarrotFantasy-v0',\n    'flashgames.CarrotFantasy2Desert-v0',\n    'flashgames.CarrotFantasy2Undersea-v0',\n    'flashgames.CarrotFantasyExtreme2-v0',\n    'flashgames.CarrotFantasyExtreme3-v0',\n    'flashgames.CarsVsRobots-v0',\n    'flashgames.CartoonCandy-v0',\n    'flashgames.CastleRush-v0',\n    'flashgames.CastleSolitaire-v0',\n    'flashgames.CatGodVsSunKing2-v0',\n    'flashgames.CatchTheStar-v0',\n    'flashgames.Cattlepult-v0',\n    'flashgames.CattlepultPlayerPack-v0',\n    'flashgames.CavemanEscape-v0',\n    'flashgames.CemeteryRoad-v0',\n    'flashgames.CharlieTheDuck-v0',\n    'flashgames.Chefday-v0',\n    'flashgames.ChickCannont-v0',\n    'flashgames.ChickInduce-v0',\n    'flashgames.ChockABox-v0',\n    'flashgames.ChristmasBubbles-v0',\n    'flashgames.ChromaticTowerDefense-v0',\n    'flashgames.ChuteAcademy-v0',\n    'flashgames.CircuitSuperCarsRacing-v0',\n    'flashgames.CitySiege3FubarLevelPack-v0',\n    'flashgames.CitySkyTyping-v0',\n    'flashgames.ClaustrophobiumFourStepsFromDeath-v0',\n    'flashgames.Cleopatra-v0',\n    'flashgames.ClickerMonsters-v0',\n    'flashgames.ClimbOrDrown2-v0',\n    'flashgames.ClimberGuy-v0',\n    'flashgames.ClimbingSanta-v0',\n    'flashgames.CloseCombat-v0',\n    'flashgames.Cloud9-v0',\n    'flashgames.ClubNitro-v0',\n    'flashgames.Clusterobot-v0',\n    'flashgames.CoastRunners-v0',\n    'flashgames.CoasterCars2Contact-v0',\n    'flashgames.CoasterCars2Megacross-v0',\n    'flashgames.CoasterCarsBridgesTrack-v0',\n    'flashgames.CoasterCarsCJackTrack-v0',\n    'flashgames.CoasterRacer-v0',\n    'flashgames.CoasterRacerLvl2-v0',\n    'flashgames.CoasterRacerLvl3-v0',\n    'flashgames.CoasterRacerLvl4-v0',\n    'flashgames.CoasterRacerLvl5-v0',\n    'flashgames.CoasterRacerLvl6-v0',\n    'flashgames.CoasterRacerLvl7-v0',\n    'flashgames.CoasterRacerLvl8-v0',\n    'flashgames.CoasterRacer2-v0',\n    'flashgames.CoasterRacer2Lvl2-v0',\n    'flashgames.CoasterRacer2Lvl3-v0',\n    'flashgames.CoasterRacer2Lvl4-v0',\n    'flashgames.CoasterRacer2Lvl5-v0',\n    'flashgames.CoasterRacer2Lvl6-v0',\n    'flashgames.CoasterRacer2Lvl7-v0',\n    'flashgames.CoasterRacer2Lvl8-v0',\n    'flashgames.CoasterRacer2Lvl9-v0',\n    'flashgames.CoasterRacer2Lvl10-v0',\n    'flashgames.CoasterRacer2Bike-v0',\n    'flashgames.CoasterRacer3-v0',\n    'flashgames.CoffeeClicker-v0',\n    'flashgames.ColorZapper-v0',\n    'flashgames.Colordefense-v0',\n    'flashgames.Colorfill-v0',\n    'flashgames.Coloruid-v0',\n    'flashgames.Colorwars-v0',\n    'flashgames.Commando-v0',\n    'flashgames.Commando2-v0',\n    'flashgames.Conjure-v0',\n    'flashgames.Connect2-v0',\n    'flashgames.Conquerium-v0',\n    'flashgames.Contra3TheAlienWars-v0',\n    'flashgames.Cooliobeat-v0',\n    'flashgames.Cooliodj-v0',\n    'flashgames.CopperheadJigsawPuzzle-v0',\n    'flashgames.CosmicSwitch-v0',\n    'flashgames.CosmoGravity2-v0',\n    'flashgames.CoverOrangeJourneyGangsters-v0',\n    'flashgames.CowboyVsUfos-v0',\n    'flashgames.Crane-v0',\n    'flashgames.CrapImBroke-v0',\n    'flashgames.CrazyDarts-v0',\n    'flashgames.Crazycle-v0',\n    'flashgames.CruiseAdventure-v0',\n    'flashgames.Cruisin-v0',\n    'flashgames.Crumbs2-v0',\n    'flashgames.CrystalCurse-v0',\n    'flashgames.CrystalStoryIi-v0',\n    'flashgames.CupidBubbles-v0',\n    'flashgames.CursedTreasureDontTouchMyGems-v0',\n    'flashgames.CurveFever-v0',\n    'flashgames.DaleAndPeakot-v0',\n    'flashgames.DanceBattle-v0',\n    'flashgames.DancingWithShadows-v0',\n    'flashgames.DartsSim-v0',\n    'flashgames.DaymareInvaders-v0',\n    'flashgames.DeadHungry2-v0',\n    'flashgames.DeathCabin-v0',\n    'flashgames.DeathDiceOverdose-v0',\n    'flashgames.DeepForest3dRace-v0',\n    'flashgames.DeepFreeze-v0',\n    'flashgames.Deliveryman-v0',\n    'flashgames.DetectiveConrad-v0',\n    'flashgames.Devilment-v0',\n    'flashgames.DiamondCrashMania-v0',\n    'flashgames.DigToChina-v0',\n    'flashgames.DinoBubble-v0',\n    'flashgames.DinoMeatHunt3Extra-v0',\n    'flashgames.DirkValentine-v0',\n    'flashgames.DisasterWillStrikeDefender-v0',\n    'flashgames.DisasterWillStrikeUltimateDisaster-v0',\n    'flashgames.DiscoverEurope-v0',\n    'flashgames.Ditloid-v0',\n    'flashgames.DnaLabRush-v0',\n    'flashgames.Dodge-v0',\n    'flashgames.DodgeAndCrash-v0',\n    'flashgames.DolphinVolleyball-v0',\n    'flashgames.DontPanic-v0',\n    'flashgames.DoodleGod2Walkthrough-v0',\n    'flashgames.DotGrowth-v0',\n    'flashgames.Dots-v0',\n    'flashgames.DotsRevamped-v0',\n    'flashgames.DoubleEdged-v0',\n    'flashgames.DoughSnake-v0',\n    'flashgames.DragonChain-v0',\n    'flashgames.DragonChronicles-v0',\n    'flashgames.DragonFortress-v0',\n    'flashgames.DragonFunflap-v0',\n    'flashgames.DragonVsMonster-v0',\n    'flashgames.DrawGems-v0',\n    'flashgames.DreamChristmasLink-v0',\n    'flashgames.DriftRunners-v0',\n    'flashgames.DriftRunners2-v0',\n    'flashgames.DriftRunners3d-v0',\n    'flashgames.Drifters-v0',\n    'flashgames.DrinkBeerNeglectFamily-v0',\n    'flashgames.DriveToWreck-v0',\n    'flashgames.DriveToWreck2-v0',\n    'flashgames.DriveToWreck3-v0',\n    'flashgames.Dropblox-v0',\n    'flashgames.DualDimension-v0',\n    'flashgames.DumperRush-v0',\n    'flashgames.DungeonBlocks-v0',\n    'flashgames.DuskDrive-v0',\n    'flashgames.DuskRacers-v0',\n    'flashgames.EasterBubbles-v0',\n    'flashgames.EasterBunnyCollectCarrots-v0',\n    'flashgames.EasterBunnyEggs-v0',\n    'flashgames.EasterEggSlider-v0',\n    'flashgames.EasterEggsChallenge-v0',\n    'flashgames.EatToWin-v0',\n    'flashgames.EctoHarvest-v0',\n    'flashgames.EffingWorms-v0',\n    'flashgames.EggzBlast-v0',\n    'flashgames.EiffelTowerAtNight-v0',\n    'flashgames.ElClassico-v0',\n    'flashgames.ElainesBakery-v0',\n    'flashgames.EmpireBusiness2Beta-v0',\n    'flashgames.Enhanced-v0',\n    'flashgames.EpicBattleFantasy4-v0',\n    'flashgames.EpicDefender-v0',\n    'flashgames.EpicDerbyRace-v0',\n    'flashgames.EpicTimePirates-v0',\n    'flashgames.EscapeTheRedGiant-v0',\n    'flashgames.EuroKicks2016-v0',\n    'flashgames.EvasiveRacers-v0',\n    'flashgames.EvilMinion-v0',\n    'flashgames.EvilSun-v0',\n    'flashgames.EvolutionRacing-v0',\n    'flashgames.EvolutionRacingLvl2-v0',\n    'flashgames.EvolutionRacingLvl3-v0',\n    'flashgames.EvolutionRacingLvl4-v0',\n    'flashgames.EvolutionRacingLvl5-v0',\n    'flashgames.EvolutionRacingLvl6-v0',\n    'flashgames.EvolutionRacingLvl7-v0',\n    'flashgames.EvolutionRacingLvl8-v0',\n    'flashgames.EvolutionRacingLvl9-v0',\n    'flashgames.EvolutionRacingLvl10-v0',\n    'flashgames.EvolutionRacingLvl11-v0',\n    'flashgames.EvolutionRacingLvl12-v0',\n    'flashgames.EvolutionRacingLvl13-v0',\n    'flashgames.EvolutionRacingLvl14-v0',\n    'flashgames.EvolutionRacingLvl15-v0',\n    'flashgames.EvolutionRacingLvl16-v0',\n    'flashgames.ExperimentalShooter2-v0',\n    'flashgames.ExploreTheCandies-v0',\n    'flashgames.ExtremeAirWars-v0',\n    'flashgames.ExtremeSkiing-v0',\n    'flashgames.F1RacingChallenge-v0',\n    'flashgames.FairyDefense-v0',\n    'flashgames.FallDamage-v0',\n    'flashgames.FarmRush-v0',\n    'flashgames.FasterMiterMaster-v0',\n    'flashgames.FeedMeMoar-v0',\n    'flashgames.FeedOurDoughnutOverlords-v0',\n    'flashgames.Filler-v0',\n    'flashgames.Filler2-v0',\n    'flashgames.FinalNinjaZero-v0',\n    'flashgames.FinalSiege-v0',\n    'flashgames.FindTheCandy3Kids-v0',\n    'flashgames.Firebug-v0',\n    'flashgames.FirefighterCannon-v0',\n    'flashgames.FireworksGame-v0',\n    'flashgames.FishAndDestroy-v0',\n    'flashgames.FishEatFish-v0',\n    'flashgames.FitItQuick-v0',\n    'flashgames.FiveTil-v0',\n    'flashgames.Fizzion-v0',\n    'flashgames.Flagman-v0',\n    'flashgames.FlappyAdventure-v0',\n    'flashgames.FlappyBat-v0',\n    'flashgames.FlappyCopter-v0',\n    'flashgames.FlappyPanda-v0',\n    'flashgames.FlashBombs-v0',\n    'flashgames.FlashDrive-v0',\n    'flashgames.FlashRace-v0',\n    'flashgames.FlashRacer-v0',\n    'flashgames.Flashcycle2-v0',\n    'flashgames.FlashsBounty-v0',\n    'flashgames.FlowerGuardian-v0',\n    'flashgames.FlowerSolitaire-v0',\n    'flashgames.FluffRush-v0',\n    'flashgames.FlyAwayRabbit2-v0',\n    'flashgames.FlyPlane-v0',\n    'flashgames.FlyingCookieQuest-v0',\n    'flashgames.FlyingKiwi-v0',\n    'flashgames.FlyingTest-v0',\n    'flashgames.Foosball2Player-v0',\n    'flashgames.FootballHeads201314Ligue1-v0',\n    'flashgames.FormulaRacer-v0',\n    'flashgames.FormulaRacerLvl2-v0',\n    'flashgames.FormulaRacerLvl3-v0',\n    'flashgames.FormulaRacerLvl4-v0',\n    'flashgames.FormulaRacerLvl5-v0',\n    'flashgames.FormulaRacerLvl6-v0',\n    'flashgames.FormulaRacerLvl7-v0',\n    'flashgames.FormulaRacerLvl8-v0',\n    'flashgames.FormulaRacer2012-v0',\n    'flashgames.FormulaRacer2012Lvl2-v0',\n    'flashgames.FormulaRacer2012Lvl3-v0',\n    'flashgames.FormulaRacer2012Lvl4-v0',\n    'flashgames.FormulaRacer2012Lvl5-v0',\n    'flashgames.FormulaRacer2012Lvl6-v0',\n    'flashgames.FormulaRacer2012Lvl7-v0',\n    'flashgames.FormulaRacer2012Lvl8-v0',\n    'flashgames.FormulaRacer2012Lvl9-v0',\n    'flashgames.FormulaRacer2012Lvl10-v0',\n    'flashgames.FormulaRacer2012Lvl11-v0',\n    'flashgames.FormulaRacer2012Lvl12-v0',\n    'flashgames.FormulaXspeed3d-v0',\n    'flashgames.FoxSnakeJigsawPuzzle-v0',\n    'flashgames.FpaWorld1Remix-v0',\n    'flashgames.FreakyRun-v0',\n    'flashgames.FredFigglehorn-v0',\n    'flashgames.FreeSouls-v0',\n    'flashgames.Free_to_use-v0',\n    'flashgames.FreecellDuplex-v0',\n    'flashgames.FrogEatFlies-v0',\n    'flashgames.Frogged-v0',\n    'flashgames.FrozenImps-v0',\n    'flashgames.FrozenIslandsNewHorizons-v0',\n    'flashgames.Funkostroll-v0',\n    'flashgames.FunnyEaster-v0',\n    'flashgames.GSwitch-v0',\n    'flashgames.GalacticCats-v0',\n    'flashgames.GalacticGems-v0',\n    'flashgames.GalacticGems2-v0',\n    'flashgames.GalacticGems2Accelerated-v0',\n    'flashgames.GalacticGems2LevelPack-v0',\n    'flashgames.GalacticGems2NewFrontiers-v0',\n    'flashgames.GalaxyDefender-v0',\n    'flashgames.GalaxyEvo2-v0',\n    'flashgames.GalaxyMission-v0',\n    'flashgames.GalleonFight-v0',\n    'flashgames.GameInit-v0',\n    'flashgames.Gameinit-v0',\n    'flashgames.GamerMemoryTest-v0',\n    'flashgames.GardenRush-v0',\n    'flashgames.GasSand-v0',\n    'flashgames.GemMania-v0',\n    'flashgames.GemPop-v0',\n    'flashgames.Gemclix-v0',\n    'flashgames.Gemcraft-v0',\n    'flashgames.GemstoneCastle-v0',\n    'flashgames.GhostClimb2Player-v0',\n    'flashgames.GiantsAndDwarvesTd-v0',\n    'flashgames.GlobalRallyRacer-v0',\n    'flashgames.Gloom-v0',\n    'flashgames.Gluey2-v0',\n    'flashgames.Go-v0',\n    'flashgames.GoGreenGo-v0',\n    'flashgames.GoKart3d-v0',\n    'flashgames.Goldextraction-v0',\n    'flashgames.GolfRun-v0',\n    'flashgames.GonAndMon-v0',\n    'flashgames.GrandPrixGo-v0',\n    'flashgames.GrandPrixGo2-v0',\n    'flashgames.GrappleCat-v0',\n    'flashgames.GravityBall-v0',\n    'flashgames.GravityGuy-v0',\n    'flashgames.GravityThruster-v0',\n    'flashgames.GroundBattles-v0',\n    'flashgames.Growbox-v0',\n    'flashgames.GsSoccerWorldCup-v0',\n    'flashgames.GunExpress-v0',\n    'flashgames.GunnerMayhem-v0',\n    'flashgames.GunpowderAndFeathers-v0',\n    'flashgames.HalloweenAdventureRun-v0',\n    'flashgames.HalloweenExplorer-v0',\n    'flashgames.HalloweenJam-v0',\n    'flashgames.HammerBall-v0',\n    'flashgames.Hamsterball-v0',\n    'flashgames.HandsOff-v0',\n    'flashgames.HappyBallz-v0',\n    'flashgames.HappyBees-v0',\n    'flashgames.HappyEasterEggs-v0',\n    'flashgames.Harvest-v0',\n    'flashgames.HarvestDay-v0',\n    'flashgames.Hash-v0',\n    'flashgames.Hearts-v0',\n    'flashgames.HeatRushFuture-v0',\n    'flashgames.HeatRushFutureLvl2-v0',\n    'flashgames.HeatRushFutureLvl3-v0',\n    'flashgames.HeatRushFutureLvl4-v0',\n    'flashgames.HeatRushFutureLvl5-v0',\n    'flashgames.HeatRushFutureLvl6-v0',\n    'flashgames.HeatRushFutureLvl7-v0',\n    'flashgames.HeatRushFutureLvl8-v0',\n    'flashgames.HeatRushFutureLvl9-v0',\n    'flashgames.HeatRushFutureLvl10-v0',\n    'flashgames.HeatRushFutureLvl11-v0',\n    'flashgames.HeatRushFutureLvl12-v0',\n    'flashgames.HeatRushFutureLvl13-v0',\n    'flashgames.HeatRushFutureLvl14-v0',\n    'flashgames.HeatRushFutureLvl15-v0',\n    'flashgames.HeatRushUsa-v0',\n    'flashgames.HeatRushUsaLvl2-v0',\n    'flashgames.HeatRushUsaLvl3-v0',\n    'flashgames.HeatRushUsaLvl4-v0',\n    'flashgames.HeatRushUsaLvl5-v0',\n    'flashgames.HeatRushUsaLvl6-v0',\n    'flashgames.HeatRushUsaLvl7-v0',\n    'flashgames.HeatRushUsaLvl8-v0',\n    'flashgames.HeatRushUsaLvl9-v0',\n    'flashgames.HeatRushUsaLvl10-v0',\n    'flashgames.HeatRushUsaLvl11-v0',\n    'flashgames.HeatRushUsaLvl12-v0',\n    'flashgames.HeatRushUsaLvl13-v0',\n    'flashgames.HeatRushUsaLvl14-v0',\n    'flashgames.HeatRushUsaLvl15-v0',\n    'flashgames.HeatRushUsaLvl16-v0',\n    'flashgames.HeavenAndHell-v0',\n    'flashgames.HeavyLegion2-v0',\n    'flashgames.HeliVsTower-v0',\n    'flashgames.HelicopsTerritories-v0',\n    'flashgames.Helicrane-v0',\n    'flashgames.Helixteus-v0',\n    'flashgames.HelmetBombers3-v0',\n    'flashgames.HeroRoofTop-v0',\n    'flashgames.HeroSimulator-v0',\n    'flashgames.HeroesOfMangaraTheFrostCrown-v0',\n    'flashgames.HexBattles-v0',\n    'flashgames.HeySummer-v0',\n    'flashgames.HighSpeedChase-v0',\n    'flashgames.HighwayRevenge-v0',\n    'flashgames.HiredHeroes-v0',\n    'flashgames.HoldTheFort-v0',\n    'flashgames.HoleInOne-v0',\n    'flashgames.Hotspot-v0',\n    'flashgames.HowDareYou-v0',\n    'flashgames.HungerHunter-v0',\n    'flashgames.HungryLittlePenguins-v0',\n    'flashgames.HungryPiranha-v0',\n    'flashgames.HunterForDismantlers-v0',\n    'flashgames.HyperTravel-v0',\n    'flashgames.IceBlock-v0',\n    'flashgames.IceCreamFromSpace-v0',\n    'flashgames.IceRun-v0',\n    'flashgames.IceSlide-v0',\n    'flashgames.Ics2-v0',\n    'flashgames.IcyGifts2-v0',\n    'flashgames.IdleChop-v0',\n    'flashgames.IdleFarmer-v0',\n    'flashgames.IdleLifting-v0',\n    'flashgames.IdlePlanet-v0',\n    'flashgames.ImitationNationSnakeGame-v0',\n    'flashgames.IncrementalAcceleration-v0',\n    'flashgames.Indefinite-v0',\n    'flashgames.IndependenceDaySlacking2015-v0',\n    'flashgames.InfectonatorSurvivorsAlphaDemo-v0',\n    'flashgames.InfernalMess-v0',\n    'flashgames.Infinitix-v0',\n    'flashgames.InsaneCircle-v0',\n    'flashgames.IntoSpace-v0',\n    'flashgames.IslandDefense-v0',\n    'flashgames.IsoblockerMaster-v0',\n    'flashgames.ItsDarkInHell-v0',\n    'flashgames.JakeTheSnake-v0',\n    'flashgames.JamesTheCircusZebra-v0',\n    'flashgames.JamesTheDeepSeaZebra-v0',\n    'flashgames.JamesThePirateZebra-v0',\n    'flashgames.JamesTheSpaceZebra-v0',\n    'flashgames.JelliesFun-v0',\n    'flashgames.JellyFriend-v0',\n    'flashgames.JellySnake-v0',\n    'flashgames.JetpackJackride-v0',\n    'flashgames.JollySwipe-v0',\n    'flashgames.JollySwipeLevelPack-v0',\n    'flashgames.JonnyBackflip-v0',\n    'flashgames.JumpOverTheRings-v0',\n    'flashgames.Jumprunner-v0',\n    'flashgames.Jumpz-v0',\n    'flashgames.JungleCrash-v0',\n    'flashgames.JungleEagle-v0',\n    'flashgames.KamikazeRace-v0',\n    'flashgames.KangoIslands-v0',\n    'flashgames.KartOn-v0',\n    'flashgames.KartRacing-v0',\n    'flashgames.KartingSuperGo-v0',\n    'flashgames.Kawairun-v0',\n    'flashgames.KeeperOfTheGrove3-v0',\n    'flashgames.Kinetikz-v0',\n    'flashgames.Kinetikz2-v0',\n    'flashgames.Kinetikz3-v0',\n    'flashgames.KingRolla-v0',\n    'flashgames.KitchenRestaurantCleanUp-v0',\n    'flashgames.KnightsOfRock-v0',\n    'flashgames.Knighttron-v0',\n    'flashgames.Knockers-v0',\n    'flashgames.Krome-v0',\n    'flashgames.LaserCannon3LevelsPack-v0',\n    'flashgames.LawnmowerRacing3d-v0',\n    'flashgames.LaxAirbusParking-v0',\n    'flashgames.Lazerman-v0',\n    'flashgames.LearnToFlyIdle-v0',\n    'flashgames.Legor9-v0',\n    'flashgames.LessQuick-v0',\n    'flashgames.LetsFall-v0',\n    'flashgames.LevelEditor3-v0',\n    'flashgames.LilyFighters-v0',\n    'flashgames.LineGameLimeEdition-v0',\n    'flashgames.LlamasInDistress-v0',\n    'flashgames.LonelyEscapeAsylum-v0',\n    'flashgames.LongJump-v0',\n    'flashgames.Long_short-v0',\n    'flashgames.LooneyAndJohny-v0',\n    'flashgames.LuckyBalls-v0',\n    'flashgames.LuxUltimate-v0',\n    'flashgames.Madburger3-v0',\n    'flashgames.MadpetSkateboarder2-v0',\n    'flashgames.MagicSafari-v0',\n    'flashgames.ManicRallyGo-v0',\n    'flashgames.MapTurtleJigsawPuzzle-v0',\n    'flashgames.MarblesShooter-v0',\n    'flashgames.MarsColonyTd-v0',\n    'flashgames.MarshmallowsEscape-v0',\n    'flashgames.MashaCollectsButterflies-v0',\n    'flashgames.MasterDifference-v0',\n    'flashgames.Match2Collapse-v0',\n    'flashgames.Match3Adventure-v0',\n    'flashgames.Match3ChristmasPack-v0',\n    'flashgames.Match3PresentBoxSaga-v0',\n    'flashgames.MatchAndCrash-v0',\n    'flashgames.MatchAndSpell-v0',\n    'flashgames.MatchAroundTheWorld-v0',\n    'flashgames.MatchCraft-v0',\n    'flashgames.MatchCrypt-v0',\n    'flashgames.MatchJong-v0',\n    'flashgames.MatchMonsters-v0',\n    'flashgames.MatchStars-v0',\n    'flashgames.MatchTheBugz-v0',\n    'flashgames.MatchTheFruits-v0',\n    'flashgames.MatchToEnjoy-v0',\n    'flashgames.MatchToEnjoyLevelPack-v0',\n    'flashgames.MatchingSweetHearts-v0',\n    'flashgames.MazeEye-v0',\n    'flashgames.MedievalShark-v0',\n    'flashgames.MeerkatMission-v0',\n    'flashgames.MexicoRex-v0',\n    'flashgames.MiceVsHammers-v0',\n    'flashgames.Michimind-v0',\n    'flashgames.MidnightCanine-v0',\n    'flashgames.MidnightMiner-v0',\n    'flashgames.MightyTower-v0',\n    'flashgames.Mimelet-v0',\n    'flashgames.MindImpulse-v0',\n    'flashgames.MineDrop-v0',\n    'flashgames.MineHero-v0',\n    'flashgames.MinedigJourneyToHollowEarth-v0',\n    'flashgames.MiniMachines-v0',\n    'flashgames.MiniSportsChallenge-v0',\n    'flashgames.MinicarHunt-v0',\n    'flashgames.Minicarting-v0',\n    'flashgames.MissionEscapeTheDojo-v0',\n    'flashgames.ModelCarRacing-v0',\n    'flashgames.MonkeyBlast-v0',\n    'flashgames.MonkeyGems-v0',\n    'flashgames.MonkeyGoHappyNinjaHunt2-v0',\n    'flashgames.MonkeyManic-v0',\n    'flashgames.MonsterChains-v0',\n    'flashgames.MonsterLabFeedThemAll-v0',\n    'flashgames.MonsterRun-v0',\n    'flashgames.MonsterTroubles-v0',\n    'flashgames.MonsterTruckFever-v0',\n    'flashgames.MonsterTruckRally-v0',\n    'flashgames.Moosters-v0',\n    'flashgames.MotherLoad-v0',\n    'flashgames.MotoMadness-v0',\n    'flashgames.MotoTrialMania-v0',\n    'flashgames.MotorWheels-v0',\n    'flashgames.Mrbirdie-v0',\n    'flashgames.MultiballMadness-v0',\n    'flashgames.Multitask-v0',\n    'flashgames.MummyMadness-v0',\n    'flashgames.Mushbooms-v0',\n    'flashgames.MushboomsLevelPack-v0',\n    'flashgames.MushboomsLevelPack2-v0',\n    'flashgames.MushroomFarmDefender-v0',\n    'flashgames.MushyMishy-v0',\n    'flashgames.MusicSmash-v0',\n    'flashgames.MusicStomp-v0',\n    'flashgames.MusicZap-v0',\n    'flashgames.MysteriousPirateJewels-v0',\n    'flashgames.MysticIndiaPop-v0',\n    'flashgames.MysticalAncientTreasure-v0',\n    'flashgames.NOfficialWebVersion-v0',\n    'flashgames.NadiasRage-v0',\n    'flashgames.NanoKingdoms2JokersRevenge-v0',\n    'flashgames.NeonRace-v0',\n    'flashgames.NeonRaceLvl2-v0',\n    'flashgames.NeonRaceLvl3-v0',\n    'flashgames.NeonRaceLvl4-v0',\n    'flashgames.NeonRaceLvl5-v0',\n    'flashgames.NeonRaceLvl6-v0',\n    'flashgames.NeonRaceLvl7-v0',\n    'flashgames.NeonRaceLvl8-v0',\n    'flashgames.NeonRace2-v0',\n    'flashgames.NeonRace2Lvl2-v0',\n    'flashgames.NeonRace2Lvl3-v0',\n    'flashgames.NeonRace2Lvl4-v0',\n    'flashgames.NeonRace2Lvl5-v0',\n    'flashgames.NeonRace2Lvl6-v0',\n    'flashgames.NeonRace2Lvl7-v0',\n    'flashgames.NeonRace2Lvl8-v0',\n    'flashgames.NeonRace2Lvl9-v0',\n    'flashgames.NeonRace2Lvl10-v0',\n    'flashgames.NeonRace2Lvl11-v0',\n    'flashgames.NeonRace2Lvl12-v0',\n    'flashgames.NeonRace2Lvl13-v0',\n    'flashgames.NeonRace2Lvl14-v0',\n    'flashgames.NeonRace2Lvl15-v0',\n    'flashgames.Neopods-v0',\n    'flashgames.NervousLadybug-v0',\n    'flashgames.NewSiberianSupercarsRacing-v0',\n    'flashgames.NewSplitterPals-v0',\n    'flashgames.NightDrivin-v0',\n    'flashgames.NightRaceRally-v0',\n    'flashgames.NinjaPainter-v0',\n    'flashgames.NinjaPandaArena-v0',\n    'flashgames.NinjaPandaCouple-v0',\n    'flashgames.NinjaTrainingWorlds-v0',\n    'flashgames.Nook-v0',\n    'flashgames.NoughtsAndCrosses-v0',\n    'flashgames.NoughtsAndCrossesExtreme-v0',\n    'flashgames.NukeDefense-v0',\n    'flashgames.Numz-v0',\n    'flashgames.NuttyBoom-v0',\n    'flashgames.ObamaAlienDefense-v0',\n    'flashgames.OceanMatch-v0',\n    'flashgames.Oddball2-v0',\n    'flashgames.OffRoaders3d-v0',\n    'flashgames.OfficeTrap-v0',\n    'flashgames.Offroaders-v0',\n    'flashgames.Offroaders2-v0',\n    'flashgames.OkParking-v0',\n    'flashgames.OldTv-v0',\n    'flashgames.OozingForever-v0',\n    'flashgames.OswaldTheAngryDwarf-v0',\n    'flashgames.Overheat-v0',\n    'flashgames.PaintWars-v0',\n    'flashgames.Paintwars-v0',\n    'flashgames.PanikInChocoland-v0',\n    'flashgames.PapaLouie3WhenSundaesAttack-v0',\n    'flashgames.PaperDefense-v0',\n    'flashgames.ParachuteRetrospect-v0',\n    'flashgames.ParallelLevels-v0',\n    'flashgames.ParkingFury-v0',\n    'flashgames.Parkour-v0',\n    'flashgames.ParticleWarsExtreme-v0',\n    'flashgames.Pathillogical-v0',\n    'flashgames.PaulVaulting-v0',\n    'flashgames.Peakart-v0',\n    'flashgames.PearlBreaking-v0',\n    'flashgames.Pel-v0',\n    'flashgames.PenguinCubes-v0',\n    'flashgames.PenguinHeroes-v0',\n    'flashgames.PenguinSkate2-v0',\n    'flashgames.PerilousJourney2-v0',\n    'flashgames.Phit-v0',\n    'flashgames.PickAndDig2-v0',\n    'flashgames.PickUpTruckRacing-v0',\n    'flashgames.PicnicPanicTd-v0',\n    'flashgames.PigDestroyer-v0',\n    'flashgames.PiggyWiggy-v0',\n    'flashgames.PiggysCupcakeQuest-v0',\n    'flashgames.PinBalls-v0',\n    'flashgames.PinataWarriors-v0',\n    'flashgames.PingPongSurvival-v0',\n    'flashgames.PirateRunAway-v0',\n    'flashgames.PiratesAndCannons-v0',\n    'flashgames.PixelBasher-v0',\n    'flashgames.PixelFighta-v0',\n    'flashgames.PixelPurge-v0',\n    'flashgames.PixelQuest-v0',\n    'flashgames.PlaneRace-v0',\n    'flashgames.PlaneRace2-v0',\n    'flashgames.PlopPlopLite-v0',\n    'flashgames.PocketRocket-v0',\n    'flashgames.Pointer-v0',\n    'flashgames.Pointless-v0',\n    'flashgames.PoliceChaseCrackdown-v0',\n    'flashgames.PoliceHotRacing-v0',\n    'flashgames.PoliceInterceptor-v0',\n    'flashgames.PolygonalFury-v0',\n    'flashgames.Popopop-v0',\n    'flashgames.Popopop2-v0',\n    'flashgames.PouJetpack-v0',\n    'flashgames.PouThanksgivingDaySlacking-v0',\n    'flashgames.PowerCopter-v0',\n    'flashgames.PowerSwing-v0',\n    'flashgames.Primary-v0',\n    'flashgames.PrincessBubblesRescuePrince-v0',\n    'flashgames.PrincessToTheRescue-v0',\n    'flashgames.ProjectMonochrome-v0',\n    'flashgames.PuddingPie-v0',\n    'flashgames.PufferFish-v0',\n    'flashgames.PumpkinCollector-v0',\n    'flashgames.PumpkinMan-v0',\n    'flashgames.PumpkinsInZombieTown-v0',\n    'flashgames.PunchBallJump-v0',\n    'flashgames.PurifyTheLegendOfZ-v0',\n    'flashgames.PuzzleMonsters-v0',\n    'flashgames.PuzzleRescuePrime-v0',\n    'flashgames.PyramidApocalypse-v0',\n    'flashgames.Pyro-v0',\n    'flashgames.Qoosh-v0',\n    'flashgames.QuashBoard-v0',\n    'flashgames.QubedMysteriousIsland-v0',\n    'flashgames.QubeyTheCube-v0',\n    'flashgames.Quick-v0',\n    'flashgames.RabbitPlanetEscape-v0',\n    'flashgames.RabbitRustler-v0',\n    'flashgames.RacerKartz-v0',\n    'flashgames.RacingSupercarChampionship-v0',\n    'flashgames.RainbowDrops-v0',\n    'flashgames.RapaNui-v0',\n    'flashgames.Raze3-v0',\n    'flashgames.Rb2-v0',\n    'flashgames.Rbots-v0',\n    'flashgames.ReachTheGoal-v0',\n    'flashgames.RedBeard-v0',\n    'flashgames.RedCode3-v0',\n    'flashgames.RedFuryRacing-v0',\n    'flashgames.ReleaseTheMooks-v0',\n    'flashgames.ReleaseTheMooks2-v0',\n    'flashgames.ReleaseTheMooks3-v0',\n    'flashgames.Resonance-v0',\n    'flashgames.RetroRunner-v0',\n    'flashgames.Retron-v0',\n    'flashgames.ReverseBoots-v0',\n    'flashgames.RhythmBlasterV2-v0',\n    'flashgames.RhythmRockets-v0',\n    'flashgames.RhythmSnake-v0',\n    'flashgames.RingsideHero-v0',\n    'flashgames.RiseOfChampions-v0',\n    'flashgames.RoadRacing-v0',\n    'flashgames.RoadblockAttack-v0',\n    'flashgames.RoboPop-v0',\n    'flashgames.RobotDuelFight-v0',\n    'flashgames.RobotWantsFishy-v0',\n    'flashgames.RocketBootsInc-v0',\n    'flashgames.Rocketeer-v0',\n    'flashgames.RollTheCluster-v0',\n    'flashgames.RollerRider-v0',\n    'flashgames.RollingHills-v0',\n    'flashgames.Rose-v0',\n    'flashgames.RubbleRacer-v0',\n    'flashgames.RunFaustoRun-v0',\n    'flashgames.RunNGun-v0',\n    'flashgames.RunRamRun-v0',\n    'flashgames.RunRunRan-v0',\n    'flashgames.RunSoldierRun-v0',\n    'flashgames.RushOfTanks-v0',\n    'flashgames.RussianTruck-v0',\n    'flashgames.SafariTime-v0',\n    'flashgames.SandcastleShowdown-v0',\n    'flashgames.SantaClimbHere-v0',\n    'flashgames.SantaMan-v0',\n    'flashgames.SantaSituation-v0',\n    'flashgames.SapphireClix-v0',\n    'flashgames.SaveTheDummyHolidays-v0',\n    'flashgames.SavingLittleAlien-v0',\n    'flashgames.SchoolBusRacing-v0',\n    'flashgames.Scribble-v0',\n    'flashgames.Scribble2-v0',\n    'flashgames.SeaPong-v0',\n    'flashgames.ShamelessClone2-v0',\n    'flashgames.Sheepster-v0',\n    'flashgames.Sheepy-v0',\n    'flashgames.ShimmyChute-v0',\n    'flashgames.ShootTheCircle-v0',\n    'flashgames.ShortCircuit-v0',\n    'flashgames.SiegeHeroPiratePillage-v0',\n    'flashgames.Sieger2LevelPack-v0',\n    'flashgames.SiegerRebuiltToDestroy-v0',\n    'flashgames.Sirtet-v0',\n    'flashgames.SistersOfNoMercy-v0',\n    'flashgames.SkiSim-v0',\n    'flashgames.SkyIsland-v0',\n    'flashgames.SkyKnight2-v0',\n    'flashgames.SkyQuest-v0',\n    'flashgames.Skytrip-v0',\n    'flashgames.SliceTheBox-v0',\n    'flashgames.SliceTheBoxRemaster-v0',\n    'flashgames.SlingBaby-v0',\n    'flashgames.SlipSlideSloth-v0',\n    'flashgames.SmashTheSwine-v0',\n    'flashgames.SmileyJumpFest-v0',\n    'flashgames.SmileyPuzzle-v0',\n    'flashgames.SmileyPuzzle2-v0',\n    'flashgames.SmileyPuzzleGirlEdition-v0',\n    'flashgames.SmileyShowdown-v0',\n    'flashgames.SnackOnLittleCreatures-v0',\n    'flashgames.SnailBob4-v0',\n    'flashgames.Snake-v0',\n    'flashgames.SnakeClassic-v0',\n    'flashgames.SnakeFightArena-v0',\n    'flashgames.SneakyScubaEscape-v0',\n    'flashgames.SnowPrincessMakeup-v0',\n    'flashgames.SnowQueen-v0',\n    'flashgames.SnowQueen3-v0',\n    'flashgames.SnowQueen4-v0',\n    'flashgames.Solarsaurs-v0',\n    'flashgames.SonicBubbles-v0',\n    'flashgames.SpaceBounty-v0',\n    'flashgames.SpaceColony-v0',\n    'flashgames.SpaceMadness-v0',\n    'flashgames.SpacePunkRacer-v0',\n    'flashgames.SpacePunkRacerLvl2-v0',\n    'flashgames.SpacePunkRacerLvl3-v0',\n    'flashgames.SpacePunkRacerLvl4-v0',\n    'flashgames.SpacePunkRacerLvl5-v0',\n    'flashgames.SpacePunkRacerLvl6-v0',\n    'flashgames.SpacePunkRacerLvl7-v0',\n    'flashgames.SpacePunkRacerLvl8-v0',\n    'flashgames.SpacemanMax-v0',\n    'flashgames.SpanishLiga2016-v0',\n    'flashgames.Sparks-v0',\n    'flashgames.Spectrum-v0',\n    'flashgames.SpectrumHeist-v0',\n    'flashgames.SpectrumRunner-v0',\n    'flashgames.SpeedBusters-v0',\n    'flashgames.SpellIdle2-v0',\n    'flashgames.SpinClimbGreen-v0',\n    'flashgames.SpinSoar-v0',\n    'flashgames.SpinSprint-v0',\n    'flashgames.SpunkyVsAliens-v0',\n    'flashgames.Stalingrad-v0',\n    'flashgames.Stalingrad2-v0',\n    'flashgames.Stalingrad3-v0',\n    'flashgames.Stand-v0',\n    'flashgames.StarCars-v0',\n    'flashgames.Stardrops-v0',\n    'flashgames.Stargrazer-v0',\n    'flashgames.Stars-v0',\n    'flashgames.Stealthbound-v0',\n    'flashgames.StealthboundLevelPack-v0',\n    'flashgames.StickBlender-v0',\n    'flashgames.StickyNinjaMissions-v0',\n    'flashgames.Stickylinky-v0',\n    'flashgames.StitchlandConflict-v0',\n    'flashgames.StormRage-v0',\n    'flashgames.Stratega-v0',\n    'flashgames.StreetRace-v0',\n    'flashgames.StreetRace2Nitro-v0',\n    'flashgames.StreetRace3-v0',\n    'flashgames.Streetrace2Nitro-v0',\n    'flashgames.StrikeForceKitty-v0',\n    'flashgames.SubmarineFighter-v0',\n    'flashgames.Sundrops-v0',\n    'flashgames.SuperAdventurePalsBattleArena-v0',\n    'flashgames.SuperBattleCity2-v0',\n    'flashgames.SuperBomb-v0',\n    'flashgames.SuperBoxotron2000-v0',\n    'flashgames.SuperCandyGems-v0',\n    'flashgames.SuperCarRacing-v0',\n    'flashgames.SuperDash-v0',\n    'flashgames.SuperIdleMaster-v0',\n    'flashgames.SuperK9-v0',\n    'flashgames.SuperPuzzlePlatformer-v0',\n    'flashgames.SuperRally3d-v0',\n    'flashgames.SuperRallyChallenge-v0',\n    'flashgames.SuperRallyChallenge2-v0',\n    'flashgames.SuperRallyExtreme-v0',\n    'flashgames.SuperShinyheadHarderThanFlappyBird-v0',\n    'flashgames.SuperXtreme5MinuteShootEmUp-v0',\n    'flashgames.SuperbikeExtreme-v0',\n    'flashgames.SuperbikeRacer-v0',\n    'flashgames.SupercarDomination-v0',\n    'flashgames.SupergirlGo-v0',\n    'flashgames.SurfBuggy-v0',\n    'flashgames.SurvivalLab-v0',\n    'flashgames.SurvivorMissionD-v0',\n    'flashgames.SushiCatTheHoneymoon-v0',\n    'flashgames.SwagMan-v0',\n    'flashgames.SwampTreck-v0',\n    'flashgames.SwapTheDots-v0',\n    'flashgames.SweetTooth-v0',\n    'flashgames.SwimmingRace-v0',\n    'flashgames.SwingTriangle-v0',\n    'flashgames.TableTennisChallenge-v0',\n    'flashgames.TamusMitta-v0',\n    'flashgames.TankStorm-v0',\n    'flashgames.TankStorm2-v0',\n    'flashgames.TankStorm3-v0',\n    'flashgames.TankStorm4-v0',\n    'flashgames.TapRocket-v0',\n    'flashgames.TastyFruits-v0',\n    'flashgames.TattooArtist-v0',\n    'flashgames.TaxiInc-v0',\n    'flashgames.TaxiRacers-v0',\n    'flashgames.TechnoMania-v0',\n    'flashgames.TempleRunKnight-v0',\n    'flashgames.TerrestrialConflict-v0',\n    'flashgames.ThatRedButton-v0',\n    'flashgames.Thaw-v0',\n    'flashgames.TheBigEscape-v0',\n    'flashgames.TheBoomlandsWorldWars-v0',\n    'flashgames.TheBravestHunter-v0',\n    'flashgames.TheCaseOfScaryShadow-v0',\n    'flashgames.TheCubicMonkeyAdventures2-v0',\n    'flashgames.TheGreatSiege-v0',\n    'flashgames.TheOneForkRestaurantDx-v0',\n    'flashgames.ThePretenderPartThree-v0',\n    'flashgames.TheProfessionals3-v0',\n    'flashgames.TheSilentPlanet-v0',\n    'flashgames.TheThreeTowers-v0',\n    'flashgames.TheTowerman-v0',\n    'flashgames.Thundercars-v0',\n    'flashgames.TinyCastle-v0',\n    'flashgames.TinyRacers-v0',\n    'flashgames.Titanic-v0',\n    'flashgames.TokyoGuineaPop-v0',\n    'flashgames.ToonEscapeMaze-v0',\n    'flashgames.ToonEscapeSpookHouse-v0',\n    'flashgames.Tosuta-v0',\n    'flashgames.TouchTheBubbles4-v0',\n    'flashgames.TouchTheSky-v0',\n    'flashgames.TowerCollapseDeluxe-v0',\n    'flashgames.TowerEmpire-v0',\n    'flashgames.TowerEmpire2-v0',\n    'flashgames.TowerMoon-v0',\n    'flashgames.TowerOfPisa-v0',\n    'flashgames.ToyRacers-v0',\n    'flashgames.ToyWarAngryRobotDog-v0',\n    'flashgames.TractorTrial-v0',\n    'flashgames.TractorTrial2-v0',\n    'flashgames.TrafficCollision-v0',\n    'flashgames.TrickOrToad-v0',\n    'flashgames.TrickyRick-v0',\n    'flashgames.Trizzle-v0',\n    'flashgames.TrollingLionJump-v0',\n    'flashgames.TtRacer-v0',\n    'flashgames.TumbleTiles-v0',\n    'flashgames.Tumblestump2-v0',\n    'flashgames.TurboCrew-v0',\n    'flashgames.TurboRally-v0',\n    'flashgames.TurtleBreak-v0',\n    'flashgames.TutiFruti-v0',\n    'flashgames.TwinkleStarRush-v0',\n    'flashgames.Typeasaurus-v0',\n    'flashgames.UdderChaos-v0',\n    'flashgames.UltimateEscape-v0',\n    'flashgames.UltimateLegend-v0',\n    'flashgames.Underrun-v0',\n    'flashgames.UnderwaterSecrets-v0',\n    'flashgames.UnfreezeMe3-v0',\n    'flashgames.UrbanFatburner-v0',\n    'flashgames.UrbanMicroRacers-v0',\n    'flashgames.V8MuscleCars-v0',\n    'flashgames.V8MuscleCars2-v0',\n    'flashgames.V8MuscleCars3-v0',\n    'flashgames.V8RacingChampion-v0',\n    'flashgames.VanguardWars-v0',\n    'flashgames.VectorRunner-v0',\n    'flashgames.Velocity-v0',\n    'flashgames.VengeanceRider-v0',\n    'flashgames.VideoGameMonster-v0',\n    'flashgames.ViewtifulFightClub2-v0',\n    'flashgames.Viridia-v0',\n    'flashgames.VirtualRacer-v0',\n    'flashgames.VolcanoPanicInIsland-v0',\n    'flashgames.VolleyBomb-v0',\n    'flashgames.WackyStrike-v0',\n    'flashgames.WarBerlinIdle-v0',\n    'flashgames.WarHeroes-v0',\n    'flashgames.WarOfTheShard-v0',\n    'flashgames.WastelandSiege-v0',\n    'flashgames.WaveLucha-v0',\n    'flashgames.Weirdville-v0',\n    'flashgames.WhatsInsideTheBox-v0',\n    'flashgames.Wheelers-v0',\n    'flashgames.WhistleAndMice-v0',\n    'flashgames.WildWestConflict-v0',\n    'flashgames.WilliamTell-v0',\n    'flashgames.WindowShooter-v0',\n    'flashgames.WinterSlider-v0',\n    'flashgames.WishTotems-v0',\n    'flashgames.WishTotemsLevelPack-v0',\n    'flashgames.WizkidEscape-v0',\n    'flashgames.WolfSpiderJigsawPuzzle-v0',\n    'flashgames.WonderRocket-v0',\n    'flashgames.WoollyBearJigsawPuzzle-v0',\n    'flashgames.WorldsGuard2-v0',\n    'flashgames.WormHappy-v0',\n    'flashgames.WreckRoad-v0',\n    'flashgames.XChains-v0',\n    'flashgames.XmasChains-v0',\n    'flashgames.Xmatch2016-v0',\n    'flashgames.Xnake-v0',\n    'flashgames.YepisJourney-v0',\n    'flashgames.YummyyummyMonsterShooter-v0',\n    'flashgames.Zed-v0',\n    'flashgames.Zevil2-v0',\n    'flashgames.ZodiacMatch-v0',\n    'flashgames.Zombality-v0',\n    'flashgames.ZombieDemolisher3-v0',\n    'flashgames.ZombieMatch3-v0',\n    'flashgames.ZombieTdReborn-v0',\n    'flashgames.ZombieTowerDefenseReborn-v0',\n    'flashgames.ZombiesAndDonuts-v0',\n    'flashgames.ZombiesMustDie-v0',\n    'flashgames.ZombiesVsBrains-v0',\n    'flashgames.Zombonarium-v0',\n    'flashgames.ZooRacer-v0',\n    ]:\n    register(\n        id=game,\n        entry_point='universe.wrappers:WrappedFlashgamesEnv',\n        max_episode_steps=20000,\n        tags={\n            'vnc': True,\n            'flashgames': True,\n            'runtime': 'flashgames',\n            'metadata_encoding': metadata_v1,\n            'action_probe': {\n                'type': 'key',\n                'value': 0x60,\n            }\n        },\n    )\n\nregister(\n    id='VNCNoopFlashgamesEnv-v0',  # Special noop flashgame env\n    entry_point='universe.vnc:WrappedFlashgamesEnv',\n    max_episode_steps=10**7,\n    tags={\n        'vnc': True,\n        'flashgames': True,\n        'runtime': 'flashgames',\n    },\n)\n\n#------------------------ World of Bits and MiniWoB ------------------------#\n#     \"World of Bits\" comprises a series of browser tasks,\n#     including a series of simple \"MiniWoB\" tasks such\n#     as using buttons and sliders, as well as more complex\n#     tasks such as booking flights on actual websites.\n\nvnc_world_of_bits = [\n    'wob.MiniWorldOfBits-v0',\n    'wob.mini.BisectAngle-v0',\n    'wob.mini.BookFlight-v0',\n    'wob.mini.ChaseCircle-v0',\n    'wob.mini.ChooseDate-v0',\n    'wob.mini.ChooseList-v0',\n    'wob.mini.CircleCenter-v0',\n    'wob.mini.ClickButton-v0',\n    'wob.mini.ClickButtonSequence-v0',\n    'wob.mini.ClickCheckboxes-v0',\n    'wob.mini.ClickCollapsible-v0',\n    'wob.mini.ClickCollapsible2-v0',\n    'wob.mini.ClickColor-v0',\n    'wob.mini.ClickDialog-v0',\n    'wob.mini.ClickDialog2-v0',\n    'wob.mini.ClickLink-v0',\n    'wob.mini.ClickMenu-v0',\n    'wob.mini.ClickMenu2-v0',\n    'wob.mini.ClickOption-v0',\n    'wob.mini.ClickPie-v0',\n    'wob.mini.ClickScrollList-v0',\n    'wob.mini.ClickShades-v0',\n    'wob.mini.ClickShape-v0',\n    'wob.mini.ClickTab-v0',\n    'wob.mini.ClickTab2-v0',\n    'wob.mini.ClickTest-v0',\n    'wob.mini.ClickTest2-v0',\n    'wob.mini.ClickWidget-v0',\n    'wob.mini.CopyPaste-v0',\n    'wob.mini.CopyPaste2-v0',\n    'wob.mini.CountShape-v0',\n    'wob.mini.CountSides-v0',\n    'wob.mini.DragBox-v0',\n    'wob.mini.DragCube-v0',\n    'wob.mini.DragItem-v0',\n    'wob.mini.DragItems-v0',\n    'wob.mini.DragItemsGrid-v0',\n    'wob.mini.DragShapes-v0',\n    'wob.mini.DragSortNumbers-v0',\n    'wob.mini.EmailInbox-v0',\n    'wob.mini.EnterDate-v0',\n    'wob.mini.EnterPassword-v0',\n    'wob.mini.EnterText-v0',\n    'wob.mini.EnterText2-v0',\n    'wob.mini.EnterTextDynamic-v0',\n    'wob.mini.EnterTime-v0',\n    'wob.mini.FindMidpoint-v0',\n    'wob.mini.FindWord-v0',\n    'wob.mini.FocusText-v0',\n    'wob.mini.FocusText2-v0',\n    'wob.mini.GridCoordinate-v0',\n    'wob.mini.GuessNumber-v0',\n    'wob.mini.HighlightText-v0',\n    'wob.mini.HighlightText2-v0',\n    'wob.mini.IdentifyShape-v0',\n    'wob.mini.LoginUser-v0',\n    'wob.mini.MovingItems-v0',\n    'wob.mini.NavigateTree-v0',\n    'wob.mini.NumberCheckboxes-v0',\n    'wob.mini.ReadTable-v0',\n    'wob.mini.ReadTable2-v0',\n    'wob.mini.ResizeTextarea-v0',\n    'wob.mini.RightAngle-v0',\n    'wob.mini.ScrollText-v0',\n    'wob.mini.ScrollText2-v0',\n    'wob.mini.SearchEngine-v0',\n    'wob.mini.SimonSays-v0',\n    'wob.mini.SimpleAlgebra-v0',\n    'wob.mini.SimpleArithmetic-v0',\n    'wob.mini.SocialMedia-v0',\n    'wob.mini.Terminal-v0',\n    'wob.mini.TextEditor-v0',\n    'wob.mini.TextTransform-v0',\n    'wob.mini.TicTacToe-v0',\n    'wob.mini.UseAutocomplete-v0',\n    'wob.mini.UseColorwheel-v0',\n    'wob.mini.UseColorwheel2-v0',\n    'wob.mini.UseSlider-v0',\n    'wob.mini.UseSlider2-v0',\n    'wob.mini.UseSpinner-v0',\n    'wob.mini.VisualAddition-v0',\n]\n\n# signup forms.\nfor _id in range(20):\n    vnc_world_of_bits.append('wob.real.Signup-{}-v0'.format(_id))\n\nfor _site in ['Jetblue', 'Kayak', 'AA', 'VirginAmerica',\n               'United',  'Delta',  'Alaska']:\n    vnc_world_of_bits.append('wob.real.BookFlight-{}-v0'.format(_site))\n\nfor _site in ['Airfrance', 'Craigslist', 'Chase']:\n    vnc_world_of_bits.append('wob.real.ClickButton-{}-v0'.format(_site))\n\nfor _task in ['Learn', 'Test']:\n    for _name in ['Geography', 'Planet', 'Universe', 'Comet', 'Moon', 'Mars', 'Solar-System']:\n        vnc_world_of_bits.append('wob.real.Quizlet-{}-{}-v0'.format(_name, _task))\n\nvnc_world_of_bits.append('wob.real.Duolingo-French-Basic-1-v0')\n\nfor game in vnc_world_of_bits:\n    register(\n        id=game,\n        entry_point='universe.wrappers:WrappedVNCEnv',\n        max_episode_steps=10**7,\n        tags={\n            'vnc': True,\n            'wob': True,\n            'runtime': 'world-of-bits',\n        },\n    )\n\n#-------------------------- Complex Games ------------------------#\n#     Any game, program, app, or website can be a\n#     Universe environment. Here we include\n#     a handful of sample \"complex\" games\n#     such as World of Bits, GTA V, and StarCraft.\n#     Adding more games is straightforward, and\n#     we welcome contributions of environments\n#     from the community!\n\nfor id in ['starcraft.TerranAstralBalance-v0']:\n    register(\n        id=id,\n        entry_point='universe.wrappers:WrappedStarCraftEnv',\n        max_episode_steps=10**7,\n        tags={\n            'vnc': True,\n            'starcraft': True,\n            'runtime': 'starcraft',\n        },\n    )\n\nfor gtav_game in ['gtav.SaneDriving-v0', 'gtav.Speed-v0']:\n    register(\n        id=gtav_game,\n        entry_point='universe.wrappers:WrappedGTAVEnv',\n        max_episode_steps=10**7,\n        tags={\n            'vnc': True,\n            'gtav': True,\n            'runtime': 'vnc-windows',\n        },\n    )\n\nregister(\n    id='world.WorldOfGoo-v0',\n    entry_point='universe.wrappers:WrappedWorldOfGooEnv',\n    max_episode_steps=10**7,\n    tags={\n        'vnc': True,\n        'wog': True,\n        'runtime': 'vnc-world-of-goo',\n    },\n)\n\nfor slith_game in ['SlitherIO-v0', 'SlitherIONoSkins-v0', 'SlitherIOEasy-v0']:\n    register(\n        id='internet.' + slith_game,\n        entry_point='universe.wrappers:WrappedInternetEnv',\n        max_episode_steps=10**7,\n        tags={\n            'vnc': True,\n            'internet': True,\n            'slither': True,\n            'runtime': 'flashgames',\n            'metadata_encoding': metadata_v1,\n            'action_probe': {\n                'type': 'key',\n                'value': 0x60,\n            }\n        },\n    )\n\nregister(\n    id='test.DummyVNCEnv-v0',\n    entry_point='universe.envs:DummyVNCEnv',\n    max_episode_steps= 10**7,\n    tags={\n        'vnc': True,\n        'metadata_encoding': metadata_v1,\n        'action_probe': {\n            'type': 'key',\n            'value': 0x60,\n            }\n        },\n    )\n"
  },
  {
    "path": "universe/configuration.py",
    "content": "import logging\nfrom gym import configuration\n\nuniverse_logger = logging.getLogger('universe')\nuniverse_logger.setLevel(logging.INFO)\n\nextra_logger = logging.getLogger('universe.extra')\nextra_logger.setLevel(logging.INFO)\n\nif hasattr(configuration, '_extra_loggers'):\n    configuration._extra_loggers.append(universe_logger)\n    configuration._extra_loggers.append(extra_logger)\n"
  },
  {
    "path": "universe/envs/__init__.py",
    "content": "import universe.envs.vnc_env\nfrom universe.envs.vnc_env import VNCEnv\nfrom universe.envs.vnc_core_env import GymCoreEnv, GymCoreSyncEnv\nfrom universe.envs.vnc_flashgames import FlashgamesEnv\nfrom universe.envs.vnc_internet import InternetEnv\nfrom universe.envs.vnc_starcraft import StarCraftEnv\nfrom universe.envs.vnc_gtav import GTAVEnv\nfrom universe.envs.vnc_wog import WorldOfGooEnv\nfrom universe.envs.dummy_vnc_env import DummyVNCEnv\n"
  },
  {
    "path": "universe/envs/diagnostics.py",
    "content": "import collections\nimport fastzbarlight\nimport itertools\nimport logging\nfrom multiprocessing import pool\nimport numpy as np\nimport time\nimport threading\n# import psutil\nimport sys\nfrom collections import namedtuple\nfrom gym.utils import reraise\n\nimport re\nfrom universe import error, pyprofile, spaces\n\n# TODO: prefix the loggers\n\nlogger = logging.getLogger(__name__)\nextra_logger = logging.getLogger('universe.extra.'+__name__)\n\ndef show(ob):\n    from PIL import Image\n    Image.fromarray(ob).show()\n\ndef standard_error(ary, axis, scale=1):\n    ary = np.array(ary) * scale\n    if len(ary) > 1:\n        return np.std(ary, axis=axis) / np.sqrt(len(ary) - 1)\n    else:\n        return np.std(ary, axis=axis)\n\ndef extract_timestamp(observation):\n    total = 0\n    for byte in observation[0]:\n        total = 256 * total + byte\n    for byte in observation[1]:\n        total = 256 * total + byte\n\n    timestamp = total/1000.\n    return timestamp\n\nclass MetadataDecoder(object):\n    @classmethod\n    def build(cls, metadata_encoding, pool, qr_pool, label):\n        metadata_encoding = metadata_encoding.copy()\n        type = metadata_encoding.pop('type')\n        if type == 'qrcode':\n            return QRCodeMetadataDecoder(label=label, pool=pool, qr_pool=qr_pool, **metadata_encoding)\n        elif type == 'pixels':\n            return PixelsMetadataDecoder(label=label)\n        else:\n            raise error.Error('Invalid encoding: {}'.format(type))\n\nclass AsyncDecode(object):\n    pool = None\n\n    def __init__(self, pool, qr_pool, method, x, y, width, height):\n        self.x = x\n        self.y = y\n        self.width = width\n        self.height = height\n\n        self._last_img = None\n\n        self.method = method\n        self.results = []\n        self.deque = collections.deque()\n        self.pool = pool\n        self.qr_pool = qr_pool\n\n    def __call__(self, img, available_at):\n        # Choose the return value\n        if len(self.deque) > 0 and self.deque[0].ready():\n            last = self.deque.popleft()\n            res = last.get()\n            if res is not None:\n                pyprofile.timing('vnc_env.diagnostics.async_decode.latency', time.time() - res['available_at'])\n        else:\n            res = False\n\n        pyprofile.gauge('vnc_env.diagnostics.async_decode.queue_depth', len(self.deque))\n\n        # Just grayscale it by keeping only one component. Should be\n        # good enough as this region is black and white anyway.\n        grayscale = img[self.y:self.y+self.height, self.x:self.x+self.width, 0]\n\n        # Apply processing if needed\n        match = np.array_equal(self._last_img, grayscale)\n        if not match:\n            pyprofile.incr('vnc_env.diagnostics.async_decode.schedule')\n            # sneakily copy if numpy hasn't, so it can be cached\n            self._last_img = np.ascontiguousarray(grayscale)\n            async = self.qr_pool.apply_async(self.method, (self._last_img, time.time(), available_at))\n            self.deque.append(async)\n        else:\n            pyprofile.incr('vnc_env.diagnostics.async_decode.cache_hit')\n\n        return res\n\nclass QRCodeMetadataDecoder(MetadataDecoder):\n    def __init__(self, pool, qr_pool, x, y, width, height, label):\n        self.flag_synchronous = False\n\n        self.x = x\n        self.y = y\n        self.width = width\n        self.height = height\n        self.label = label\n\n        self.decode = AsyncDecode(pool, qr_pool, self._decode, x, y, width, height)\n\n    def _decode(self, observation, start, available_at):\n        # This method gets wrapped by AsyncDecode.__call__\n        with pyprofile.push('vnc_env.diagnostics.QRCodeMetadataDecoder.qr_code_scanner'):\n\n            encoded = fastzbarlight.qr_code_scanner(observation.tobytes(), self.width, self.height)\n        if encoded is None:\n            # Failed to parse!\n            return\n        if encoded.startswith(b'v1:'):\n            encoded = encoded.decode('utf-8')\n            if len(encoded) != len('v1:') + 12 + 12:\n                raise error.Error('Bad length for metadata from enviroment: {}'.format(encoded))\n\n            encoded = encoded[len('v1:'):]\n            last_update = int(encoded[:12], 16) / 1000.0\n            last_action = int(encoded[12:24], 16) / 1000.\n\n            return {\n                # Timestamp on the image\n                'now': last_update,\n                # When the last probe was received\n                'probe_received_at': last_action,\n                'processing_start': start,\n                'processing_end': time.time(),\n                'available_at': available_at,\n            }\n        else:\n            raise error.Error('Bad version string for metadata from environment: {}'.format(encoded))\n\n\nclass PixelsMetadataDecoder(MetadataDecoder):\n    def __init__(self, label):\n        self.flag_synchronous = True\n\n        self.anchor = np.array([\n            [(0x12, 0x34, 0x56), (0x78, 0x90, 0xab)],\n            [(0x23, 0x45, 0x67), (0x89, 0x0a, 0xbc)],\n        ], dtype=np.uint8)\n\n        self.location = None\n        self.last_search_metadata = 0\n        self.label = label\n\n    def _check_location(self, observation, location):\n        y, x = location\n        return np.all(observation[y:y+2, x:x+2] == self.anchor)\n\n    def _find_metadata_location(self, observation):\n        ys, xs = np.where(np.all(observation == self.anchor[0, 0], axis=-1))\n        if len(ys) == 0:\n            extra_logger.info('[%s] Could not find metadata anchor pixel', self.label)\n            return False\n\n        # TODO: handle multiple hits\n        assert len(ys) == 1\n        location = (ys[0], xs[0])\n\n        assert self._check_location(observation, location)\n        extra_logger.info('[%s] Found metadata anchor pixel: %s', self.label, location)\n        return location\n\n    def _should_search_metadata(self):\n       return time.time() - self.last_search_metadata > 1\n\n    def decode(self, observation, available_at=None):\n        start = time.time()\n\n        # metadata pixel location hasn't been initialized or it has moved\n        if not self.location or not self._check_location(observation,\n                                                         self.location):\n            # only search for metadata occasionally\n            if self._should_search_metadata():\n                self.location = self._find_metadata_location(observation)\n                self.last_search_metadata = time.time()\n\n        if not self.location:\n            return False  # False translates to None in DiagnosticsInstance\n\n        y, x = self.location\n        now = extract_timestamp(observation[y, x+2:x+4])\n        probe_received_at = extract_timestamp(observation[y, x+4:x+6])\n\n        return {\n            'now': now,\n            'probe_received_at': probe_received_at,\n            'processing_start': start,\n            'processing_end': time.time(),\n            'available_at': available_at,\n        }\n\nclass Diagnostics(object):\n    def __init__(self, n, probe_key, ignore_clock_skew=False, metadata_encoding=None, disable_action_probes=False):\n        # Each QR code takes about 1ms (and updates at 5fps). We do\n        # our best to ensure the QR is processed in time for the next\n        # step call (n/16 would put us right at the threshold).\n        self.pool = pool.ThreadPool(max(int(n/4), 1))\n        self.qr_pool = pool.ThreadPool(max(int(n/8), 1))\n        self.lock = threading.RLock()\n\n        self.instance_n = [None] * n\n        self.ignore_clock_skew = ignore_clock_skew\n        self.disable_action_probes = disable_action_probes\n\n        self.metadata_encoding = metadata_encoding\n\n        self.update(probe_key=probe_key, metadata_encoding=metadata_encoding)\n\n    # only used in flashgames right now\n    def update(self, probe_key, metadata_encoding):\n        self.probe_key = probe_key\n        self.metadata_encoding = metadata_encoding\n\n        for instance in self.instance_n:\n            if instance is not None:\n                instance.update(probe_key=self.probe_key, metadata_encoding=self.metadata_encoding)\n\n    def connect(self, i, network=None, label=None):\n        # This should technically be synchronized\n        self.instance_n[i] = DiagnosticsInstance(i, network, self.probe_key, self.ignore_clock_skew, self.metadata_encoding, disable_action_probes=self.disable_action_probes, qr_pool=self.qr_pool, pool=self.pool, label=label)\n\n    def close(self, i=None):\n        if i is not None:\n            self.instance_n[i] = None\n        else:\n            self.pool.close()\n            self.qr_pool.close()\n            for i in range(len(self.instance_n)):\n                self.close(i)\n            self.instance_n = None\n\n    def add_probe(self, action_n, mask_n):\n        if self.disable_action_probes or self.instance_n is None:\n            return\n\n        for instance, action, mask in zip(self.instance_n, action_n, mask_n):\n            # Important that masking prevents us from adding probes. (This\n            # avoids us e.g. filling in backticks into text boxes as the\n            # environment boots.)\n            if mask and instance:\n                instance.add_probe(action)\n\n    def add_metadata(self, observation_n, info_n, available_at=None):\n        \"\"\"Mutates the info_n dictionary.\"\"\"\n        if self.instance_n is None:\n            return\n\n        with pyprofile.push('vnc_env.diagnostics.Diagnostics.add_metadata'):\n            async = self.pool.imap_unordered(\n                self._add_metadata_i,\n                zip(self.instance_n, observation_n, info_n, [available_at] * len(observation_n)))\n            list(async)\n\n    def _add_metadata_i(self, args):\n        instance, observation, info, now = args\n        if instance is None or observation is None:\n            return\n        instance.add_metadata(observation, info, now)\n\n    def extract_metadata(self, observation_n):\n        return [instance._extract_metadata(observation)\n                for instance, observation in zip(self.instance_n, observation_n)]\n\n    def clear_probes_when_done(self, done_n):\n        if self.instance_n is None: # if we've been closed there's nothing to do\n            return\n        for instance, done in zip(self.instance_n, done_n):\n            if done:\n                instance.clear_probe()\n\nclass DiagnosticsInstance(object):\n    anchor = np.array([\n        [(0x12, 0x12, 0x12), (0x78, 0x78, 0x78)],\n        [(0x23, 0x23, 0x23), (0x89, 0x89, 0x89)],\n    ], dtype=np.uint8)\n    zero_clock_skew = np.zeros([2])\n\n    def __init__(self, i, network, probe_key, ignore_clock_skew, metadata_encoding, disable_action_probes, pool, qr_pool, label=None):\n        '''\n        network - either Network() object used to get clock skew, or None.\n\n                  If None, we skip measuring clock skew, and skip measuring\n                  diagnostics which rely on clock skew.\n        '''\n        if network is None:\n            assert ignore_clock_skew\n        self.ignore_clock_skew = ignore_clock_skew\n\n        self.label = label\n        self.i = i\n        self.network = network\n\n        self.probe_sent_at = None # local time\n        self.probe_received_at = None # remote time\n        self.action_latency_skewed = None\n        self.last_observation_timestamp = None\n        self.disable_action_probes = disable_action_probes\n\n        self.pool = pool\n        self.qr_pool = qr_pool\n        self.could_read_metadata = None\n        self.update(probe_key=probe_key, metadata_encoding=metadata_encoding)\n\n    def update(self, probe_key, metadata_encoding):\n        self.probe = [\n                spaces.KeyEvent(probe_key, down=True).compile(),\n                spaces.KeyEvent(probe_key, down=False).compile(),\n        ]\n\n        if metadata_encoding is not None:\n            self.metadata_decoder = MetadataDecoder.build(metadata_encoding, pool=self.pool, qr_pool=self.qr_pool, label=self.label)\n        else:\n            self.metadata_decoder = None\n\n    def clear_probe(self):\n        self.probe_sent_at = None\n        self.probe_received_at = None\n\n    def add_probe(self, action):\n        if self.network is not None and not self.network.active():\n            return\n\n        if self.probe_sent_at is not None and self.probe_sent_at + 10 < time.time():\n            extra_logger.warn('[%s] Probe to determine action latency timed out (was sent %s). (This is harmless, but worth knowing about.)', self.label, self.probe_sent_at)\n            self.probe_sent_at = None\n        if self.probe_sent_at is None:\n            extra_logger.debug('[%s] Sending out new action probe: %s', self.label, self.probe)\n            self.probe_sent_at = time.time()\n            action += self.probe\n        assert self.probe_sent_at is not None\n\n    def add_metadata(self, observation, info, available_at=None):\n        \"\"\"Extract metadata from a pixel observation and add it to the info\n        \"\"\"\n        observation = observation['vision']\n        if observation is None: return\n        if self.network is not None and not self.network.active():\n            return\n        elif self.metadata_decoder is None:\n            return\n        elif observation is None:\n            return\n        # should return a dict with now/probe_received_at keys\n        with pyprofile.push('vnc_env.diagnostics.DiagnosticsInstance.add_metadata.decode'):\n            metadata = self.metadata_decoder.decode(observation, available_at=available_at)\n\n        if metadata is False:\n            # No metadata ready, though it doesn't mean parsing failed\n            metadata = None\n        elif metadata is None:\n            if self.could_read_metadata:\n                self.could_read_metadata = False\n                extra_logger.info('[%s] Stopped being able to read metadata (expected when environment resets)', self.label)\n        elif not self.could_read_metadata:\n            self.could_read_metadata = True\n            extra_logger.info('[%s] Started being able to read metadata', self.label)\n\n        if self.metadata_decoder.flag_synchronous and metadata is not None:\n            info['diagnostics.image_remote_time'] = metadata['now']\n\n        local_now = time.time()\n\n        if self.network is None:\n            # Assume the clock skew is zero. Should only be run on the\n            # same machine as the VNC server, such as the universe\n            # instance inside of the environmenth containers.\n            real_clock_skew = self.zero_clock_skew\n        else:\n            # Note: this is a 2-length vector of (min, max), so anything added to\n            # it is also going to be a 2-length vector.\n            # Most of the diagnostics below are, but you have to look carefully.\n            real_clock_skew = self.network.reversed_clock_skew()\n\n        # Store real clock skew here\n        info['stats.gauges.diagnostics.clock_skew'] = real_clock_skew\n        if self.ignore_clock_skew:\n            clock_skew = self.zero_clock_skew\n        else:\n            clock_skew = real_clock_skew\n\n        if metadata is not None:\n            # We'll generally update the observation timestamp infrequently\n            if self.last_observation_timestamp == metadata['now']:\n                delta = None\n            else:\n                # We just got a new timestamp in the observation!\n                self.last_observation_timestamp = metadata['now']\n                observation_now = metadata['now']\n                delta = observation_now - metadata['available_at']\n\n                # Subtract *local* time it was received from the *remote* time\n                # displayed. Negate and reverse order to fix time ordering.\n                info['stats.gauges.diagnostics.lag.observation'] = -(delta + clock_skew)[[1, 0]]\n\n            # if self.network is None:\n            #     # The rest of diagnostics need the network, so we're done here\n            #     return\n\n            probe_received_at = metadata['probe_received_at']\n            if probe_received_at == 0 or self.disable_action_probes:\n                # Happens when the env first starts\n                self.probe_received_at = None\n            elif self.probe_received_at is None: # this also would work for the equality case\n                self.probe_received_at = probe_received_at\n            elif self.probe_received_at != probe_received_at and self.probe_sent_at is None:\n                logger.info('[%s] Probe is marked as received at %s, but probe_sent_at is None. This is surprising. (HINT: do you have multiple universe instances talking to the same environment?)', self.label, probe_received_at)\n            elif self.probe_received_at != probe_received_at:\n                extra_logger.debug('[%s] Next probe received: old=%s new=%s', self.label, self.probe_received_at, probe_received_at)\n                self.probe_received_at = probe_received_at\n                # Subtract the *local* time we sent it from the *remote* time it was received\n                self.action_latency_skewed = probe_received_at - self.probe_sent_at\n                self.probe_sent_at = None\n\n            if self.action_latency_skewed:\n                action_lag = self.action_latency_skewed + clock_skew\n                self.action_latency_skewed = None\n            else:\n                action_lag = None\n            info['stats.gauges.diagnostics.lag.action'] = action_lag\n\n        local_now = time.time()\n        # Look at when the remote believed it parsed the score (not\n        # all envs send this currently).\n        #\n        # Also, if we received no new rewards, then this values is\n        # None. This could indicate a high reward latency (bad,\n        # uncommon), or that the agent is calling step faster than new\n        # rewards are coming in (good, common).\n        remote_score_now = info.get('rewarder.lag.observation.timestamp')\n        if remote_score_now is not None:\n            delta = remote_score_now - local_now\n            info['stats.gauges.diagnostics.lag.reward'] = -(delta + clock_skew)[[1, 0]]\n\n        # Look at when the remote send the message, so we know how\n        # long it's taking for messages to get to us.\n        rewarder_message_now = info.get('reward_buffer.remote_time')\n        if rewarder_message_now:\n            delta = rewarder_message_now - local_now\n            info['stats.gauges.diagnostics.lag.rewarder_message'] = -(delta + clock_skew)[[1, 0]]\n\n\ndef extract_n_m(dict_n_m, key):\n    output = []\n    for dict_n in dict_n_m:\n        layer = []\n        for dict in dict_n:\n            layer.append(dict[key])\n        output.append(layer)\n    return np.array(output)\n\n\n# class ChromeProcessInfo(object):\n#     proc_regex = re.compile('.*(chrome|Chrome|nacl_helper).*')\n\n#     def add_system_stats(self, info, now):\n#         \"\"\"TODO: This needs be moved to universe-envs and run there. Otherwise it only works if the env and agent\n#             are on the same machine. In addition a new rpc call, rpc.env.diagnostics, should be added to return\n#             data to the agent periodically.\n#         \"\"\"\n#         start = time.time()\n\n#         # CPU\n#         cpu_percent = psutil.cpu_percent()\n#         info['diagnostics.env.cpu.percent'] = cpu_percent\n#         cpu_cores_percent = psutil.cpu_percent(percpu=True)\n#         num_cores = len(cpu_cores_percent)\n#         info['diagnostics.env.cpu.percent.all_cores'] = cpu_percent / num_cores\n#         info['diagnostics.env.cpu.percent.each_core'] = cpu_cores_percent\n#         info['diagnostics.env.cpu.num_cores'] = num_cores\n\n#         # MEMORY\n#         mem = psutil.virtual_memory()\n#         info['diagnostics.env.memory.percent'] = mem.percent\n#         info['diagnostics.env.memory.total'] = mem.total\n#         info['diagnostics.env.memory.available'] = mem.available\n\n#         # NETWORK\n#         if self.last_measured_at is not None:\n#             elapsed_ms = (now - self.last_measured_at) * 1000.\n#             current = psutil.net_io_counters()\n#             dl = (current.bytes_recv - self.system_network_counters.bytes_recv) / elapsed_ms\n#             ul = (current.bytes_sent - self.system_network_counters.bytes_sent) / elapsed_ms\n#             info['diagnostics.env.network.download_bytes_ps'] = dl * 1000.\n#             info['diagnostics.env.network.upload_bytes_ps'] = ul * 1000.\n#             self.system_network_counters = current\n\n#         # CHROME\n#         if self.chrome_last_measured_at is None or (time.time() - self.chrome_last_measured_at) > 30:\n#             # Fetch every 30 seconds\n#             self.chrome_last_measured_at = time.time()\n#             logger.info(\"Measuring Chrome process statistics\")\n#             chrome_info = ChromeProcessInfo()\n#             chrome_info = best_effort(chrome_info.fetch, num_cores)\n#             if chrome_info is not None:\n#                 self.chrome_info = chrome_info\n\n#         if self.chrome_info is not None:\n#             self._populate_chrome_info(self.chrome_info, info)\n\n#         # TODO: Add GPU stats\n\n#         pyprofile.push('diagnostics.system_stats')\n\n#     def _populate_chrome_info(self, chrome_info, info):\n#         pyprofile.push('diagnostics.chrome_process_info.process_iter')\n#         pyprofile.push('diagnostics.chrome_process_info.total')\n#         info['diagnostics.chrome.age'] = chrome_info.age\n#         info['diagnostics.chrome.cpu.time'] = chrome_info.cpu_time\n#         info['diagnostics.chrome.cpu.percent'] = chrome_info.cpu_percent\n#         info['diagnostics.chrome.cpu.percent.all_cores'] = chrome_info.cpu_percent_all_cores\n#         info['diagnostics.chrome.cpu.percent.all_cores_all_time'] = chrome_info.cpu_percent_all_cores_all_time\n#         info['diagnostics.chrome.num_processes'] = len(chrome_info.processes)\n\n#     def __init__(self):\n#         self.cpu_time = 0.\n#         self.cpu_percent = 0.\n#         self.min_create_time = None\n#         self.visited_pids = set()\n#         self.processes = []\n#         self.time_to_get_procs = None\n#         self.total_time_to_measure = None\n#         self.age = None\n#         self.cpu_percent_all_cores_all_time = None\n#         self.cpu_percent_all_cores = None\n\n#     def fetch(self, num_cores):\n#         start = time.time()\n#         start_process_iter = time.time()\n#         procs = list(psutil.process_iter())\n#         self.time_to_get_procs = time.time() - start_process_iter\n#         for proc in procs:\n#             try:\n#                 name = proc.name()\n#                 if self.proc_regex.match(name):\n#                     self._fetch_single(proc, name)\n#                     # N.B. Don't read children. defunct processes make this take 4ever.\n#                     # Child processes are all uncovered by initial scan.\n#             except (psutil.AccessDenied, psutil.NoSuchProcess) as e:\n#                 pass\n#         self.total_time_to_measure = time.time() - start\n#         if self.min_create_time is None:\n#             self.age = 0\n#         else:\n#             self.age = time.time() - self.min_create_time\n#         self.cpu_percent_all_cores_all_time = 100. * self.cpu_time / (self.age * num_cores)\n#         self.cpu_percent_all_cores = self.cpu_percent / num_cores\n#         return self\n\n#     def _fetch_single(self, proc, name):\n#         if proc.pid in self.visited_pids:\n#             return\n#         try:\n#             cpu_times = proc.cpu_times()\n#             cpu_percent = proc.cpu_percent()\n#             created = proc.create_time()\n#             if self.min_create_time is None:\n#                 self.min_create_time = created\n#             else:\n#                 self.min_create_time = min(created, self.min_create_time)\n\n#             cpu_time = cpu_times.user + cpu_times.system\n#             proc_info = namedtuple('proc_info', 'name cpu_time cpu_percent created age')\n#             proc_info.name = name\n#             proc_info.cpu_time = cpu_time\n#             proc_info.cpu_percent = cpu_percent\n#             proc_info.created = created\n#             proc_info.age = time.time() - created\n#             proc_info.pid = proc.pid\n#             self.processes.append(proc_info)\n\n#             # Totals\n#             self.cpu_time += cpu_time\n#             self.cpu_percent += cpu_percent\n#             self.visited_pids.add(proc.pid)\n\n\n#         except (psutil.AccessDenied, psutil.NoSuchProcess) as e:\n#             pass\n"
  },
  {
    "path": "universe/envs/dummy_vnc_env.py",
    "content": "import logging\nimport numpy as np\n\nfrom gym.utils import reraise\n\nfrom universe import error, rewarder, spaces, utils, vectorized\nfrom universe.envs import diagnostics\nfrom universe.remotes import healthcheck\nfrom universe.runtimes import registration\n\nclass DummyVNCEnv(vectorized.Env):\n    \"\"\"\n    A simple env for unit testing that does nothing, but looks like a VNC env.\n    It accepts any actions, and returns black screens.\n    It also returns the actions in the observation, so you can test that action wrappers are producing the right answers\n    For example, to test that YourActionWrapper converts example_input_action to example_output_action:\n\n    >>> dummy_env = gym.make('test.DummyVNCEnv-v0')\n    >>> e = YourActionWrapper(dummy_env)\n    >>> e = universe.wrappers.Unvectorize(e)\n    >>> observation, reward, done, info = e.step(example_input_action)\n    >>> assert observation['action'] == example_output_action\n\n    \"\"\"\n    metadata = {\n        'render.modes': ['human'], # we wrap with a Render which can render to rgb_array\n        'semantics.async': True,\n        'semantics.autoreset': True,\n        'video.frames_per_second' : 60,\n        'runtime.vectorized': True,\n    }\n\n    def __init__(self):\n        self._started = False\n\n        self.observation_space = spaces.VNCObservationSpace()\n        self.action_space = spaces.VNCActionSpace()\n\n    def configure(self, remotes=None,\n                   client_id=None,\n                   start_timeout=None, docker_image=None,\n                   ignore_clock_skew=False, disable_action_probes=False,\n                   vnc_driver=None, vnc_kwargs={},\n                   replace_on_crash=False, allocate_sync=True,\n                   observer=False,\n                   _n=3,\n    ):\n        self.n = _n\n        self._reward_buffers = [rewarder.RewardBuffer('dummy:{}'.format(i)) for i in range(self.n)]\n        self._started = True\n\n    def _reset(self):\n        return [None] * self.n\n\n    def _step(self, action_n):\n        assert self.n == len(action_n), \"Expected {} actions but received {}: {}\".format(self.n, len(action_n), action_n)\n\n        observation_n = [{\n            'vision': np.zeros((1024, 768, 3), dtype=np.uint8),\n            'text': [],\n            'action': action_n[i]\n        } for i in range(self.n)]\n\n        reward_n = []\n        done_n = []\n        info_n = []\n        for reward_buffer in self._reward_buffers:\n            reward, done, info = reward_buffer.pop()\n            reward_n.append(reward)\n            done_n.append(done)\n            info_n.append(info)\n        return observation_n, reward_n, done_n, {'n': info_n}\n\n    def __str__(self):\n        return 'DummyVNCEnv'\n"
  },
  {
    "path": "universe/envs/tests/__init__.py",
    "content": ""
  },
  {
    "path": "universe/envs/tests/test_semantics.py",
    "content": "# import numpy as np\n# from universe import vectorized\n\n# class SimpleEnv(vectorized.Env):\n#     def _step(self, action_n):\n#         return {'vision': np.zeros((10, 10))}, 10, False, {}\n\n\n# from universe.envs import vnc_env\nimport gym\nimport numpy as np\nimport os\nimport universe\n\nfrom autobahn.twisted import websocket\nfrom PIL import Image\n\nfrom universe.rewarder import rewarder_client, rewarder_session, reward_buffer\nfrom universe import spaces, wrappers\n\ndef get_rewarder_session(env):\n    return env.unwrapped.rewarder_session\n\ndef get_vnc_session(env):\n    return env.unwrapped.vnc_session\n\ndef get_rewarder_client(env):\n    rewarder_session = get_rewarder_session(env)\n    return rewarder_session.connections['0'].rewarder_client\n\ndef get_reward_buffer(env):\n    rewarder_session = get_rewarder_session(env)\n    return rewarder_session.connections['0'].reward_buffer\n\ndef setup_module(module):\n    universe.configure_logging('-')\n\nclass FakeVNCConnection(object):\n    def __init__(self, name, address, password, encoding=None, fine_quality_level=None, subsample_level=None, start_timeout=None):\n        self.name = name\n        self.address = address\n        self.password = password\n        self.encoding = encoding\n        self.fine_quality_level = fine_quality_level\n        self.subsample_level = subsample_level\n        self.start_timeout = start_timeout\n\n        self._frame = np.array(Image.open(os.path.join(os.path.dirname(__file__), 'dusk-drive.png')))\n\n    def step(self, action):\n        info_d = {}\n        return self._frame, info_d\n\n    def _to_dict(self):\n        return {\n            'name': self.name,\n            'address': self.address,\n            'password': self.password,\n            'encoding': self.encoding,\n            'fine_quality_level': self.fine_quality_level,\n            'subsample_level': self.subsample_level,\n            'start_timeout': self.start_timeout,\n        }\n\nclass FakeVNCSession(object):\n    def __init__(self):\n        self.connections = {}\n\n    def connect(self, name, **kwargs):\n        self.connections[name] = FakeVNCConnection(name=name, **kwargs)\n\n    def close(self, name=None):\n        if name is not None:\n            del self.connections[name]\n        else:\n            self.connections = None\n\n    def step(self, action_d):\n        observation_d = {}\n        info_d = {}\n        err_d = {}\n        for name, conn in self.connections.items():\n            observation, info = conn.step(action_d.get(name, []))\n            observation_d[name] = observation\n            info_d[name] = info\n        return observation_d, info_d, err_d\n\n    def _to_dict(self):\n        return {name: conn._to_dict() for name, conn in self.connections.items()}\n\nclass FakeRewarderConnection(object):\n    def __init__(self, name, address, label, password, env_id=None, seed=None, fps=60,\n                 start_timeout=None, observer=False, skip_network_calibration=False):\n        self.name = name\n        self.address = address\n        self.label = label\n        self.password = password\n        self.env_id = env_id\n        self.seed = None\n        self.fps = fps\n        self.start_timeout = start_timeout\n        self.observer = observer\n        self.skip_network_calibration = skip_network_calibration\n\n        self.reward_buffer = reward_buffer.RewardBuffer(label=self.label)\n\n        factory = websocket.WebSocketClientFactory('ws://'+address)\n        factory.reward_buffer = self.reward_buffer\n        factory.label = self.label\n        self.rewarder_client = rewarder_client.RewarderClient()\n        self.rewarder_client.factory = factory\n        self.rewarder_client.onConnect(None)\n\n    def reset(self, seed=None):\n        self.seed = seed\n\n    def pop(self, peek=False):\n        return self.reward_buffer.pop(peek=peek)\n\n    def _to_dict(self):\n        return {\n            'name': self.name,\n            'address': self.address,\n            'label': self.label,\n            'password': self.password,\n            'env_id': self.env_id,\n            'seed': self.seed,\n            'fps': self.fps,\n            'start_timeout': self.start_timeout,\n            'observer': self.observer,\n            'skip_network_calibration': self.skip_network_calibration,\n        }\n\nclass FakeRewarder(object):\n    def __init__(self):\n        self.connections = {}\n\n    def reset(self, seed=None, **kwargs):\n        for conn in self.connections.values():\n            conn.reset(seed=seed)\n\n    def connect(self, name, **kwargs):\n        self.connections[name] = FakeRewarderConnection(name=name, **kwargs)\n        return rewarder_session.Network()\n\n    def close(self, name=None):\n        if name is not None:\n            del self.connections[name]\n        else:\n            self.connections = None\n\n    def pop(self, peek_d):\n        reward_d = {}\n        done_d = {}\n        info_d = {}\n        err_d = {}\n        for name, conn in self.connections.items():\n            reward, done, info = conn.pop(peek=peek_d.get(name))\n            reward_d[name] = reward\n            done_d[name] = done\n            info_d[name] = info\n        return reward_d, done_d, info_d, err_d\n\n    def _to_dict(self):\n        return {name: conn._to_dict() for name, conn in self.connections.items()}\n\ndef test_connect():\n    env = gym.make('flashgames.DuskDrive-v0')\n    env.configure(vnc_driver=FakeVNCSession, rewarder_driver=FakeRewarder, remotes='vnc://example.com:5900+15900')\n    vnc_session = get_vnc_session(env)\n    rewarder_session = get_rewarder_session(env)\n\n    assert vnc_session._to_dict() == {'0': {'name': '0', 'subsample_level': 2, 'encoding': 'tight', 'fine_quality_level': 50, 'start_timeout': 7, 'address': 'example.com:5900', 'password': 'openai'}}\n    assert rewarder_session._to_dict() == {'0': {'start_timeout': 7, 'seed': None, 'name': '0', 'fps': 60, 'address': 'example.com:15900', 'env_id': 'flashgames.DuskDrive-v0', 'password': 'openai', 'skip_network_calibration': False, 'observer': False, 'label': '0:example.com:5900'}}\n\ndef test_describe_handling():\n    env = gym.make('flashgames.DuskDrive-v0')\n    env.configure(vnc_driver=FakeVNCSession, rewarder_driver=FakeRewarder, remotes='vnc://example.com:5900+15900')\n    env.reset()\n\n    reward_buffer = get_reward_buffer(env)\n    rewarder_client = get_rewarder_client(env)\n\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'resetting', 'fps': 60}, {'episode_id': '1'})\n\n    assert reward_buffer._remote_episode_id == '1'\n    assert reward_buffer._remote_env_state == 'resetting'\n    assert reward_buffer._current_episode_id == None\n    assert reward_buffer.reward_state(reward_buffer._current_episode_id)._env_state == None\n\n    rewarder_client._manual_recv('v0.reply.env.reset', {}, {'episode_id': '1'})\n\n    assert reward_buffer._remote_episode_id == '1'\n    assert reward_buffer._remote_env_state == 'resetting'\n    assert reward_buffer._current_episode_id == '1'\n    assert reward_buffer.reward_state(reward_buffer._current_episode_id)._env_state == 'resetting'\n\ndef test_vnc_env():\n    env = gym.make('flashgames.DuskDrive-v0')\n    env = wrappers.Unvectorize(env)\n    env.configure(vnc_driver=FakeVNCSession, rewarder_driver=FakeRewarder, remotes='vnc://example.com:5900+15900')\n    env.reset()\n\n    rewarder_client = get_rewarder_client(env)\n\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'resetting', 'fps': 60}, {'episode_id': '1'})\n\n    observation, reward, done, info = env.step([spaces.KeyEvent.by_name('a', down=True)])\n    assert (observation, reward, done, info['env_status.env_state'], info['env_status.episode_id']) == (None, 0, False, None, None)\n\n    rewarder_client._manual_recv('v0.reply.env.reset', {}, {'episode_id': '1'})\n\n    observation, reward, done, info = env.step([spaces.KeyEvent.by_name('a', down=True)])\n    assert (observation, reward, done, info['env_status.env_state'], info['env_status.episode_id']) == (None, 0, False, 'resetting', '1')\n\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'running', 'fps': 60}, {'episode_id': '1'})\n\n    rewarder_client._manual_recv('v0.env.reward', {'reward': 10, 'done': False, 'info': {}}, {'episode_id': '1'})\n    rewarder_client._manual_recv('v0.env.reward', {'reward': 15, 'done': False, 'info': {}}, {'episode_id': '1'})\n    rewarder_client._manual_recv('v0.env.reward', {'reward': -3, 'done': False, 'info': {}}, {'episode_id': '1'})\n\n    observation, reward, done, info = env.step([spaces.KeyEvent.by_name('a', down=True)])\n    assert sorted(observation.keys()) == ['text', 'vision']\n    assert observation['text'] == []\n    assert observation['vision'].shape == (768, 1024, 3)\n    assert (reward, done, info['env_status.env_state'], info['env_status.episode_id']) == (22, False, 'running', '1')\n    assert info['stats.reward.count'] == 3\n\ndef test_boundary_simple():\n    env = gym.make('flashgames.DuskDrive-v0')\n    env = wrappers.Unvectorize(env)\n    env.configure(vnc_driver=FakeVNCSession, rewarder_driver=FakeRewarder, remotes='vnc://example.com:5900+15900')\n    env.reset()\n\n    rewarder_client = get_rewarder_client(env)\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'resetting', 'fps': 60}, {'episode_id': '1'})\n    rewarder_client._manual_recv('v0.reply.env.reset', {}, {'episode_id': '1'})\n\n    rewarder_client._manual_recv('v0.env.reward', {'reward': 1, 'done': False, 'info': {}}, {'episode_id': '1'})\n    rewarder_client._manual_recv('v0.env.reward', {'reward': 2, 'done': True, 'info': {}}, {'episode_id': '1'})\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'resetting', 'fps': 60}, {'episode_id': '2'})\n\n    # We have reward of 3 for episode 1, and episode 2 should now be resetting\n    observation, reward, done, info = env.step([])\n    assert info['mask.masked.observation']\n    assert info['mask.masked.action']\n    assert (reward, done, info['env_status.env_state'], info['env_status.episode_id']) == (3, True, 'resetting', '2')\n\ndef test_boundary_multiple():\n    env = gym.make('flashgames.DuskDrive-v0')\n    env = wrappers.Unvectorize(env)\n    env.configure(vnc_driver=FakeVNCSession, rewarder_driver=FakeRewarder, remotes='vnc://example.com:5900+15900')\n    env.reset()\n\n    rewarder_client = get_rewarder_client(env)\n    # episode 2\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'resetting', 'fps': 60}, {'episode_id': '2'})\n    rewarder_client._manual_recv('v0.reply.env.reset', {}, {'episode_id': '2'})\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'running', 'fps': 60}, {'episode_id': '2'})\n    rewarder_client._manual_recv('v0.env.reward', {'reward': 2, 'done': True, 'info': {}}, {'episode_id': '2'})\n\n    # episode 3\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'resetting', 'fps': 60}, {'episode_id': '3'})\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'running', 'fps': 60}, {'episode_id': '3'})\n    rewarder_client._manual_recv('v0.env.reward', {'reward': 3, 'done': True, 'info': {}}, {'episode_id': '3'})\n\n    # episode 4\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'resetting', 'fps': 60}, {'episode_id': '4'})\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'running', 'fps': 60}, {'episode_id': '4'})\n    rewarder_client._manual_recv('v0.env.reward', {'reward': 4, 'done': False, 'info': {}}, {'episode_id': '4'})\n\n    observation, reward, done, info = env.step([])\n    assert not info.get('mask.masked.observation')\n    assert not info.get('mask.masked.action')\n    assert (reward, done, info['env_status.env_state'], info['env_status.episode_id']) == (2, True, 'running', '4')\n    assert (info['env_status.complete.env_state'], info['env_status.complete.episode_id']) == ('running', '2')\n\n    observation, reward, done, info = env.step([])\n    assert (reward, done, info['env_status.env_state'], info['env_status.episode_id']) == (4, False, 'running', '4')\n\ndef test_peek():\n    env = gym.make('flashgames.DuskDrive-v0')\n    env = wrappers.Unvectorize(env)\n    env.configure(vnc_driver=FakeVNCSession, rewarder_driver=FakeRewarder, remotes='vnc://example.com:5900+15900')\n    env.reset()\n\n    rewarder_client = get_rewarder_client(env)\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'resetting', 'fps': 60}, {'episode_id': '1'})\n    rewarder_client._manual_recv('v0.reply.env.reset', {}, {'episode_id': '1'})\n\n    observation, reward, done, info = env.step([spaces.PeekReward])\n\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'resetting', 'fps': 60}, {'episode_id': '2'})\n    observation, reward, done, info = env.step([spaces.PeekReward])\n    assert info['mask.masked.observation']\n    assert info['mask.masked.action']\n    assert info['env_status.episode_id'] == '1'\n    assert info['env_status.env_state'] == 'resetting'\n    assert info['env_status.peek.episode_id'] == '2'\n    assert info['env_status.peek.env_state'] == 'resetting'\n\n    rewarder_client._manual_recv('v0.env.describe', {'env_id': 'flashgames.DuskDrive-v0', 'env_state': 'running', 'fps': 60}, {'episode_id': '2'})\n    observation, reward, done, info = env.step([spaces.PeekReward])\n    assert not info.get('mask.masked.observation')\n    assert not info.get('mask.masked.action')\n    assert info['env_status.episode_id'] == '1'\n    assert info['env_status.env_state'] == 'resetting'\n    assert info['env_status.peek.episode_id'] == '2'\n    assert info['env_status.peek.env_state'] == 'running'\n"
  },
  {
    "path": "universe/envs/vnc_core_env/__init__.py",
    "content": "from universe.envs.vnc_core_env.vnc_core_env import GymCoreEnv, GymCoreSyncEnv\nfrom universe.envs.vnc_core_env.translator import AtariTranslator, CartPoleTranslator\n"
  },
  {
    "path": "universe/envs/vnc_core_env/key.py",
    "content": "# imported from Pyglet\n\n# ----------------------------------------------------------------------------\n# pyglet\n# Copyright (c) 2006-2008 Alex Holkner\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions\n# are met:\n#\n#  * Redistributions of source code must retain the above copyright\n#    notice, this list of conditions and the following disclaimer.\n#  * Redistributions in binary form must reproduce the above copyright\n#    notice, this list of conditions and the following disclaimer in\n#    the documentation and/or other materials provided with the\n#    distribution.\n#  * Neither the name of pyglet nor the names of its\n#    contributors may be used to endorse or promote products\n#    derived from this software without specific prior written\n#    permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n# ----------------------------------------------------------------------------\n\n'''Key constants and utilities for pyglet.window.\n\nUsage::\n\n    from pyglet.window import Window\n    from pyglet.window import key\n\n    window = Window()\n\n    @window.event\n    def on_key_press(symbol, modifiers):\n        # Symbolic names:\n        if symbol == key.RETURN:\n\n        # Alphabet keys:\n        elif symbol == key.Z:\n\n        # Number keys:\n        elif symbol == key._1:\n\n        # Number keypad keys:\n        elif symbol == key.NUM_1:\n\n        # Modifiers:\n        if modifiers & key.MOD_CTRL:\n\n'''\n\n__docformat__ = 'restructuredtext'\n__version__ = '$Id$'\n\nclass KeyStateHandler(dict):\n    '''Simple handler that tracks the state of keys on the keyboard. If a\n    key is pressed then this handler holds a True value for it.\n\n    For example::\n\n        >>> win = window.Window\n        >>> keyboard = key.KeyStateHandler()\n        >>> win.push_handlers(keyboard)\n\n        # Hold down the \"up\" arrow...\n\n        >>> keyboard[key.UP]\n        True\n        >>> keyboard[key.DOWN]\n        False\n\n    '''\n    def on_key_press(self, symbol, modifiers):\n        self[symbol] = True\n    def on_key_release(self, symbol, modifiers):\n        self[symbol] = False\n    def __getitem__(self, key):\n        return self.get(key, False)\n\ndef modifiers_string(modifiers):\n    '''Return a string describing a set of modifiers.\n\n    Example::\n\n        >>> modifiers_string(MOD_SHIFT | MOD_CTRL)\n        'MOD_SHIFT|MOD_CTRL'\n\n    :Parameters:\n        `modifiers` : int\n            Bitwise combination of modifier constants.\n\n    :rtype: str\n    '''\n    mod_names = []\n    if modifiers & MOD_SHIFT:\n        mod_names.append('MOD_SHIFT')\n    if modifiers & MOD_CTRL:\n        mod_names.append('MOD_CTRL')\n    if modifiers & MOD_ALT:\n        mod_names.append('MOD_ALT')\n    if modifiers & MOD_CAPSLOCK:\n        mod_names.append('MOD_CAPSLOCK')\n    if modifiers & MOD_NUMLOCK:\n        mod_names.append('MOD_NUMLOCK')\n    if modifiers & MOD_SCROLLLOCK:\n        mod_names.append('MOD_SCROLLLOCK')\n    if modifiers & MOD_COMMAND:\n        mod_names.append('MOD_COMMAND')\n    if modifiers & MOD_OPTION:\n        mod_names.append('MOD_OPTION')\n    if modifiers & MOD_FUNCTION:\n        mod_names.append('MOD_FUNCTION')\n    return '|'.join(mod_names)\n\ndef symbol_string(symbol):\n    '''Return a string describing a key symbol.\n\n    Example::\n\n        >>> symbol_string(BACKSPACE)\n        'BACKSPACE'\n\n    :Parameters:\n        `symbol` : int\n            Symbolic key constant.\n\n    :rtype: str\n    '''\n    if symbol < 1 << 32:\n        return _key_names.get(symbol, str(symbol))\n    else:\n        return 'user_key(%x)' % (symbol >> 32)\n\ndef motion_string(motion):\n    '''Return a string describing a text motion.\n\n    Example::\n\n        >>> motion_string(MOTION_NEXT_WORD):\n        'MOTION_NEXT_WORD'\n\n    :Parameters:\n        `motion` : int\n            Text motion constant.\n\n    :rtype: str\n    '''\n    return _motion_names.get(motion, str(motion))\n\ndef user_key(scancode):\n    '''Return a key symbol for a key not supported by pyglet.\n\n    This can be used to map virtual keys or scancodes from unsupported\n    keyboard layouts into a machine-specific symbol.  The symbol will\n    be meaningless on any other machine, or under a different keyboard layout.\n\n    Applications should use user-keys only when user explicitly binds them\n    (for example, mapping keys to actions in a game options screen).\n    '''\n    assert scancode > 0\n    return scancode << 32\n\n# Modifier mask constants\nMOD_SHIFT       = 1 << 0\nMOD_CTRL        = 1 << 1\nMOD_ALT         = 1 << 2\nMOD_CAPSLOCK    = 1 << 3\nMOD_NUMLOCK     = 1 << 4\nMOD_WINDOWS     = 1 << 5\nMOD_COMMAND     = 1 << 6\nMOD_OPTION      = 1 << 7\nMOD_SCROLLLOCK  = 1 << 8\nMOD_FUNCTION    = 1 << 9\n\n#: Accelerator modifier.  On Windows and Linux, this is ``MOD_CTRL``, on\n#: Mac OSX it's ``MOD_COMMAND``.\nMOD_ACCEL       = MOD_CTRL\n# gdb: don't need this import\n# from pyglet import compat_platform\n# if compat_platform == 'darwin':\n#     MOD_ACCEL   = MOD_COMMAND\n\n\n# Key symbol constants\n\n# ASCII commands\nBACKSPACE     = 0xff08\nTAB           = 0xff09\nLINEFEED      = 0xff0a\nCLEAR         = 0xff0b\nRETURN        = 0xff0d\nENTER         = 0xff0d      # synonym\nPAUSE         = 0xff13\nSCROLLLOCK    = 0xff14\nSYSREQ        = 0xff15\nESCAPE        = 0xff1b\nSPACE         = 0xff20\n\n# Cursor control and motion\nHOME          = 0xff50\nLEFT          = 0xff51\nUP            = 0xff52\nRIGHT         = 0xff53\nDOWN          = 0xff54\nPAGEUP        = 0xff55\nPAGEDOWN      = 0xff56\nEND           = 0xff57\nBEGIN         = 0xff58\n\n# Misc functions\nDELETE        = 0xffff\nSELECT        = 0xff60\nPRINT         = 0xff61\nEXECUTE       = 0xff62\nINSERT        = 0xff63\nUNDO          = 0xff65\nREDO          = 0xff66\nMENU          = 0xff67\nFIND          = 0xff68\nCANCEL        = 0xff69\nHELP          = 0xff6a\nBREAK         = 0xff6b\nMODESWITCH    = 0xff7e\nSCRIPTSWITCH  = 0xff7e\nFUNCTION      = 0xffd2\n\n# Text motion constants: these are allowed to clash with key constants\nMOTION_UP                = UP\nMOTION_RIGHT             = RIGHT\nMOTION_DOWN              = DOWN\nMOTION_LEFT              = LEFT\nMOTION_NEXT_WORD         = 1\nMOTION_PREVIOUS_WORD     = 2\nMOTION_BEGINNING_OF_LINE = 3\nMOTION_END_OF_LINE       = 4\nMOTION_NEXT_PAGE         = PAGEDOWN\nMOTION_PREVIOUS_PAGE     = PAGEUP\nMOTION_BEGINNING_OF_FILE = 5\nMOTION_END_OF_FILE       = 6\nMOTION_BACKSPACE         = BACKSPACE\nMOTION_DELETE            = DELETE\n\n# Number pad\nNUMLOCK       = 0xff7f\nNUM_SPACE     = 0xff80\nNUM_TAB       = 0xff89\nNUM_ENTER     = 0xff8d\nNUM_F1        = 0xff91\nNUM_F2        = 0xff92\nNUM_F3        = 0xff93\nNUM_F4        = 0xff94\nNUM_HOME      = 0xff95\nNUM_LEFT      = 0xff96\nNUM_UP        = 0xff97\nNUM_RIGHT     = 0xff98\nNUM_DOWN      = 0xff99\nNUM_PRIOR     = 0xff9a\nNUM_PAGE_UP   = 0xff9a\nNUM_NEXT      = 0xff9b\nNUM_PAGE_DOWN = 0xff9b\nNUM_END       = 0xff9c\nNUM_BEGIN     = 0xff9d\nNUM_INSERT    = 0xff9e\nNUM_DELETE    = 0xff9f\nNUM_EQUAL     = 0xffbd\nNUM_MULTIPLY  = 0xffaa\nNUM_ADD       = 0xffab\nNUM_SEPARATOR = 0xffac\nNUM_SUBTRACT  = 0xffad\nNUM_DECIMAL   = 0xffae\nNUM_DIVIDE    = 0xffaf\n\nNUM_0         = 0xffb0\nNUM_1         = 0xffb1\nNUM_2         = 0xffb2\nNUM_3         = 0xffb3\nNUM_4         = 0xffb4\nNUM_5         = 0xffb5\nNUM_6         = 0xffb6\nNUM_7         = 0xffb7\nNUM_8         = 0xffb8\nNUM_9         = 0xffb9\n\n# Function keys\nF1            = 0xffbe\nF2            = 0xffbf\nF3            = 0xffc0\nF4            = 0xffc1\nF5            = 0xffc2\nF6            = 0xffc3\nF7            = 0xffc4\nF8            = 0xffc5\nF9            = 0xffc6\nF10           = 0xffc7\nF11           = 0xffc8\nF12           = 0xffc9\nF13           = 0xffca\nF14           = 0xffcb\nF15           = 0xffcc\nF16           = 0xffcd\nF17           = 0xffce\nF18           = 0xffcf\nF19           = 0xffd0\nF20           = 0xffd1\n\n# Modifiers\nLSHIFT        = 0xffe1\nRSHIFT        = 0xffe2\nLCTRL         = 0xffe3\nRCTRL         = 0xffe4\nCAPSLOCK      = 0xffe5\nLMETA         = 0xffe7\nRMETA         = 0xffe8\nLALT          = 0xffe9\nRALT          = 0xffea\nLWINDOWS      = 0xffeb\nRWINDOWS      = 0xffec\nLCOMMAND      = 0xffed\nRCOMMAND      = 0xffee\nLOPTION       = 0xffef\nROPTION       = 0xfff0\n\n# Latin-1\nSPACE         = 0x020\nEXCLAMATION   = 0x021\nDOUBLEQUOTE   = 0x022\nHASH          = 0x023\nPOUND         = 0x023  # synonym\nDOLLAR        = 0x024\nPERCENT       = 0x025\nAMPERSAND     = 0x026\nAPOSTROPHE    = 0x027\nPARENLEFT     = 0x028\nPARENRIGHT    = 0x029\nASTERISK      = 0x02a\nPLUS          = 0x02b\nCOMMA         = 0x02c\nMINUS         = 0x02d\nPERIOD        = 0x02e\nSLASH         = 0x02f\n_0            = 0x030\n_1            = 0x031\n_2            = 0x032\n_3            = 0x033\n_4            = 0x034\n_5            = 0x035\n_6            = 0x036\n_7            = 0x037\n_8            = 0x038\n_9            = 0x039\nCOLON         = 0x03a\nSEMICOLON     = 0x03b\nLESS          = 0x03c\nEQUAL         = 0x03d\nGREATER       = 0x03e\nQUESTION      = 0x03f\nAT            = 0x040\nBRACKETLEFT   = 0x05b\nBACKSLASH     = 0x05c\nBRACKETRIGHT  = 0x05d\nASCIICIRCUM   = 0x05e\nUNDERSCORE    = 0x05f\nGRAVE         = 0x060\nQUOTELEFT     = 0x060\nA             = 0x061\nB             = 0x062\nC             = 0x063\nD             = 0x064\nE             = 0x065\nF             = 0x066\nG             = 0x067\nH             = 0x068\nI             = 0x069\nJ             = 0x06a\nK             = 0x06b\nL             = 0x06c\nM             = 0x06d\nN             = 0x06e\nO             = 0x06f\nP             = 0x070\nQ             = 0x071\nR             = 0x072\nS             = 0x073\nT             = 0x074\nU             = 0x075\nV             = 0x076\nW             = 0x077\nX             = 0x078\nY             = 0x079\nZ             = 0x07a\nBRACELEFT     = 0x07b\nBAR           = 0x07c\nBRACERIGHT    = 0x07d\nASCIITILDE    = 0x07e\n\n_key_names = {}\n_motion_names = {}\nfor _name, _value in locals().copy().items():\n    if _name[:2] != '__' and _name.upper() == _name and \\\n       not _name.startswith('MOD_'):\n        if _name.startswith('MOTION_'):\n            _motion_names[_value] = _name\n        else:\n            _key_names[_value] = _name\n"
  },
  {
    "path": "universe/envs/vnc_core_env/translator.py",
    "content": "from universe import spaces\nfrom universe.envs.vnc_core_env import key\nimport logging\n\nlogger = logging.getLogger(__name__)\n\n\nclass AtariKeyState(object):\n    \"\"\"\n    Converts from VNCEvents to an Atari-v0 action index\n\n    Since spaces.KeyEvent only give you a diff of a keyboard, we need to persist the total state of the keyboard to\n    convert from VNCEvents to an action index\n    \"\"\"\n    def __init__(self, env):\n        self._translator = AtariTranslator(env)\n        self._down_keysyms = set()  # Assumes that your env starts with no keys pressed down\n\n    def apply_vnc_actions(self, vnc_actions):\n        \"\"\"\n        Play a list of vnc_actions forward over the current keysyms state\n\n        NOTE: Since we are squashing a set of diffs into a single keyboard state, some information may be lost.\n        For example if the Z key is down, then we receive [(Z-up), (Z-down)], the output will not reflect any change in Z\n        You can make each frame shorter to offset this effect.\n        \"\"\"\n        for event in vnc_actions:\n            if isinstance(event, spaces.KeyEvent):\n                if event.down:\n                    self._down_keysyms.add(event.key)\n                else:\n                    self._down_keysyms.discard(event.key)\n\n        logger.debug(\"AtariKeyState._down_keysyms: {}\".format(self._down_keysyms))\n\n    def to_keysyms(self):\n        \"\"\"Returns the current state as keysyms\"\"\"\n        return list(self._down_keysyms)\n\n    def to_index(self):\n        \"\"\"Returns the current state as an index\"\"\"\n        return self._translator.keysyms_to_index(self.to_keysyms())\n\n\nclass AtariTranslator(object):\n    \"\"\"Translates Atari actions to and from various formats\"\"\"\n    _all_keysyms = [key.UP, key.DOWN, key.LEFT, key.RIGHT, key.Z]\n\n    def __init__(self, env):\n        # e.g. {0: 'NOOP', 1: 'FIRE', 2: 'RIGHT', 3: 'LEFT', 4: 'RIGHTFIRE', 5: 'LEFTFIRE'}\n        self._index_to_name_ = {}\n        # e.g. {'RIGHT': 2, 'FIRE': 1, 'RIGHTFIRE': 4, 'LEFTFIRE': 5, 'NOOP': 0, 'LEFT': 3}\n        self._name_to_index_ = {}\n\n        for i, meaning in enumerate(env.unwrapped.get_action_meanings()):\n            self._name_to_index_[meaning] = i\n            self._index_to_name_[i] = meaning\n\n    def keysyms_to_vnc_actions(self, keysyms):\n        actions = []\n        keysyms = set(keysyms)\n        for keysym in self._all_keysyms:\n            down = keysym in keysyms\n            actions.append(spaces.KeyEvent(keysym, down=down))\n        return actions\n\n    def keysyms_to_index(self, keysyms):\n        name = self._keysyms_to_name(keysyms)\n        return self._name_to_index(name)\n\n    def index_to_keysyms(self, i):\n        name = self._index_to_name(i)\n        keysyms = []\n        if 'UP' in name:\n            keysyms.append(key.UP)\n        if 'DOWN' in name:\n            keysyms.append(key.DOWN)\n        if 'LEFT' in name:\n            keysyms.append(key.LEFT)\n        if 'RIGHT' in name:\n            keysyms.append(key.RIGHT)\n        if 'FIRE' in name:\n            keysyms.append(key.Z)\n        return keysyms\n\n    def _name_to_index(self, name):\n        return self._name_to_index_.get(name, 0)\n\n    def _index_to_name(self, i):\n        return self._index_to_name_[i]\n\n    def _keysyms_to_name(self, keysyms):\n        keys = ''\n        if key.UP in keysyms:\n            keys += 'UP'\n        if key.DOWN in keysyms:\n            keys += 'DOWN'\n        if key.LEFT in keysyms:\n            keys += 'LEFT'\n        if key.RIGHT in keysyms:\n            keys += 'RIGHT'\n        if key.Z in keysyms:\n            keys += 'FIRE'\n        return keys\n\nclass CartPoleTranslator(object):\n    def __init__(self, env):\n        pass\n\n    def keysyms_to_vnc_actions(self, keysyms):\n        down = key.LEFT in keysyms\n        return [spaces.KeyEvent(key.LEFT, down=down)]\n\n    def keysyms_to_index(self, keys):\n        if key.LEFT in keys:\n            return 0\n        else:\n            return 1\n\n    def index_to_keysyms(self, i):\n        if i == 0:\n            return [key.LEFT]\n        else:\n            return []\n"
  },
  {
    "path": "universe/envs/vnc_core_env/vnc_core_env.py",
    "content": "import logging\nimport time\n\nimport gym\nfrom universe import spaces\nfrom universe.envs import vnc_env\n\nlogger = logging.getLogger(__name__)\n\nclass GymCoreEnv(vnc_env.VNCEnv):\n    def __init__(self, gym_core_id, fps=60):\n        super(GymCoreEnv, self).__init__()\n\n        self.metadata = dict(self.metadata)\n        self.metadata['video.frames_per_second'] = fps\n\n        self.gym_core_id = gym_core_id\n        self._seed_value = None\n\n        self.vnc_pixels = True\n\nclass GymCoreSyncEnv(GymCoreEnv):\n    \"\"\"A synchronized version of the core envs. Its semantics should match\n    that of the core envs. (By default, observations are pixels from\n    the VNC session, but it also supports receiving the normal Gym\n    observations over the rewarder socket.)\n\n    Provided primarily for testing and debugging.\n    \"\"\"\n\n    def __init__(self, gym_core_id, fps=60, vnc_pixels=True):\n        super(GymCoreSyncEnv, self).__init__(gym_core_id, fps=fps)\n        # Metadata has already been cloned\n        self.metadata['semantics.async'] = False\n\n        self.gym_core_id = gym_core_id\n        self.vnc_pixels = vnc_pixels\n\n        if not vnc_pixels:\n            self._core_env = gym.spec(gym_core_id).make()\n        else:\n            self._core_env = None\n\n    def _flip_past(self, when_n):\n        info_n = [{} for i in range(self.n)]\n        while True:\n            observation_n, obs_info_n = self.vnc_session.flip()\n            metadata_n = self.diagnostics.extract_metadata(observation_n)\n\n            # Save the update count\n            self._propagate_obs_info(info_n, obs_info_n)\n\n            # All remote times, so no clock skew adjustments needed\n            invalid = []\n            for i, (metadata, when) in enumerate(zip(metadata_n, when_n)):\n                delta = when - metadata.get('now', 0)\n                if delta > 0:\n                    invalid.append((i, delta))\n            if not invalid:\n                break\n            else:\n                tick = 1./self.metadata['video.frames_per_second']\n                logger.info('Waiting %sms for the following observations to catch up: %s', int(1000*tick), invalid)\n                time.sleep(tick)\n        return observation_n, info_n\n\n    def _reset(self):\n        assert self.rewarder_session\n\n        result = self.rewarder_session.reset(\n            seed=self._seed_value,\n        )\n        # Clear seed value so we don't double-send it\n        self._seed_value = None\n\n        # Wait until all the observations have passed the reset_time\n        remote_reset_time = [response['headers']['sent_at'] for _, _, response in result]\n        observation_n, _ = self._flip_past(remote_reset_time)\n\n        # Double check that our reward queue is empty\n        assert all(c == 0 for c in self.rewarder_session.rewards_count())\n\n        return self._observation(observation_n)\n\n    def _observation(self, observation_n):\n        if self.vnc_pixels:\n            return observation_n\n        else:\n            observation_n = self.rewarder_session.pop_observation()\n            assert all(observation is not None for observation in observation_n), 'At least one missing observation: {}'.format(observation_n)\n            return self._core_env.observation_space.from_jsonable(observation_n)\n\n    def _step(self, action_n):\n        # Add C keypress in order to \"commit\" the action, as\n        # interpreted by the remote.\n        action_n = [action + [\n            spaces.KeyEvent.by_name('c', down=True),\n            spaces.KeyEvent.by_name('c', down=False)\n        ] for action in action_n]\n        # Submit directly to VNC session, without popping rewards\n        logger.debug('Submitting actions: %s', action_n)\n        action_n = self._compile_actions(action_n)\n        _, obs_info_n = self.vnc_session.step(action_n)\n        # Wait until the actions have actually happened\n        self.rewarder_session.wait(timeout=5)\n\n        # TODO: this is now present in the info messages; need to\n        # update the implementation.\n        when_n = [reward_buffer.info['reward_buffer.remote_time'] for reward_buffer in self.rewarder_session.reward_buffers]\n        observation_n, obs_info_n = self._flip_past(when_n)\n\n        reward_n, reward_time_n, done_n, info_n = self.rewarder_session.pop()\n        self._propagate_obs_info(info_n, obs_info_n)\n\n        # Warn if we detect multiple rewards\n        if any(info['stats.reward.count'] != 1 for info in info_n):\n            # Arrived but there was a bug\n            logger.warn('Likely bug: should have received 1 reward for every env, but instead received %s. Current return: observation=%s reward=%s done=%s info=%s', [info['stats.reward.count'] for info in info_n], observation_n, reward_n, done_n, info_n)\n\n        return self._observation(observation_n), reward_n, done_n, {'n': info_n}\n"
  },
  {
    "path": "universe/envs/vnc_env.py",
    "content": "import getpass\nimport logging\nimport os\nimport random\nimport uuid\n\nimport universe\nfrom gym.utils import reraise\nfrom universe import error, pyprofile, rewarder, spaces, twisty, vectorized, vncdriver\nfrom universe import remotes as remotes_module\nfrom universe.envs import diagnostics\nfrom universe.runtimes import registration\nfrom universe.vncdriver import libvnc_session\n\n# The Go driver is the most supported one. So long as the Go driver\n# turns out to be easy to install, we'll continue forcing the Go\n# driver here.\n# noinspection PyUnresolvedReferences\nimport go_vncdriver\n\nlogger = logging.getLogger(__name__)\nextra_logger = logging.getLogger('universe.extra.'+__name__)\n\nif os.environ.get('UNIVERSE_VNCDRIVER', None) == 'go':\n    # Importing the Go driver early is desirable, so that people get\n    # errors if it's not present. Also sometimes if go_vncdriver is\n    # loaded after TensorFlow it will crash.\n    import go_vncdriver\n\ndef default_client_id():\n    return '{}-{}'.format(uuid.uuid4(), getpass.getuser())\n\ndef rewarder_session(which):\n    if which is None:\n        which = rewarder.RewarderSession\n\n    if isinstance(which, type):\n        return which\n    else:\n        raise error.Error('Invalid RewarderSession driver: {!r}'.format(which))\n\ndef go_vncdriver():\n    import go_vncdriver\n    return go_vncdriver.VNCSession\n\ndef py_vncdriver():\n    return vncdriver.VNCSession\n\ndef libvnc_vncdriver():\n    return libvnc_session.LibVNCSession\n\ndef vnc_session(which=None):\n    # Short circuit so long as we're forcing the Go driver. Other code\n    # left behind for the future if we need to support the other\n    # drivers again.\n    if isinstance(which, type):\n        # Used in the tests to pass a custom VNC driver\n        return which\n\n    logger.info('Using the golang VNC implementation')\n    return go_vncdriver()\n\n    if which is None:\n        which = os.environ.get('UNIVERSE_VNCDRIVER')\n\n    if isinstance(which, type):\n        return which\n    if which == 'go':\n        logger.info('Using the golang VNC implementation')\n        return go_vncdriver()\n    elif which == 'py':\n        logger.info('Using the Python VNC implementation')\n        return py_vncdriver()\n    elif which == 'libvnc':\n        logger.info('Using the libvnc VNC implementation')\n        return libvnc_vncdriver()\n    elif which is None:\n        try:\n            go = go_vncdriver()\n            logger.debug('Using golang VNC implementation')\n            return go\n        except ImportError as e:\n            logger.info(\"Go driver failed to import: {}\".format(e))\n            logger.info(\"Using pure Python vncdriver implementation. Run 'pip install go-vncdriver' to install the more performant Go implementation. Optionally set the environment variable UNIVERSE_VNCDRIVER='go' to force its use.\")\n            return py_vncdriver()\n    else:\n        raise error.Error('Invalid VNCSession driver: {!r}'.format(which))\n\ndef build_observation_n(visual_observation_n, info_n):\n    observation_n = []\n    for visual, info in zip(visual_observation_n, info_n):\n        text = info.pop('env.text', [])\n        obs = {\n            'vision': visual,\n            'text': text,\n        }\n        if 'env.generic' in info:\n            obs['generic'] = info.pop('env.generic')\n        observation_n.append(obs)\n    return observation_n\n\nclass VNCEnv(vectorized.Env):\n    metadata = {\n        'render.modes': ['human'], # we wrap with a Render which can render to rgb_array\n        'semantics.async': True,\n        'semantics.autoreset': True,\n        'video.frames_per_second' : 60,\n        'runtime.vectorized': True,\n        'configure.required': True,\n    }\n\n    def __init__(self, fps=None, probe_key=None):\n        self.metadata = dict(self.metadata)\n        if fps is not None:\n            self.metadata['video.frames_per_second'] = fps\n\n        self._started = False\n\n        self.observation_space = spaces.VNCObservationSpace()\n        self.action_space = spaces.VNCActionSpace()\n\n        self._seed_value = None\n        self._remotes_manager = None\n\n        self._probe_key = probe_key or 0xbeef1\n\n        self.vnc_session = None\n        self.rewarder_session = None\n\n        self._send_actions_over_websockets = False\n        self._skip_network_calibration = False\n\n\n    def _seed(self, seed):\n        self._seed_value = seed\n        return [seed]\n\n    def configure(self, remotes=None,\n                  client_id=None,\n                  start_timeout=None, docker_image=None,\n                  ignore_clock_skew=False, disable_action_probes=False,\n                  vnc_driver=None, vnc_kwargs=None,\n                  rewarder_driver=None,\n                  replace_on_crash=False, allocate_sync=True,\n                  observer=False, api_key=None,\n                  record=False,\n                  sample_env_ids=None,\n    ):\n        \"\"\"Universe method to configure the environment.\n\n        Args:\n\n          ignore_clock_skew (bool): Assume remotes are on the same machine as us,\n            for the purposes of diagnostics measurement.\n\n            If true, we skip measuring the clock skew over the network,\n            and skip generating diagnostics which rely on it.\n\n            True when used by the rewarder to measure latency between\n            the VNC frame and its calculation of reward for that\n            frame.  In this case we share a common clock with the env\n            generating the VNC frame, so we don't need to send/receive\n            probes.  Clock skew is zero in this case.\n\n            False when remotes are potentially different machines\n            (such as an agent, or a demonstrator), and we will be\n            sending probe keys and measuring network ping rountrip\n            times to calculate clock skew.\n        \"\"\"\n        if self._started:\n            raise error.Error('{} has already been started; cannot change configuration now.'.format(self))\n\n        universe.configure_logging()\n\n        twisty.start_once()\n\n        if self.spec is not None:\n            runtime = registration.runtime_spec(self.spec.tags['runtime'])\n            # Let the user manually set the docker_image version\n            if docker_image:\n                # TODO: don't support this option?\n                runtime.image = docker_image\n        else:\n            runtime = None\n\n        if remotes is None:\n            remotes = os.environ.get('GYM_VNC_REMOTES', '1')\n\n        if client_id is None:\n            client_id = default_client_id()\n\n        if vnc_kwargs is None:\n            vnc_kwargs = {}\n\n        self.remote_manager, self.n = remotes_module.build(\n            client_id=client_id,\n            remotes=remotes, runtime=runtime, start_timeout=start_timeout,\n            api_key=api_key,\n            use_recorder_ports=record,\n        )\n        self.connection_names = [None] * self.n\n        self.connection_labels = [None] * self.n\n        self.crashed = {}\n\n        self.allow_reconnect = replace_on_crash and self.remote_manager.supports_reconnect\n        if self.remote_manager.connect_vnc:\n            cls = vnc_session(vnc_driver)\n            vnc_kwargs.setdefault('start_timeout', self.remote_manager.start_timeout)\n            if runtime == 'gym-core':\n                vnc_kwargs.setdefault('encoding', 'zrle')\n            else:\n                vnc_kwargs.setdefault('encoding', 'tight')\n                vnc_kwargs.setdefault('fine_quality_level', 50)\n                vnc_kwargs.setdefault('subsample_level', 2)\n            # Filter out None values, since some drivers may not handle them correctly\n            vnc_kwargs = {k: v for k, v in vnc_kwargs.items() if v is not None}\n            logger.info('Using VNCSession arguments: %s. (Customize by running \"env.configure(vnc_kwargs={...})\"', vnc_kwargs)\n            self.vnc_kwargs = vnc_kwargs\n            self.vnc_session = cls()\n        else:\n            self.vnc_session = None\n\n        self._observer = observer\n        if self.remote_manager.connect_rewarder:\n            cls = rewarder_session(rewarder_driver)\n            self.rewarder_session = cls()\n        else:\n            self.rewarder_session = None\n\n        if ignore_clock_skew:\n            logger.info('Printed stats will ignore clock skew. (This usually makes sense only when the environment and agent are on the same machine.)')\n\n        if self.rewarder_session or ignore_clock_skew:\n            # Don't need rewarder session if we're ignoring clock skew\n            if self.spec is not None:\n                metadata_encoding = self.spec.tags.get('metadata_encoding')\n            else:\n                metadata_encoding = None\n            self.diagnostics = diagnostics.Diagnostics(self.n, self._probe_key, ignore_clock_skew, metadata_encoding=metadata_encoding, disable_action_probes=disable_action_probes)\n        else:\n            self.diagnostics = None\n\n        self._sample_env_ids = sample_env_ids\n\n        self._reset_mask()\n        self._started = True\n\n        self.remote_manager.allocate([str(i) for i in range(self.n)], initial=True)\n        if allocate_sync:\n            # Block until we've fulfilled n environments\n            self._handle_connect(n=self.n)\n        else:\n            # Handle any backends which synchronously fufill their\n            # allocation.\n            self._handle_connect()\n\n    def connect(self, i, name, vnc_address, rewarder_address, vnc_password=None, rewarder_password=None):\n        logger.info('[%s] Connecting to environment: vnc://%s password=%s. If desired, you can manually connect a VNC viewer, such as TurboVNC. Most environments provide a convenient in-browser VNC client: http://%s/viewer/?password=%s', name, vnc_address, vnc_password, rewarder_address, vnc_password)\n\n        extra_logger.info('[%s] Connecting to environment details: vnc_address=%s vnc_password=%s rewarder_address=%s rewarder_password=%s', name, vnc_address, vnc_password, rewarder_address, rewarder_password)\n        self.connection_names[i] = name\n        self.connection_labels[i] = '{}:{}'.format(name, vnc_address)\n        if self.vnc_session is not None:\n            kwargs = {\n                'name': name,\n                'address': vnc_address,\n                'password': vnc_password,\n            }\n            kwargs.update(self.vnc_kwargs)\n\n            try:\n                self.vnc_session.connect(**kwargs)\n            except TypeError as e:\n                reraise(suffix=\"(HINT: this error was while passing arguments to the VNCSession driver: {})\".format(kwargs))\n\n            # TODO: name becomes index:pod_id\n            # TODO: never log index, just log name\n\n        if self.rewarder_session is not None:\n            if self.spec is not None:\n                env_id = self.spec.id\n            else:\n                env_id = None\n\n            if self._seed_value is not None:\n                # Once we use a seed, we clear it so we never\n                # accidentally reuse the seed. Seeds are an advanced\n                # feature and aren't supported by most envs in any\n                # case.\n                seed = self._seed_value[i]\n                self._seed_value[i] = None\n            else:\n                seed = None\n\n            assert rewarder_password, \"Missing rewarder password: {}\".format(rewarder_password)\n            network = self.rewarder_session.connect(\n                name=name, address=rewarder_address,\n                seed=seed, env_id=env_id,\n                fps=self.metadata['video.frames_per_second'],\n                password=rewarder_password,\n                label=self.connection_labels[i],\n                start_timeout=self.remote_manager.start_timeout,\n                observer=self._observer,\n                skip_network_calibration=self._skip_network_calibration\n            )\n        else:\n            network = None\n\n        if self.diagnostics is not None:\n            self.diagnostics.connect(i, network, label=name)\n        self.crashed.pop(i, None)\n\n    def _close(self, i=None):\n        if i is not None:\n            name = self.connection_names[i]\n            if self.rewarder_session:\n                self.rewarder_session.close(name)\n            if self.vnc_session:\n                self.vnc_session.close(name)\n            if self.diagnostics:\n                self.diagnostics.close(i)\n            self.mask.close(i)\n            self.connection_names[i] = None\n            self.connection_labels[i] = None\n        else:\n            if hasattr(self, 'rewarder_session') and self.rewarder_session:\n                self.rewarder_session.close()\n            if hasattr(self, 'vnc_session') and self.vnc_session:\n                self.vnc_session.close()\n            if hasattr(self, 'diagnostics') and self.diagnostics:\n                self.diagnostics.close()\n            if hasattr(self, 'remotes_manager') and self._remotes_manager:\n                self._remotes_manager.close()\n\n    def _reset(self):\n        self._handle_connect()\n\n        if self.rewarder_session:\n            if self._sample_env_ids:\n                env_id = random.choice(self._sample_env_ids)\n                logger.info(\"Randomly sampled env_id={}\".format(env_id))\n            else:\n                env_id = None\n            self.rewarder_session.reset(env_id=env_id)\n        else:\n            logger.info(\"No rewarder session exists, so cannot send a reset via the rewarder channel\")\n        self._reset_mask()\n        return [None] * self.n\n\n    def _reset_mask(self):\n        self.mask = Mask(self.connection_labels, initially_masked=bool(self.rewarder_session))\n\n    def _pop_rewarder_session(self, peek_d):\n        with pyprofile.push('vnc_env.VNCEnv.rewarder_session.pop'):\n            reward_d, done_d, info_d, err_d = self.rewarder_session.pop(peek_d=peek_d)\n\n        reward_n = []\n        done_n = []\n        info_n = []\n        err_n = []\n        for name in self.connection_names:\n            reward_n.append(reward_d.get(name, 0))\n            done_n.append(done_d.get(name, False))\n            info_n.append(info_d.get(name, {'env_status.disconnected': True}))\n            err_n.append(err_d.get(name))\n        return reward_n, done_n, info_n, err_n\n\n    def _step_vnc_session(self, compiled_d):\n        if self._send_actions_over_websockets:\n            self.rewarder_session.send_action(compiled_d, self.spec.id)\n            vnc_action_d = {}\n        else:\n            vnc_action_d = compiled_d\n\n        with pyprofile.push('vnc_env.VNCEnv.vnc_session.step'):\n            observation_d, info_d, err_d = self.vnc_session.step(vnc_action_d)\n\n        observation_n = []\n        info_n = []\n        err_n = []\n        for name in self.connection_names:\n            observation_n.append(observation_d.get(name))\n            info_n.append(info_d.get(name))\n            err_n.append(err_d.get(name))\n\n        return observation_n, info_n, err_n\n\n    def _compile_actions(self, action_n):\n        compiled_n = []\n        peek_d = {}\n        try:\n            for i, action in enumerate(action_n):\n                compiled = []\n                compiled_n.append(compiled)\n                for event in action:\n                    # Handle any special control actions\n                    if event == spaces.PeekReward:\n                        name = self.connection_names[i]\n                        peek_d[name] = True\n                        continue\n\n                    # Do a generic compile\n                    compiled.append(compile_action(event))\n        except Exception as e:\n            raise error.Error('Could not compile actions. Original error: {} ({}). action_n={}'.format(e, type(e), action_n))\n        else:\n            return compiled_n, peek_d\n\n    def _action_d(self, action_n):\n        action_d = {}\n        for i, action in enumerate(action_n):\n            action_d[self.connection_names[i]] = action\n        return action_d\n\n    def _step(self, action_n):\n        self._handle_connect()\n\n        # Compile actions to something more palatable by drivers\n        # written in other language.\n        action_n, peek_d = self._compile_actions(action_n)\n\n        # We pop from the rewarder session first since we need to\n        # determine if any of the current VNC actions need to be\n        # masked. (If the environment is resetting, we should\n        # definitely not send it any actions.)\n        #\n        # It's a bit counterintuitive to check for rewards first,\n        # since we haven't submitted the actions yet, but keep in mind\n        # that everything here is asynchronous!\n        if self.rewarder_session:\n            reward_n, done_n, info_n, err_n = self._pop_rewarder_session(peek_d)\n        else:\n            reward_n = done_n = [None] * self.n\n            info_n = [{} for _ in range(self.n)]\n            err_n = [None] * self.n\n\n        action_mask = observation_mask = self.mask.maintain_mask(done_n, info_n)\n\n        # Drop any actions to resetting environments.\n        #\n        # We pass the mask to add_probe so it doesn't try to schedule\n        # probes which are potentially harmful and will just time out\n        # anyway.\n        self.mask.apply_to_actions(action_n, info_n, action_mask)\n        # Send our actions and return the current framebuffer\n        if self.vnc_session:\n            if self.diagnostics:\n                self.diagnostics.clear_probes_when_done(done_n)\n                self.diagnostics.add_probe(action_n, action_mask)\n            action_d = self._action_d(action_n)\n\n            visual_observation_n, obs_info_n, vnc_err_n = self._step_vnc_session(action_d)\n            # Merge in any keys from the observation\n            self._propagate_obs_info(info_n, obs_info_n)\n        else:\n            visual_observation_n = [None] * self.n\n            vnc_err_n = [None] * self.n\n\n        observation_n = build_observation_n(visual_observation_n, info_n)\n        self.mask.apply_to_return(observation_n, reward_n, done_n, info_n, observation_mask)\n\n        self._handle_initial_n(observation_n, reward_n)\n        self._handle_err_n(err_n, vnc_err_n, info_n, observation_n, reward_n, done_n)\n        self._handle_crashed_n(info_n)\n\n        return observation_n, reward_n, done_n, {'n': info_n}\n\n    def _handle_initial_n(self, observation_n, reward_n):\n        if self.rewarder_session is None:\n            return\n\n        for i, reward in enumerate(reward_n):\n            if reward is None:\n                # Index hasn't come up yet, so ensure the observation\n                # is blanked out.\n                observation_n[i] = None\n\n    def _handle_err_n(self, err_n, vnc_err_n, info_n, observation_n=None, reward_n=None, done_n=None):\n        # Propogate any errors upwards.\n        for i, (err, vnc_err) in enumerate(zip(err_n, vnc_err_n)):\n            if err is None and vnc_err is None:\n                # All's well at this index.\n                continue\n\n            if observation_n is not None:\n                observation_n[i] = None\n                done_n[i] = True\n\n            # Propagate the error\n            if err is not None and vnc_err is not None:\n                # Both the rewarder and vnc failed at the same\n                # time. What are the odds?\n                info_n[i]['error'] = 'Both VNC and rewarder sessions failed: {}; {}'.format(vnc_err, err)\n            elif err is not None:\n                info_n[i]['error'] = 'Rewarder session failed: {}'.format(err)\n            else:\n                info_n[i]['error'] = 'VNC session failed: {}'.format(vnc_err)\n\n            extra_logger.info('[%s] %s', self.connection_names[i], info_n[i]['error'])\n\n            if self.allow_reconnect:\n                logger.info('[%s] Making a call to the allocator to replace crashed index: %s', self.connection_names[i], info_n[i]['error'])\n                self.remote_manager.allocate([str(i)])\n\n            self.crashed[i] = self.connection_names[i]\n            self._close(i)\n\n    def _handle_connect(self, n=None):\n        # Connect to any environments which are ready\n        for remote in self.remote_manager.pop(n=n):\n            if remote.name is not None:\n                name = '{}:{}'.format(remote.handle, remote.name)\n            else:\n                name = remote.handle\n\n            self.connect(\n                int(remote.handle), name=name,\n                vnc_address=remote.vnc_address, vnc_password=remote.vnc_password,\n                rewarder_address=remote.rewarder_address, rewarder_password=remote.rewarder_password)\n\n    def _handle_crashed_n(self, info_n):\n        # for i in self.crashed:\n        #     info_n[i]['env_status.crashed'] = True\n\n        if self.allow_reconnect:\n            return\n\n        if len(self.crashed) > 0:\n            errors = {}\n            for i, info in enumerate(info_n):\n                if 'error' in info:\n                    errors[self.crashed[i]] = info['error']\n\n            if len(errors) == 0:\n                raise error.Error('{}/{} environments have crashed. No error key in info_n: {}'.format(len(self.crashed), self.n, info_n))\n            else:\n                raise error.Error('{}/{} environments have crashed! Most recent error: {}'.format(len(self.crashed), self.n, errors))\n\n    def _propagate_obs_info(self, info_n, obs_info_n):\n        for obs_info, info in zip(obs_info_n, info_n):\n            # obs_info keys take precedence over info keys\n            if obs_info is not None:\n                info.update(obs_info)\n\n    def _render(self, mode='human', close=False):\n        if close:\n            # render(close) is not currently supported by the Go VNCSession\n            return\n\n        if mode is 'human' and self.vnc_session is not None:\n            if self.connection_names[0]:\n                self.vnc_session.render(self.connection_names[0])\n\n    def __str__(self):\n        if self.spec:\n            return '<VNCEnv{}>'.format(self.spec.id)\n        else:\n            return 'VNCEnv'\n\n\nclass Mask(object):\n    \"\"\"Blocks the agent from interacting with the environment while the\n    environment is resetting.\n\n    On the boundaries:\n\n    - Mask will *drop* actions to environments which have just started\n      resetting (i.e. returning done=True in this iteration and have\n      env_state=resetting).\n\n    - Mask will *allow* actions to environments which have just\n      finished resetting (i.e. their env_state=running).\n\n    - Mask will *allow* rewards from environments which have just\n      started resetting (i.e. returning done=True in this iteration\n      and have env_state=resetting), but mask observations from them.\n\n    - Mask will *allow* observations from environments which have just\n      finished resetting (i.e. their env_state is running)\n    \"\"\"\n    def __init__(self, connection_labels, initially_masked=True):\n        self.connection_labels = connection_labels\n        self.n = len(connection_labels)\n\n        self.episode_ids = [None] * self.n\n        if initially_masked:\n            self.mask = [None] * self.n\n        else:\n            self.mask = [True] * self.n\n\n    def close(self, i):\n        self.mask[i] = None\n        self.episode_ids[i] = None\n\n    def maintain_mask(self, done_n, info_n):\n        for i, ok in enumerate(self.mask):\n            if info_n[i].get('peek'):\n                env_state = info_n[i].get('env_status.peek.env_state', 'resetting')\n                episode_id = info_n[i].get('env_status.peek.episode_id')\n\n                if info_n[i].get('env_status.episode_id') != episode_id:\n                    completed_episode_id = info_n[i].get('env_status.episode_id')\n                else:\n                    completed_episode_id = None\n            else:\n                env_state = info_n[i].get('env_status.env_state', 'resetting')\n                episode_id = info_n[i].get('env_status.episode_id')\n                completed_episode_id = info_n[i].get('env_status.complete.episode_id')\n\n            # Either:\n            # 1. The env is currently masked (not ok)\n            # 2. We have an active episode (self.episode_ids[i])\n            # 3. We didn't connect the rewarder (done_n[i] is None)\n            assert not ok or self.episode_ids[i] is not None or done_n[i] is None, \"ok={} episode_id={} i={}\".format(ok, episode_id, i)\n            if not ok and env_state == 'running':\n                extra_logger.info('[%s] Episode began: episode_id=%s env_state=%s', self.connection_labels[i], episode_id, env_state)\n                self.mask[i] = True\n                # this should change only for initial reset\n                self.episode_ids[i] = episode_id\n            elif ok and self.episode_ids[i] != episode_id and env_state == 'running':\n                extra_logger.info('[%s] Episode ended (and began, so not masking): episode_id=%s->%s env_state=%s', self.connection_labels[i], completed_episode_id, episode_id, env_state)\n                self.episode_ids[i] = episode_id\n            elif ok and self.episode_ids[i] != episode_id:\n                extra_logger.info('[%s] Episode ended: episode_id=%s->%s env_state=%s', self.connection_labels[i], completed_episode_id, episode_id, env_state)\n                self.mask[i] = False\n                self.episode_ids[i] = episode_id\n        return self.mask\n\n    def apply_to_actions(self, action_n, info_n, mask):\n        for i, ok in enumerate(mask):\n            if ok:\n                continue\n\n            action_n[i] = []\n            info_n[i]['mask.masked.action'] = True\n        return self.mask\n\n    def apply_to_return(self, observation_n, reward_n, done_n, info_n, observation_mask):\n        # Next, mask any environments which are resetting. We are\n        # guaranteed to get done=True messages prior to getting the\n        # v0.env.describe message telling us it's resetting, so the\n        # conservative route (block upon done=True, unblock upon\n        # v0.env.describe with env_state=running) locks us out of the\n        # maximum surface area of environment reset possible.\n        for i, ok in enumerate(observation_mask):\n            if ok:\n                continue\n\n            if len(observation_n[i]['text']) > 0 and ok is False:\n                logger.warn('[%s] WARNING: Masking text observation for environment %d: %r. This means we received text data before the environment finished resetting; the text observation has been lost. This is not expected and should be reported.', self.connection_labels[i], i, observation_n[i]['text'])\n\n            observation_n[i] = None\n            info_n[i]['mask.masked.observation'] = True\n\ndef compile_action(event):\n    if isinstance(event, tuple):\n        if event[0] == 'KeyEvent':\n            name, down = event[1:]\n            return spaces.KeyEvent.by_name(name, down=down).compile()\n        elif event[0] == 'PointerEvent':\n            x, y, buttonmask = event[1:]\n            return spaces.PointerEvent(x, y, buttonmask).compile()\n    else:\n        return event.compile()\n"
  },
  {
    "path": "universe/envs/vnc_flashgames.py",
    "content": "from universe.envs import vnc_env\n\nclass FlashgamesEnv(vnc_env.VNCEnv):\n     def __init__(self):\n        super(FlashgamesEnv, self).__init__()\n        self._probe_key = 0x60  # backtick `\n"
  },
  {
    "path": "universe/envs/vnc_gtav.py",
    "content": "from universe.envs import vnc_env\nfrom universe.spaces.joystick_action_space import JoystickActionSpace\n\n\nclass GTAVEnv(vnc_env.VNCEnv):\n    def __init__(self):\n        super(GTAVEnv, self).__init__()\n        self.action_space = JoystickActionSpace(axis_x=True, axis_z=True)\n        self._send_actions_over_websockets = True\n        self._skip_network_calibration = True\n\n"
  },
  {
    "path": "universe/envs/vnc_internet.py",
    "content": "from universe.envs import vnc_env\n\nclass InternetEnv(vnc_env.VNCEnv):\n     def __init__(self):\n        super(InternetEnv, self).__init__()\n        self._probe_key = 0x60  # backtick `\n"
  },
  {
    "path": "universe/envs/vnc_starcraft.py",
    "content": "import string\n\nfrom universe import spaces\nfrom universe.spaces import vnc_event, VNCActionSpace\nfrom universe.spaces.vnc_event import KeyEvent, PointerEvent\nfrom universe.envs import vnc_env\nfrom universe.vncdriver import constants\nimport logging\n\nlogger = logging.getLogger()\n\nSCREEN_DIM = (640, 480)\n\nclass StarCraftEnv(vnc_env.VNCEnv):\n    def __init__(self):\n        super(StarCraftEnv, self).__init__()\n        self.action_space = VNCActionSpace(\n            keys=['f2',  # Map positions\n                  'f3',  # Map positions\n                  'f4',  # Map positions\n                  'spacebar',\n                  'left',\n                  'up',\n                  'right',\n                  'down'],\n            screen_shape=SCREEN_DIM\n        )\n        self.safe_action_space = self.action_space\n\n    # def _step(self, action_n):\n    #     return super(StarCraftEnv, self)._step(\n    #         (StarCraftEventFilter.filter(a) for a in action_n))\n\n\n# class StarCraftEventFilter(object):\n#     \"\"\"\n#     We only allow keyboard inputs used by StarCraft:\n#     http://gamingweapons.com/image/steelseries/zboard-starcraft2-keyset/steelseries_zboard_starcraft2_keyset_02.jpg\n#     \"\"\"\n#     _x_offset = 5  # Centered\n#     _y_offset = 30  # Remove the chrome\n\n#     @classmethod\n#     def _safe_pointer_event(cls, event):\n#         \"\"\"Returns true if the click is in a place that will not break out of the box\"\"\"\n#         height = SCREEN_DIM[0]\n#         width = SCREEN_DIM[1]\n#         margin = 5  # Never allow clicking within 5 pixels of the edge of the screen\n\n#         unsafe_locations = [\n#             (event.y < cls._y_offset + margin),  # At the top, where menu chrome is\n#             (event.y > height + cls._y_offset - margin),  # Too far down\n#             (event.x < cls._x_offset + margin),  # Too far left\n#             (event.x > width + cls._x_offset - margin),  # Too far right\n#             (410 < event.x < 510) and (370 < event.y < 450),  # Where the menu button is\n#         ]\n#         unsafe = any(unsafe_locations)\n#         if unsafe:\n#             logger.warning('skipping unsafe pointer event')\n#         return not unsafe\n\n#     @classmethod\n#     def safe_event(cls, event):\n#         if isinstance(event, PointerEvent):\n#             return cls._safe_pointer_event(event)\n\n#     @classmethod\n#     def filter(cls, events):\n#         return filter(cls.safe_event, events)\n"
  },
  {
    "path": "universe/envs/vnc_wog.py",
    "content": "from universe.envs import vnc_env\nfrom universe.spaces import VNCActionSpace\n\n\nclass WorldOfGooEnv(vnc_env.VNCEnv):\n    def __init__(self):\n        super(WorldOfGooEnv, self).__init__()\n        # TODO: set action space screen shape to match\n        # HACK: empty keys list fails for some weird reason, give it an 'a'\n        self.action_space = VNCActionSpace(keys=['a'], buttonmasks=[1])\n"
  },
  {
    "path": "universe/error.py",
    "content": "import sys\n\nclass Error(Exception):\n    pass\n\nclass RPCError(Error):\n    pass\n\nclass ConnectionError(Error):\n    pass\n\nclass TimeoutError(Error):\n    pass\n\nclass AuthenticationError(Error):\n    pass\n"
  },
  {
    "path": "universe/kube/__init__.py",
    "content": "from universe.kube.discovery import discover, discover_batches\n"
  },
  {
    "path": "universe/kube/discovery.py",
    "content": "import json\nimport logging\nimport pipes\nimport subprocess\n\nclass Error(Exception):\n    pass\n\nlogger = logging.getLogger()\n\ndef pretty_command(command):\n    return ' '.join(pipes.quote(c) for c in command)\n\ndef log_command(command, prefix=''):\n    logger.info('%sExecuting: %s', prefix, pretty_command(command))\n\ndef check_call(command, *args, **kwargs):\n    log_command(command)\n    return subprocess.check_call(command, *args, **kwargs)\n\ndef popen(command, *args, **kwargs):\n    log_command(command)\n    return subprocess.Popen(command, *args, **kwargs)\n\ndef check_with_output(command, *args, **kwargs):\n    log_command(command)\n    proc = subprocess.Popen(command, *args, stdout=subprocess.PIPE, **kwargs)\n    stdout, _ = proc.communicate()\n    if proc.returncode != 0:\n        raise Error('Command {} returned non-zero exit status {}'.format(command, proc.returncode))\n    return stdout\n\ndef interpret_ready(pod):\n    # status:\n    # conditions:\n    # - lastProbeTime: null\n    #   lastTransitionTime: 2016-07-06T05:29:45Z\n    #   message: 'containers with unready status: [xdummy xvnc vnc-atari]'\n    #   reason: ContainersNotReady\n    #   status: \"False\"\n    #   type: Ready\n    if 'conditions' not in pod['status']:\n        return False\n\n    ready = [c for c in pod['status']['conditions'] if c['type'] == 'Ready']\n    if not ready:\n        return False\n\n    return ready[0]['status'] == 'True'\n\ndef interpret_ports(containers):\n    # TODO: clean up hack\n    try:\n        recorder = containers['vnc-recorder']\n    except KeyError:\n        pass\n    else:\n        spec = recorder['ports'][0]\n        assert spec['containerPort'] == 5899\n        return spec['hostPort'], None\n\n    app = [k for k in containers.keys() if k.startswith('vnc-')]\n    assert len(app) == 1\n    app = app[0]\n\n    port_mapping = {}\n    for spec in containers[app]['ports']:\n        port_mapping[spec['containerPort']] = spec['hostPort']\n    # vnc, rewarder\n    return port_mapping[5900], port_mapping.get(15900)\n\nclass VNCEnvDiscovery(object):\n    def __init__(self):\n        self.context = 'sci'\n        self.namespace = 'gym'\n        self.kubectl = ['kubectl', '--context', self.context, '--namespace', self.namespace]\n\n    def discover_batches(self):\n        pods = check_with_output(self.kubectl + ['get', 'pods', '-o', 'json', '-l', 'type=universe'])\n        pods = json.loads(pods)\n\n        batches = {}\n        for pod in pods['items']:\n            if 'deletionTimestamp' in pod['metadata']:\n                # Pod has been deleted!\n                continue\n\n            batch = pod['metadata']['labels']['batch']\n            if batch not in batches:\n                batches[batch] = {'count': 0}\n            batches[batch]['count'] += 1\n        return batches\n\n    def discover(self, batch, force_ready=False):\n        pods = check_with_output(self.kubectl + ['get', 'pods', '-o', 'json', '-l', 'type=universe', '-l', 'batch={}'.format(batch)])\n        pods = json.loads(pods)\n\n        if len(pods['items']) == 0:\n            raise Error('Incorrect batch id: {}'.format(batch))\n\n        remotes = []\n\n        for pod in pods['items']:\n            name = pod['metadata']['name']\n            containers = {}\n            for container in pod['spec']['containers']:\n                containers[container['name']] = container\n            vnc_port, rewarder_port = interpret_ports(containers)\n            node = pod['spec'].get('nodeName')\n\n            # Not scheduled on a node yet\n            if node is None:\n                if force_ready:\n                    raise Error('Not all pods ready: {} is not scheduled on a node yet'.format(name))\n                continue\n\n            address = '{}:{}'.format(node, vnc_port)\n            if rewarder_port is not None:\n                address += '+{}'.format(rewarder_port)\n            spec = {\n                'name': name,\n                'address': address,\n                'ready': interpret_ready(pod),\n            }\n            remotes.append(spec)\n        return remotes\n\nvnc_env_discovery = VNCEnvDiscovery()\ndiscover = vnc_env_discovery.discover\ndiscover_batches = vnc_env_discovery.discover_batches\n"
  },
  {
    "path": "universe/pyprofile/__init__.py",
    "content": "# A simple in-memory stats library\n#\n# Inspired by statsd: http://statsd.readthedocs.io/en/v3.1/types.html#gauges\nimport collections\nimport json\nimport logging\nimport numbers\nimport numpy as np\nimport os\nimport six\nimport threading\nimport time\n\nlogger = logging.getLogger(__name__)\n\nBYTES = 'bytes'\nSECONDS = 'seconds'\n\nclass Error(Exception):\n    pass\n\nclass ExponentialAverage(object):\n    def __init__(self, decay=0.1):\n        self.decay = decay\n        self.last_update = None\n        self.last_data_decay = None\n        self._avg = None\n\n    def add(self, data):\n        assert isinstance(data, numbers.Number)\n        if self.last_update is None:\n            self._avg = data\n            self.last_update = time.time()\n            self.last_data_decay = 1\n        else:\n            now = time.time()\n            delta = now - self.last_update\n            if delta < 0:\n                # Time is allowed to go a little backwards (NTP update, etc)\n                logger.warn(\"Backwards delta value: {}\".format(delta))\n                # Treat this entry as if it happened with 0 delta\n                delta = 0\n            if delta != 0:\n                self.last_data_decay = (1 - self.decay**delta) * 1/delta\n                self._avg = self.decay**delta * self._avg + self.last_data_decay * data\n            else:\n                # Don't divide by zero; just reuse the last delta. Should stack well\n                self._avg += self.last_data_decay * data\n            self.last_update = now\n\n    def avg(self):\n        return self._avg\n\nclass RunningVariance(object):\n    \"\"\" Implements Welford's algorithm for computing a running mean\n    and standard deviation as described at:\n        http://www.johndcook.com/standard_deviation.html\n    can take single values or iterables\n    Properties:\n        mean    - returns the mean\n        std     - returns the std\n        meanfull- returns the mean and std of the mean\n    Usage:\n        >>> foo = Welford()\n        >>> foo(range(100))\n        >>> foo\n        <Welford: 49.5 +- 29.0114919759>\n        >>> foo([1]*1000)\n        >>> foo\n        <Welford: 5.40909090909 +- 16.4437417146>\n        >>> foo.mean\n        5.409090909090906\n        >>> foo.std\n        16.44374171455467\n        >>> foo.meanfull\n        (5.409090909090906, 0.4957974674244838)\n    \"\"\"\n\n    def __init__(self):\n        self.k = 0\n        self.M = 0\n        self.S = 0\n\n    def add(self,x):\n        if x is None:\n            return\n        self.k += 1\n        newM = self.M + (x - self.M)*1./self.k\n        newS = self.S + (x - self.M)*(x - newM)\n        self.M, self.S = newM, newS\n\n    def mean(self):\n        return self.M\n    def meanfull(self):\n        return self.mean, self.std/np.sqrt(self.k)\n    def std(self):\n        if self.k==1:\n            return 0\n        return np.sqrt(self.S/(self.k-1))\n    def __repr__(self):\n        return \"<Welford: {} +- {}>\".format(self.mean, self.std)\n\ndef pretty(d, unit):\n    if unit is None:\n        return d\n    elif unit == BYTES:\n        return pretty_bytes(d)\n    elif unit == SECONDS:\n        return pretty_seconds(d)\n    else:\n        raise Error('No such unit: {}'.format(unit))\n\ndef pretty_bytes(b):\n    if b is None:\n        return None\n\n    assert isinstance(b, numbers.Number), \"Surprising type for data: {} ({!r})\".format(type(b), b)\n    if b > 1000 * 1000:\n        return '{:.0f}MB'.format(b/1000.0/1000.0)\n    elif b > 1000:\n        return '{:.0f}kB'.format(b/1000.0)\n    else:\n        return '{:.0f}B'.format(b)\n\ndef pretty_seconds(t):\n    a_t = abs(t)\n    if a_t < 0.001:\n        return '{:.2f}us'.format(1000*1000*t)\n    elif a_t < 1:\n        return '{:.2f}ms'.format(1000*t)\n    else:\n        return '{:.2f}s'.format(t)\n\ndef thread_id():\n    return threading.current_thread().ident\n\nclass StackProfile(object):\n    def __init__(self, profile):\n        self.profile = profile\n\n        self.stack_by_thread = {}\n        self.lock = threading.Lock()\n\n    def __enter__(self):\n        return self\n\n    def __exit__(self, type, value, tb):\n        self.pop()\n\n    def push(self, event):\n        stack = self._current_stack()\n        stack.append({\n            'name': event,\n            'start': time.time(),\n        })\n        return self\n\n    def pop(self):\n        stack = self._current_stack()\n        event = stack.pop()\n        name = event['name']\n        start = event['start']\n\n        with self.profile as txn:\n            delta = time.time() - start\n            txn.timing(name, delta)\n            # These are now subsumed by the timers key\n            # txn.incr(name + '.total_time', delta, unit=SECONDS)\n            # txn.incr(name + '.calls')\n\n    def _current_stack(self):\n        id = thread_id()\n\n        try:\n            stack = self.stack_by_thread[id]\n        except KeyError:\n            with self.lock:\n                # Only current thread should be adding to this entry anyway\n                assert id not in self.stack_by_thread\n                stack = self.stack_by_thread[id] = []\n        return stack\n\nclass Profile(object):\n    def __init__(self, print_frequency=None, print_filter=None):\n        if print_filter is None:\n            print_filter = lambda event: True\n\n        self.lock = threading.RLock()\n\n        self.print_frequency = print_frequency\n        self.last_export = None\n        self.export_hooks = [self._print_export]\n\n        self.print_filter = print_filter\n        self._in_txn = False\n\n        self.reset()\n\n    def reset(self):\n        self.timers = {}\n        self.counters = {}\n        self.gauges = {}\n\n    def add_export_hook(self, hook):\n        self.export_hooks.append(hook)\n\n    def __enter__(self):\n        self.lock.acquire()\n        self._in_txn = True\n        return self\n\n    def __exit__(self, type, value, tb):\n        self._in_txn = False\n        self._print_if_needed()\n        self.lock.release()\n\n    def timing(self, event, time):\n        assert isinstance(event, six.string_types)\n        # return\n        with self.lock:\n            if event not in self.timers:\n                self.timers[event] = {\n                    'total': 0,\n                    'calls': 0,\n                    'std': RunningVariance(),\n                }\n            self.timers[event]['total'] += time\n            self.timers[event]['calls'] += 1\n            self.timers[event]['std'].add(time)\n\n            self._print_if_needed()\n\n    def incr(self, event, amount=1, unit=None):\n        assert isinstance(event, six.string_types)\n        # return\n        with self.lock:\n            if event not in self.counters:\n                self.counters[event] = {\n                    'total': 0,\n                    'calls': 0,\n                    'rate': ExponentialAverage(),\n                    'unit': unit,\n                    'std': RunningVariance(),\n                }\n            self.counters[event]['total'] += amount\n            self.counters[event]['calls'] += 1\n            self.counters[event]['rate'].add(amount)\n            self.counters[event]['std'].add(amount)\n\n            self._print_if_needed()\n\n    def gauge(self, event, value, delta=False, unit=None):\n        assert isinstance(event, six.string_types)\n        with self.lock:\n            if event not in self.gauges:\n                self.gauges[event] = {\n                    'value': 0,\n                    'calls': 0,\n                    'unit': unit,\n                    'std': RunningVariance(),\n                }\n            if delta:\n                self.gauges[event]['value'] += value\n            else:\n                self.gauges[event]['value'] = value\n            self.gauges[event]['calls'] += 1\n            self.gauges[event]['std'].add(value)\n\n            self._print_if_needed()\n\n    def _print_if_needed(self):\n        \"\"\"Assumes you hold the lock\"\"\"\n        if self._in_txn or self.print_frequency is None:\n            return\n        elif self.last_export is not None and \\\n             self.last_export + self.print_frequency > time.time():\n            return\n\n        self.export()\n\n    def export(self, log=True, reset=True):\n        with self.lock:\n            if self.last_export is None:\n                self.last_export = time.time()\n            delta = time.time() - self.last_export\n            self.last_export = time.time()\n\n            timers = {}\n            for event, stat in self.timers.items():\n                timers[event] = {\n                    'mean': stat['std'].mean(),\n                    'std': stat['std'].std(),\n                    'calls': stat['calls'],\n                    'unit': 'seconds',\n                }\n\n            counters = {}\n            for counter, stat in self.counters.items():\n                counters[counter] = {\n                    'calls': stat['calls'],\n                    'std': stat['std'].std(),\n                    'mean': stat['std'].mean(),\n                    'unit': stat['unit'],\n                    'total': stat['total'],\n                    'rate': stat['rate'].avg(),\n                }\n\n            gauges = {}\n            for gauge, stat in self.gauges.items():\n                gauges[gauge] = {\n                    'value': stat['value'],\n                    'calls': stat['calls'],\n                    'std': stat['std'].std(),\n                    'mean': stat['std'].mean(),\n                    'unit': stat['unit'],\n                }\n\n            export = {\n                'timers': timers,\n                'counters': counters,\n                'gauges': gauges,\n                'metadata': {\n                    'period': delta,\n                }\n            }\n            if log:\n                for hook in self.export_hooks:\n                    hook(export)\n            if reset:\n                self.reset()\n            return export\n\n    def _print_export(self, export):\n        timers = {}\n        for event, stat in sorted(export['timers'].items()):\n            if not self.print_filter(event):\n                continue\n\n            timers[event] = {\n                'mean': pretty_seconds(stat['mean']),\n                'std': pretty_seconds(stat['std']),\n                'calls': stat['calls'],\n            }\n\n        counters = collections.OrderedDict({})\n        for counter, stat in sorted(export['counters'].items()):\n            if not self.print_filter(counter):\n                continue\n\n            unit = stat['unit']\n            counters[counter] = {\n                'calls': stat['calls'],\n                'std': pretty(stat['std'], unit),\n                'mean': pretty(stat['mean'], unit),\n            }\n\n        gauges = collections.OrderedDict({})\n        for gauge, stat in sorted(export['gauges'].items()):\n            if not self.print_filter(gauge):\n                continue\n\n            unit = stat['unit']\n            gauges[gauge] = {\n                'value': pretty(stat['value'], unit),\n                'calls': stat['calls'],\n                'std': pretty(stat['std'], unit),\n                'mean': pretty(stat['mean'], unit),\n            }\n\n        # A bit of a hack, but we want this time to be as inclusive as\n        # possible.\n        export['metadata']['export_time'] = time.time() - self.last_export\n\n        # We do the explicit OrderedDict and json.dumps to order\n        # keys. Maybe there's a better way?\n        logger.info('[pyprofile] period=%s timers=%s counters=%s gauges=%s (export_time=%s)',\n                    pretty_seconds(export['metadata']['period']),\n                    json.dumps(timers), json.dumps(counters), json.dumps(gauges),\n                    pretty_seconds(export['metadata']['export_time']),\n        )\n\nprint_frequency = os.environ.get('PYPROFILE_FREQUENCY')\nif print_frequency is not None:\n    print_frequency = float(print_frequency)\n\nprint_prefix = os.environ.get('PYPROFILE_PREFIX')\nif print_prefix is not None:\n    print_filter = lambda event: event.startswith(print_prefix)\nelse:\n    print_filter = None\n\nprofile = Profile(print_frequency=print_frequency, print_filter=print_filter)\nstack_profile = StackProfile(profile)\n\npush = stack_profile.push\npop = stack_profile.pop\nincr = profile.incr\ntiming = profile.timing\ngauge = profile.gauge\nexport = profile.export\n"
  },
  {
    "path": "universe/remotes/__init__.py",
    "content": "from universe.remotes.hardcoded_addresses import HardcodedAddresses\nfrom universe.remotes.allocator_remote import AllocatorManager\nfrom universe.remotes.docker_remote import DockerManager\nfrom universe.remotes.build import build\n"
  },
  {
    "path": "universe/remotes/allocator_remote.py",
    "content": "import json\nimport logging\nimport os\nimport re\nimport requests\nimport six\nimport six.moves.urllib.parse as urlparse\nimport threading\nimport time\n\nimport gym\nfrom gym import scoreboard\nfrom gym.utils import reraise\n\nfrom universe import error, utils\nfrom universe.remotes import remote\n\nif six.PY2:\n    import Queue as queue\nelse:\n    import queue\n\nlogger = logging.getLogger(__name__)\nextra_logger = logging.getLogger('universe.extra.'+__name__)\n\n# Using gym for this\n_api_key = 'tyytjgq3envte2j9yv2e-{}'.format(os.environ.get('OPENAI_USER', os.environ.get('USER')))\nallocator_base = 'http://allocator.sci.openai-tech.com'\n# gym_base_url = 'http://api.gym.sci.openai-tech.com'\n\nclass Stop(Exception):\n    pass\n\nclass RequestError(Exception):\n    def __init__(self, message, status_code=None):\n        super(RequestError, self).__init__(message)\n        self.message = message\n        if status_code is not None:\n            self.status_code = status_code\n\nclass FatalError(RequestError):\n    pass\n\nclass AllocatorManager(threading.Thread):\n    daemon = True\n\n    def __init__(self, client_id, base_url=allocator_base,\n                 address_type=None, start_timeout=None, api_key=None,\n                 runtime_id=None, params=None, placement=None,\n                 use_recorder_ports=False,\n    ):\n        super(AllocatorManager, self).__init__()\n        self.label = 'AllocatorManager'\n\n        self.supports_reconnect = True\n        self.connect_vnc = True\n        self.connect_rewarder = True\n\n        if address_type is None: address_type = 'public'\n        if address_type not in ['public', 'pod', 'private']:\n            raise error.Error('Bad address type specified: {}. Must be public, pod, or private.'.format(address_type))\n\n        self.client_id = client_id\n        self.address_type = address_type\n\n        if start_timeout is None:\n            start_timeout = 20 * 60\n        self.start_timeout = start_timeout\n        self.params = params\n        self.placement = placement\n        self.use_recorder_ports = use_recorder_ports\n\n#         if base_url is None:\n#             base_url = scoreboard.api_base\n#         if base_url is None:\n#             base_url = gym_base_url\n#         if api_key is None:\n#             api_key = scoreboard.api_key\n#         if api_key is None:\n#             raise gym.error.AuthenticationError(\"\"\"You must provide an OpenAI Gym API key.\n\n# (HINT: Set your API key using \"gym.scoreboard.api_key = ..\" or \"export OPENAI_GYM_API_KEY=...\"). You can find your API key in the OpenAI Gym web interface: https://gym.openai.com/settings/profile.\"\"\")\n\n        if api_key is None:\n            api_key = _api_key\n        self._requestor = AllocatorClient(self.label, api_key, base_url=base_url)\n        self.base_url = base_url\n\n        # These could be overridden on a per-allocation basis, if you\n        # want heterogeoneous envs. We don't support those currently\n        # in the higher layers, but this layer could support it\n        # easily.\n        self.runtime_id = runtime_id\n\n        self.pending = {}\n\n        self.error_buffer = utils.ErrorBuffer()\n        self.requests = queue.Queue()\n        self.ready = queue.Queue()\n\n        self._reconnect_history = {}\n        self._sleep = 1\n\n    @classmethod\n    def from_remotes(cls, client_id, remotes, runtime_id, runtime_tag, start_timeout, api_key, use_recorder_ports):\n        parsed = urlparse.urlparse(remotes)\n        if not (parsed.scheme == 'http' or parsed.scheme == 'https'):\n            raise error.Error('AllocatorManager must start with http:// or https://: {}'.format(remotes))\n\n        base_url = parsed.scheme + '://' + parsed.netloc\n        if parsed.path:\n            base_url += '/' + parsed.path\n        query = urlparse.parse_qs(parsed.query)\n\n        # Intercept url-encoded params (\"?n=2\" and similar)\n        params = {}\n        n = query.get('n', [1])[0] # not added to params, just returned later\n\n        cpu = query.get('cpu', [None])[0]\n        if cpu is not None:\n            cpu = float(cpu)\n            params['cpu'] = cpu\n\n        tag = query.get('tag', [None])[0]\n        if tag is not None:\n            params['tag'] = tag  # url-encoded \"?tag=\" gets precedence over runtimes.yml tag\n        else:\n            params['tag'] = runtime_tag\n\n        placement = query.get('address', ['public'])[0]\n\n        # anything else from the query other than the components processed above will get dropped on the floor\n\n        return cls(client_id=client_id, runtime_id=runtime_id, base_url=base_url, start_timeout=start_timeout, params=params, placement=placement, api_key=api_key, use_recorder_ports=use_recorder_ports), int(n)\n\n    def pop(self, n=None):\n        \"\"\"Call from main thread. Returns the list of newly-available (handle, env) pairs.\"\"\"\n        self.error_buffer.check()\n\n        envs = []\n\n        if n is None:\n            while True:\n                try:\n                    envs += self.ready.get(block=False)\n                except queue.Empty:\n                    break\n        else:\n            sync_timeout = 10 * 60\n            start = time.time()\n\n            wait_time = 1\n            while len(envs) < n:\n                try:\n                    extra_logger.info('[%s] Waiting for %d envs, currently at %d, sleeping for %d', self.label, n, len(envs), wait_time)\n                    envs += self.ready.get(timeout=wait_time)\n                except queue.Empty:\n                    self.error_buffer.check()\n                wait_time = min(wait_time * 2, 30)\n                delta = time.time() - start\n                if delta > sync_timeout:\n                    raise FatalError(\"Waited %.0fs to obtain envs, timeout was %.0fs. (Obtained %d/%d envs.)\" % (delta, sync_timeout, len(envs), n))\n\n        return envs\n\n    def allocate(self, handles, initial=False, params={}):\n        \"\"\"Call from main thread. Initiate a request for more environments\"\"\"\n        assert all(re.search('^\\d+$', h) for h in handles), \"All handles must be numbers: {}\".format(handles)\n        self.requests.put(('allocate', (handles, initial, params)))\n\n    def close(self):\n        self.requests.put(('close', ()))\n\n    def run(self):\n        try:\n            self._run()\n        except Stop:\n            pass\n        except Exception as e:\n            self.error_buffer.record(e)\n\n    def _run(self):\n        while True:\n            self._process_requests()\n            self._poll()\n\n    def _process_requests(self):\n        while True:\n            try:\n                method, args = self.requests.get(timeout=self._sleep)\n            except queue.Empty:\n                break\n            else:\n                if method == 'allocate':\n                    handles, initial, params = args\n                    self._allocate(handles, initial, params)\n                elif method == 'close':\n                    raise Stop\n\n    def _allocate(self, handles, initial, params):\n        self._sleep = 1\n\n        _params = self.params.copy()\n        _params.update(params)\n\n        for handle in handles:\n            history = self._reconnect_history.get(handle, [])\n            history.append(time.time())\n            floor = time.time() - 5 * 60\n            history = [entry for entry in history if entry > floor]\n            if len(history) > 5:\n                raise error.Error('Tried reallocating a fresh remote at index {} a total of {} times in the past 5 minutes (at {}). Please examine the logs to determine why the remotes keep failing.'.format(handle, len(history), history))\n            self._reconnect_history[handle] = history\n\n        assert all(re.search('^\\d+$', h) for h in handles), \"All handles must be numbers: {}\".format(handles)\n        allocation = self.with_retries(self._requestor.allocation_create,\n            client_id=self.client_id,\n            runtime_id=self.runtime_id,\n            placement=self.placement,\n            params=_params,\n            handles=handles,\n            initial=initial,\n        )\n        news = len([entry for entry in allocation['info']['n'] if entry['new']])\n        extra_logger.info('[%s] Received allocation with %s new and %s existing envs: %s', self.label, news, len(allocation['info']['n']) - news, allocation)\n\n        assert len(allocation['env_n']) <= len(handles), \"Received more envs than requested: allocation={} handles={}\".format(allocation, handles)\n        _, pending = self._handle_allocation(allocation)\n\n        for env in pending:\n            self.pending[env['name']] = {\n                'handle': env['handle'],\n                'params': params,\n                'received_at': time.time()\n            }\n\n    def _poll(self):\n        self._sleep = min(20, self._sleep + 2)\n\n        if len(self.pending) == 0:\n            return\n\n        for name, spec in self.pending.items():\n            delta = time.time() - spec['received_at']\n            if delta > self.start_timeout:\n                raise error.TimeoutError('Waited {}s for {} to get an IP, which exceeds start_timeout of {}'.format(delta, name, self.start_timeout))\n\n        names = list(self.pending.keys())\n        # This really should be an allocation_get, but it's possible\n        # the pods list will be long. So it's either GET with a body,\n        # or POST what should really be a GET. We do the latter.\n        allocation = self.with_retries(self._requestor.allocation_refresh, self.client_id, names=names)\n        assert len(allocation['env_n']) <= len(names), \"Received more envs than requested: allocation={} names={}\".format(allocation, names)\n\n        # Handle any envs which have gone missing\n        result = set(env['name'] for env in allocation['env_n'])\n        dropped = [p for p in self.pending.keys() if p not in result]\n        if len(dropped) > 0:\n            logger.info('Pending remote envs %s were not returned by the allocator (only %s were returned). Assuming the missing ones have gone down and requesting replacements.', dropped, list(result))\n            for d in dropped:\n                spec = self.pending.pop(d)\n                self._allocate([spec['handle']], False, spec['params'])\n\n        # Handle successful allocations\n        self._handle_allocation(allocation, pop=True)\n\n    def _handle_allocation(self, allocation, pop=False):\n        ready = []\n        not_ready = []\n        for alloc_env in allocation['env_n']:\n            if alloc_env['status'] != 'allocated':\n                not_ready.append(alloc_env)\n                continue\n            if pop:\n                self.pending.pop(alloc_env['name'])\n            vnc_address = alloc_env['vnc_recorder_address'] if self.use_recorder_ports else alloc_env['vnc_address']\n            rewarder_address = alloc_env['rewarder_recorder_address'] if self.use_recorder_ports else alloc_env['rewarder_address']\n            env = remote.Remote(\n                name=alloc_env['name'],\n                handle=alloc_env['handle'],\n                vnc_address=vnc_address,\n                vnc_password=alloc_env['vnc_password'],\n                rewarder_address=rewarder_address,\n                rewarder_password=alloc_env['rewarder_password'],\n            )\n            ready.append(env)\n\n        if len(ready) > 0:\n            extra_logger.info('[%s] The following envs now have IPs, but still may take time to boot: %s', self.label, ready)\n            self.ready.put(ready)\n\n        return ready, not_ready\n\n    def with_retries(self, method, *args, **kwargs):\n        timeout = 20 * 60\n        start = time.time()\n\n        i = 0\n        while True:\n            try:\n                return method(*args, **kwargs)\n            except FatalError as e:\n                logger.error('[%s] %s', self.label, e)\n                self.error_buffer.record(e)\n                raise\n            except Exception as e:\n                delta = time.time() - start\n                if delta > timeout:\n                    raise error.TimeoutError('Have been unable to connect to the allocator at {} for {}s. Giving up. Last error: {}'.format(self.base_url, delta, e))\n                i += 1\n\n                sleep = min(2**i, 60)\n                time.sleep(sleep)\n                logger.error('[%s] Error making request to allocator: %s. Will retry in %ss (and timeout in %.0fs)', self.label, e, sleep, start + timeout - time.time())\n\nclass AllocatorClient(object):\n    def __init__(self, label, api_key, base_url):\n        self.label = label\n        self.api_key = api_key\n        self.base_url = base_url\n        self.session = requests.Session()\n        self.session.headers.update({'Content-type': 'application/json'})\n        self.request_timeout = 80\n\n    def _handle_resp(self, resp):\n        try:\n            parsed = resp.json()\n        except ValueError as e:\n            if resp.status_code == 500:\n                raise RequestError(message=\"500 Internal Error (retrying automatically): response={}\".format(resp.content), status_code=resp.status_code)\n            elif resp.status_code == 503:\n                raise RequestError(message=\"503 Error from server (allocator is probably overloaded): response={}\".format(resp.content), status_code=resp.status_code)\n            elif resp.status_code == 200:\n                raise RequestError(message=\"Response from server: status_code={} response={}\".format(resp.status_code, resp.content), status_code=resp.status_code)\n            else:\n                raise RequestError(message=\"Error from server: status_code={} response={}\".format(resp.status_code, resp.content), status_code=resp.status_code)\n\n        if resp.status_code == 200:\n            return parsed\n        elif 'detail' in parsed:\n            raise FatalError(message=parsed['detail'], status_code=resp.status_code)\n        else:\n            raise RequestError(message='Malformed response from allocator, missing \"detail\" key: {}'.format(parsed), status_code=resp.status_code)\n\n    def _post_request(self, route, data, description):\n        url = urlparse.urljoin(self.base_url, route)\n        extra_logger.info('[%s] %s: POST %s: %s', self.label, description, url, json.dumps(data))\n        resp = self.session.post(urlparse.urljoin(self.base_url, route),\n                                 data=json.dumps(data), auth=(self.api_key, ''),\n                                 timeout=self.request_timeout,\n        )\n        return self._handle_resp(resp)\n\n    def _delete_request(self, route):\n        url = urlparse.urljoin(self.base_url, route)\n        extra_logger.info(\"[%s] DELETE %s\", self.label, url)\n        resp = self.session.delete(url, auth=(self.api_key, ''), timeout=self.request_timeout)\n        return self._handle_resp(resp)\n\n    def _get_request(self, route):\n        url = urlparse.urljoin(self.base_url, route)\n        extra_logger.info(\"[%s] GET %s\", self.label, url)\n        resp = self.session.get(url, auth=(self.api_key, ''), timeout=self.request_timeout)\n        return self._handle_resp(resp)\n\n    def allocation_create(self, client_id, runtime_id, handles, params={}, placement='public', initial=False):\n        route = '/v1/allocations'\n        data = {'client': client_id, 'runtime': runtime_id, 'params': params, 'handles': handles, 'initial': initial, 'placement': placement}\n        logger.info('Requesting %s environment%s from %s: %s', len(handles), 's' if len(handles) != 1 else '', self.base_url, data)\n        resp = self._post_request(route, data, description='requesting new allocation')\n        return resp\n\n    def allocation_refresh(self, id, names):\n        route = '/v1/allocations/{}'.format(id)\n        resp = self._post_request(route, data={'names': names}, description='refreshing existing allocation')\n        return resp\n\n    def allocation_delete(self, id, names):\n        route = '/v1/allocations/{}'.format(id)\n        resp = self._post_request(route, {'names': names}, 'deleting existing allocation')\n        return resp\n"
  },
  {
    "path": "universe/remotes/build.py",
    "content": "import re\nfrom universe import error\nfrom universe.remotes.allocator_remote import AllocatorManager\nfrom universe.remotes.docker_remote import DockerManager\nfrom universe.remotes.hardcoded_addresses import HardcodedAddresses\n\ndef build(client_id, remotes, runtime=None, start_timeout=None, **kwargs):\n    if isinstance(remotes, int):\n        remotes = str(remotes)\n    elif not isinstance(remotes, str):\n        raise error.Error('remotes argument must be a string, got {} which is of type {}'.format(remotes, type(remotes)))\n\n    if re.search('^\\d+$', remotes): # an integer, like -r 20\n        n = int(remotes)\n        return DockerManager(\n            runtime=runtime,\n            start_timeout=start_timeout,\n            reuse=kwargs.get('reuse', False),\n            n=n,\n        ), n\n    elif remotes.startswith('vnc://'):\n        return HardcodedAddresses.build(\n            remotes,\n            start_timeout=start_timeout)\n    elif remotes.startswith('http://') or remotes.startswith('https://'):\n        if runtime is None:\n            raise error.Error('Must provide a runtime. HINT: try creating your env instance via gym.make(\"flashgames.DuskDrive-v0\")')\n\n        manager, n = AllocatorManager.from_remotes(\n            client_id,\n            remotes,\n            runtime_id=runtime.id,\n            runtime_tag=runtime.image.split(':')[-1],\n            start_timeout=start_timeout,\n            api_key=kwargs.get('api_key'),\n            use_recorder_ports=kwargs.get('use_recorder_ports', False),\n        )\n        manager.start()\n        return manager, n\n    else:\n        raise error.Error('Invalid remotes: {!r}. Must be an integer or must start with vnc:// or https://'.format(remotes))\n"
  },
  {
    "path": "universe/remotes/compose/__init__.py",
    "content": ""
  },
  {
    "path": "universe/remotes/compose/colors.py",
    "content": "from __future__ import absolute_import\nfrom __future__ import unicode_literals\nNAMES = [\n    'grey',\n    'red',\n    'green',\n    'yellow',\n    'blue',\n    'magenta',\n    'cyan',\n    'white'\n]\n\n\ndef get_pairs():\n    for i, name in enumerate(NAMES):\n        yield(name, str(30 + i))\n        yield('intense_' + name, str(30 + i) + ';1')\n\n\ndef ansi(code):\n    return '\\033[{0}m'.format(code)\n\n\ndef ansi_color(code, s):\n    return '{0}{1}{2}'.format(ansi(code), s, ansi(0))\n\n\ndef make_color_fn(code):\n    return lambda s: ansi_color(code, s)\n\n\nfor (name, code) in get_pairs():\n    globals()[name] = make_color_fn(code)\n\n\ndef rainbow():\n    cs = ['cyan', 'yellow', 'green', 'magenta', 'red', 'blue',\n          'intense_cyan', 'intense_yellow', 'intense_green',\n          'intense_magenta', 'intense_red', 'intense_blue']\n\n    for c in cs:\n        yield globals()[c]\n"
  },
  {
    "path": "universe/remotes/compose/container.py",
    "content": "from __future__ import absolute_import\nfrom __future__ import unicode_literals\n\nfrom functools import reduce\n\nimport six\n\nLABEL_CONTAINER_NUMBER = 'com.docker.compose.container-number'\nLABEL_ONE_OFF = 'com.docker.compose.oneoff'\nLABEL_PROJECT = 'com.docker.compose.project'\nLABEL_SERVICE = 'com.docker.compose.service'\nLABEL_VERSION = 'com.docker.compose.version'\nLABEL_CONFIG_HASH = 'com.docker.compose.config-hash'\n\nclass Container(object):\n    \"\"\"\n    Represents a Docker container, constructed from the output of\n    GET /containers/:id:/json.\n    \"\"\"\n    def __init__(self, client, dictionary, has_been_inspected=False):\n        self.client = client\n        self.dictionary = dictionary\n        self.has_been_inspected = has_been_inspected\n        self.log_stream = None\n\n    @classmethod\n    def from_ps(cls, client, dictionary, **kwargs):\n        \"\"\"\n        Construct a container object from the output of GET /containers/json.\n        \"\"\"\n        name = get_container_name(dictionary)\n        if name is None:\n            return None\n\n        new_dictionary = {\n            'Id': dictionary['Id'],\n            'Image': dictionary['Image'],\n            'Name': '/' + name,\n        }\n        return cls(client, new_dictionary, **kwargs)\n\n    @classmethod\n    def from_id(cls, client, id):\n        return cls(client, client.inspect_container(id), has_been_inspected=True)\n\n    @classmethod\n    def create(cls, client, **options):\n        response = client.create_container(**options)\n        return cls.from_id(client, response['Id'])\n\n    @property\n    def id(self):\n        return self.dictionary['Id']\n\n    @property\n    def image(self):\n        return self.dictionary['Image']\n\n    @property\n    def image_config(self):\n        return self.client.inspect_image(self.image)\n\n    @property\n    def short_id(self):\n        return self.id[:12]\n\n    @property\n    def name(self):\n        return self.dictionary['Name'][1:]\n\n    @property\n    def service(self):\n        return self.labels.get(LABEL_SERVICE)\n\n    @property\n    def name_without_project(self):\n        project = self.labels.get(LABEL_PROJECT)\n\n        if self.name.startswith('{0}_{1}'.format(project, self.service)):\n            return '{0}_{1}'.format(self.service, self.number)\n        else:\n            return self.name\n\n    @property\n    def number(self):\n        number = self.labels.get(LABEL_CONTAINER_NUMBER)\n        if not number:\n            raise ValueError(\"Container {0} does not have a {1} label\".format(\n                self.short_id, LABEL_CONTAINER_NUMBER))\n        return int(number)\n\n    @property\n    def ports(self):\n        self.inspect_if_not_inspected()\n        return self.get('NetworkSettings.Ports') or {}\n\n    @property\n    def human_readable_ports(self):\n        def format_port(private, public):\n            if not public:\n                return private\n            return '{HostIp}:{HostPort}->{private}'.format(\n                private=private, **public[0])\n\n        return ', '.join(format_port(*item)\n                         for item in sorted(six.iteritems(self.ports)))\n\n    @property\n    def labels(self):\n        return self.get('Config.Labels') or {}\n\n    @property\n    def stop_signal(self):\n        return self.get('Config.StopSignal')\n\n    @property\n    def log_config(self):\n        return self.get('HostConfig.LogConfig') or None\n\n    @property\n    def human_readable_state(self):\n        if self.is_paused:\n            return 'Paused'\n        if self.is_restarting:\n            return 'Restarting'\n        if self.is_running:\n            return 'Ghost' if self.get('State.Ghost') else 'Up'\n        else:\n            return 'Exit %s' % self.get('State.ExitCode')\n\n    @property\n    def human_readable_command(self):\n        entrypoint = self.get('Config.Entrypoint') or []\n        cmd = self.get('Config.Cmd') or []\n        return ' '.join(entrypoint + cmd)\n\n    @property\n    def environment(self):\n        def parse_env(var):\n            if '=' in var:\n                return var.split(\"=\", 1)\n            return var, None\n        return dict(parse_env(var) for var in self.get('Config.Env') or [])\n\n    @property\n    def exit_code(self):\n        return self.get('State.ExitCode')\n\n    @property\n    def is_running(self):\n        return self.get('State.Running')\n\n    @property\n    def is_restarting(self):\n        return self.get('State.Restarting')\n\n    @property\n    def is_paused(self):\n        return self.get('State.Paused')\n\n    @property\n    def log_driver(self):\n        return self.get('HostConfig.LogConfig.Type')\n\n    @property\n    def has_api_logs(self):\n        log_type = self.log_driver\n        return not log_type or log_type != 'none'\n\n    def attach_log_stream(self):\n        \"\"\"A log stream can only be attached if the container uses a json-file\n        log driver.\n        \"\"\"\n        if self.has_api_logs:\n            self.log_stream = self.attach(stdout=True, stderr=True, stream=True)\n\n    def get(self, key):\n        \"\"\"Return a value from the container or None if the value is not set.\n\n        :param key: a string using dotted notation for nested dictionary\n                    lookups\n        \"\"\"\n        self.inspect_if_not_inspected()\n\n        def get_value(dictionary, key):\n            return (dictionary or {}).get(key)\n\n        return reduce(get_value, key.split('.'), self.dictionary)\n\n    def get_local_port(self, port, protocol='tcp'):\n        port = self.ports.get(\"%s/%s\" % (port, protocol))\n        return \"{HostIp}:{HostPort}\".format(**port[0]) if port else None\n\n    def get_mount(self, mount_dest):\n        for mount in self.get('Mounts'):\n            if mount['Destination'] == mount_dest:\n                return mount\n        return None\n\n    def start(self, **options):\n        return self.client.start(self.id, **options)\n\n    def stop(self, **options):\n        return self.client.stop(self.id, **options)\n\n    def pause(self, **options):\n        return self.client.pause(self.id, **options)\n\n    def unpause(self, **options):\n        return self.client.unpause(self.id, **options)\n\n    def kill(self, **options):\n        return self.client.kill(self.id, **options)\n\n    def restart(self, **options):\n        return self.client.restart(self.id, **options)\n\n    def remove(self, **options):\n        return self.client.remove_container(self.id, **options)\n\n    def create_exec(self, command, **options):\n        return self.client.exec_create(self.id, command, **options)\n\n    def start_exec(self, exec_id, **options):\n        return self.client.exec_start(exec_id, **options)\n\n    def rename_to_tmp_name(self):\n        \"\"\"Rename the container to a hopefully unique temporary container name\n        by prepending the short id.\n        \"\"\"\n        self.client.rename(\n            self.id,\n            '%s_%s' % (self.short_id, self.name)\n        )\n\n    def inspect_if_not_inspected(self):\n        if not self.has_been_inspected:\n            self.inspect()\n\n    def wait(self):\n        return self.client.wait(self.id)\n\n    def logs(self, *args, **kwargs):\n        return self.client.logs(self.id, *args, **kwargs)\n\n    def inspect(self):\n        self.dictionary = self.client.inspect_container(self.id)\n        self.has_been_inspected = True\n        return self.dictionary\n\n    def attach(self, *args, **kwargs):\n        return self.client.attach(self.id, *args, **kwargs)\n\n    def __repr__(self):\n        return '<Container: %s (%s)>' % (self.name, self.id[:6])\n\n    def __eq__(self, other):\n        if type(self) != type(other):\n            return False\n        return self.id == other.id\n\n    def __hash__(self):\n        return self.id.__hash__()\n\n\ndef get_container_name(container):\n    if not container.get('Name') and not container.get('Names'):\n        return None\n    # inspect\n    if 'Name' in container:\n        return container['Name']\n    # ps\n    shortest_name = min(container['Names'], key=lambda n: len(n.split('/')))\n    return shortest_name.split('/')[-1]\n"
  },
  {
    "path": "universe/remotes/compose/log_printer.py",
    "content": "# Forked from docker-compose\nfrom __future__ import absolute_import\nfrom __future__ import unicode_literals\n\nimport sys\nimport os\nimport threading\n\nfrom collections import namedtuple\nfrom itertools import cycle\nfrom threading import Thread\n\nfrom six.moves import _thread as thread\nfrom six.moves.queue import Empty\nfrom six.moves.queue import Queue\n\nfrom universe.remotes.compose import colors, utils\nfrom universe.remotes.compose.signals import ShutdownException\nfrom universe.remotes.compose.utils import split_buffer\n\ndef build(containers, service_names, **kwargs):\n    monochrome = not os.isatty(1)\n    presenters = build_log_presenters(service_names, monochrome)\n    printer = LogPrinter(containers, presenters, **kwargs)\n    printer.start()\n\nclass LogPresenter(object):\n\n    def __init__(self, prefix_width, color_func):\n        self.prefix_width = prefix_width\n        self.color_func = color_func\n\n    def present(self, container, line):\n        prefix = container.name_without_project.ljust(self.prefix_width)\n        return '{prefix} {line}'.format(\n            prefix=self.color_func(prefix + ' |'),\n            line=line)\n\n\ndef build_log_presenters(service_names, monochrome):\n    \"\"\"Return an iterable of functions.\n\n    Each function can be used to format the logs output of a container.\n    \"\"\"\n    prefix_width = max_name_width(service_names)\n\n    def no_color(text):\n        return text\n\n    for color_func in cycle([no_color] if monochrome else colors.rainbow()):\n        yield LogPresenter(prefix_width, color_func)\n\n\ndef max_name_width(service_names, max_index_width=3):\n    \"\"\"Calculate the maximum width of container names so we can make the log\n    prefixes line up like so:\n\n    db_1  | Listening\n    web_1 | Listening\n    \"\"\"\n    return max(len(name) for name in service_names) + max_index_width\n\n\nclass LogPrinter(threading.Thread):\n    \"\"\"Print logs from many containers to a single output stream.\"\"\"\n\n    daemon = True\n\n    def __init__(self,\n                 containers,\n                 presenters,\n                 output=sys.stdout,\n                 cascade_stop=False,\n                 log_args=None):\n        super(LogPrinter, self).__init__(name='LogPrinter')\n        self.containers = containers\n        self.presenters = presenters\n        self.output = utils.get_output_stream(output)\n        self.cascade_stop = cascade_stop\n        self.log_args = log_args or {}\n\n    def run(self):\n        if not self.containers:\n            return\n\n        queue = Queue()\n        thread_args = queue, self.log_args\n        thread_map = build_thread_map(self.containers, self.presenters, thread_args)\n\n        for line in consume_queue(queue, self.cascade_stop):\n            remove_stopped_threads(thread_map)\n\n            if not line:\n                if not thread_map:\n                    # There are no running containers left to tail, so exit\n                    return\n                # We got an empty line because of a timeout, but there are still\n                # active containers to tail, so continue\n                continue\n\n            try:\n                self.output.write(line)\n                self.output.flush()\n            except ValueError:\n                # ValueError: I/O operation on closed file\n                break\n\n\ndef remove_stopped_threads(thread_map):\n    for container_id, tailer_thread in list(thread_map.items()):\n        if not tailer_thread.is_alive():\n            thread_map.pop(container_id, None)\n\n\ndef build_thread(container, presenter, queue, log_args):\n    tailer = Thread(\n        target=tail_container_logs,\n        args=(container, presenter, queue, log_args))\n    tailer.daemon = True\n    tailer.start()\n    return tailer\n\n\ndef build_thread_map(initial_containers, presenters, thread_args):\n    return {\n        container.id: build_thread(container, next(presenters), *thread_args)\n        for container in initial_containers\n    }\n\n\nclass QueueItem(namedtuple('_QueueItem', 'item is_stop exc')):\n\n    @classmethod\n    def new(cls, item):\n        return cls(item, None, None)\n\n    @classmethod\n    def exception(cls, exc):\n        return cls(None, None, exc)\n\n    @classmethod\n    def stop(cls):\n        return cls(None, True, None)\n\n\ndef tail_container_logs(container, presenter, queue, log_args):\n    generator = get_log_generator(container)\n\n    try:\n        for item in generator(container, log_args):\n            queue.put(QueueItem.new(presenter.present(container, item)))\n    except Exception as e:\n        queue.put(QueueItem.exception(e))\n        return\n\n    if log_args.get('follow'):\n        queue.put(QueueItem.new(presenter.color_func(wait_on_exit(container))))\n    queue.put(QueueItem.stop())\n\n\ndef get_log_generator(container):\n    if container.has_api_logs:\n        return build_log_generator\n    return build_no_log_generator\n\n\ndef build_no_log_generator(container, log_args):\n    \"\"\"Return a generator that prints a warning about logs and waits for\n    container to exit.\n    \"\"\"\n    yield \"WARNING: no logs are available with the '{}' log driver\\n\".format(\n        container.log_driver)\n\n\ndef build_log_generator(container, log_args):\n    # if the container doesn't have a log_stream we need to attach to container\n    # before log printer starts running\n    if container.log_stream is None:\n        stream = container.logs(stdout=True, stderr=True, stream=True, **log_args)\n    else:\n        stream = container.log_stream\n\n    return split_buffer(stream)\n\n\ndef wait_on_exit(container):\n    exit_code = container.wait()\n    return \"%s exited with code %s\\n\" % (container.name, exit_code)\n\n\ndef start_producer_thread(thread_args):\n    producer = Thread(target=watch_events, args=thread_args)\n    producer.daemon = True\n    producer.start()\n\n\ndef watch_events(thread_map, event_stream, presenters, thread_args):\n    for event in event_stream:\n        if event['action'] == 'stop':\n            thread_map.pop(event['id'], None)\n\n        if event['action'] != 'start':\n            continue\n\n        if event['id'] in thread_map:\n            if thread_map[event['id']].is_alive():\n                continue\n            # Container was stopped and started, we need a new thread\n            thread_map.pop(event['id'], None)\n\n        thread_map[event['id']] = build_thread(\n            event['container'],\n            next(presenters),\n            *thread_args)\n\n\ndef consume_queue(queue, cascade_stop):\n    \"\"\"Consume the queue by reading lines off of it and yielding them.\"\"\"\n    while True:\n        try:\n            item = queue.get(timeout=0.1)\n        except Empty:\n            yield None\n            continue\n        # See https://github.com/docker/compose/issues/189\n        except thread.error:\n            raise ShutdownException()\n\n        if item.exc:\n            raise item.exc\n\n        if item.is_stop:\n            if cascade_stop:\n                raise StopIteration\n            else:\n                continue\n\n        yield item.item\n"
  },
  {
    "path": "universe/remotes/compose/progress_stream.py",
    "content": "from __future__ import absolute_import\nfrom __future__ import unicode_literals\n\nfrom universe.remotes.compose import utils\n\n\nclass StreamOutputError(Exception):\n    pass\n\n\ndef stream_output(output, stream):\n    is_terminal = hasattr(stream, 'isatty') and stream.isatty()\n    stream = utils.get_output_stream(stream)\n    all_events = []\n    lines = {}\n    diff = 0\n\n    for event in utils.json_stream(output):\n        all_events.append(event)\n        is_progress_event = 'progress' in event or 'progressDetail' in event\n\n        if not is_progress_event:\n            print_output_event(event, stream, is_terminal)\n            stream.flush()\n            continue\n\n        if not is_terminal:\n            continue\n\n        # if it's a progress event and we have a terminal, then display the progress bars\n        image_id = event.get('id')\n        if not image_id:\n            continue\n\n        if image_id in lines:\n            diff = len(lines) - lines[image_id]\n        else:\n            lines[image_id] = len(lines)\n            stream.write(\"\\n\")\n            diff = 0\n\n        # move cursor up `diff` rows\n        stream.write(\"%c[%dA\" % (27, diff))\n\n        print_output_event(event, stream, is_terminal)\n\n        if 'id' in event:\n            # move cursor back down\n            stream.write(\"%c[%dB\" % (27, diff))\n\n        stream.flush()\n\n    return all_events\n\n\ndef print_output_event(event, stream, is_terminal):\n    if 'errorDetail' in event:\n        raise StreamOutputError(event['errorDetail']['message'])\n\n    terminator = ''\n\n    if is_terminal and 'stream' not in event:\n        # erase current line\n        stream.write(\"%c[2K\\r\" % 27)\n        terminator = \"\\r\"\n    elif 'progressDetail' in event:\n        return\n\n    if 'time' in event:\n        stream.write(\"[%s] \" % event['time'])\n\n    if 'id' in event:\n        stream.write(\"%s: \" % event['id'])\n\n    if 'from' in event:\n        stream.write(\"(from %s) \" % event['from'])\n\n    status = event.get('status', '')\n\n    if 'progress' in event:\n        stream.write(\"%s %s%s\" % (status, event['progress'], terminator))\n    elif 'progressDetail' in event:\n        detail = event['progressDetail']\n        total = detail.get('total')\n        if 'current' in detail and total:\n            percentage = float(detail['current']) / float(total) * 100\n            stream.write('%s (%.1f%%)%s' % (status, percentage, terminator))\n        else:\n            stream.write('%s%s' % (status, terminator))\n    elif 'stream' in event:\n        stream.write(\"%s%s\" % (event['stream'], terminator))\n    else:\n        stream.write(\"%s%s\\n\" % (status, terminator))\n\n\ndef get_digest_from_pull(events):\n    for event in events:\n        status = event.get('status')\n        if not status or 'Digest' not in status:\n            continue\n\n        _, digest = status.split(':', 1)\n        return digest.strip()\n    return None\n\n\ndef get_digest_from_push(events):\n    for event in events:\n        digest = event.get('aux', {}).get('Digest')\n        if digest:\n            return digest\n    return None\n"
  },
  {
    "path": "universe/remotes/compose/signals.py",
    "content": "from __future__ import absolute_import\nfrom __future__ import unicode_literals\n\nimport signal\n\n\nclass ShutdownException(Exception):\n    pass\n\n\ndef shutdown(signal, frame):\n    raise ShutdownException()\n\n\ndef set_signal_handler(handler):\n    signal.signal(signal.SIGINT, handler)\n    signal.signal(signal.SIGTERM, handler)\n\n\ndef set_signal_handler_to_shutdown():\n    set_signal_handler(shutdown)\n"
  },
  {
    "path": "universe/remotes/compose/utils.py",
    "content": "from __future__ import absolute_import\nfrom __future__ import unicode_literals\n\nimport codecs\nimport hashlib\nimport json\nimport json.decoder\n\nimport six\n\n\njson_decoder = json.JSONDecoder()\n\n\ndef get_output_stream(stream):\n    if six.PY3:\n        return stream\n    return codecs.getwriter('utf-8')(stream)\n\n\ndef stream_as_text(stream):\n    \"\"\"Given a stream of bytes or text, if any of the items in the stream\n    are bytes convert them to text.\n\n    This function can be removed once docker-py returns text streams instead\n    of byte streams.\n    \"\"\"\n    for data in stream:\n        if not isinstance(data, six.text_type):\n            data = data.decode('utf-8', 'replace')\n        yield data\n\n\ndef line_splitter(buffer, separator=u'\\n'):\n    index = buffer.find(six.text_type(separator))\n    if index == -1:\n        return None\n    return buffer[:index + 1], buffer[index + 1:]\n\n\ndef split_buffer(stream, splitter=None, decoder=lambda a: a):\n    \"\"\"Given a generator which yields strings and a splitter function,\n    joins all input, splits on the separator and yields each chunk.\n\n    Unlike string.split(), each chunk includes the trailing\n    separator, except for the last one if none was found on the end\n    of the input.\n    \"\"\"\n    splitter = splitter or line_splitter\n    buffered = six.text_type('')\n\n    for data in stream_as_text(stream):\n        buffered += data\n        while True:\n            buffer_split = splitter(buffered)\n            if buffer_split is None:\n                break\n\n            item, buffered = buffer_split\n            yield item\n\n    if buffered:\n        yield decoder(buffered)\n\n\ndef json_splitter(buffer):\n    \"\"\"Attempt to parse a json object from a buffer. If there is at least one\n    object, return it and the rest of the buffer, otherwise return None.\n    \"\"\"\n    try:\n        obj, index = json_decoder.raw_decode(buffer)\n        rest = buffer[json.decoder.WHITESPACE.match(buffer, index).end():]\n        return obj, rest\n    except ValueError:\n        return None\n\n\ndef json_stream(stream):\n    \"\"\"Given a stream of text, return a stream of json objects.\n    This handles streams which are inconsistently buffered (some entries may\n    be newline delimited, and others are not).\n    \"\"\"\n    return split_buffer(stream, json_splitter, json_decoder.decode)\n\n\ndef json_hash(obj):\n    dump = json.dumps(obj, sort_keys=True, separators=(',', ':'))\n    h = hashlib.sha256()\n    h.update(dump.encode('utf8'))\n    return h.hexdigest()\n\n\ndef microseconds_from_time_nano(time_nano):\n    return int(time_nano % 1000000000 / 1000)\n\n\ndef build_string_dict(source_dict):\n    return dict((k, str(v if v is not None else '')) for k, v in source_dict.items())\n"
  },
  {
    "path": "universe/remotes/docker_remote.py",
    "content": "from __future__ import absolute_import\n\nimport base64\nimport logging\nimport os\nimport pipes\nimport sys\nimport threading\nimport uuid\nimport time, random\n\nimport docker\nimport six.moves.urllib.parse as urlparse\nfrom gym.utils import closer\nfrom universe import error\nfrom universe.remotes import healthcheck, remote\nfrom universe import error, utils\nfrom universe.remotes.compose import container, log_printer, progress_stream\n\nlogger = logging.getLogger(__name__)\n\ndocker_closer = closer.Closer()\n\ndef random_alphanumeric(length=14):\n    buf = []\n    while len(buf) < length:\n        entropy = base64.encodestring(uuid.uuid4().bytes).decode('utf-8')\n        bytes = [c for c in entropy if c.isalnum()]\n        buf += bytes\n    return ''.join(buf)[:length]\n\ndef pretty_command(command):\n    return ' '.join(pipes.quote(c) for c in command)\n\nclass DockerManager(object):\n    def __init__(self, runtime, n, reuse=False, start_timeout=None):\n        super(DockerManager, self).__init__()\n\n        self.runtime = runtime\n\n        self.supports_reconnect = False\n        self.connect_vnc = True\n        self.connect_rewarder = True\n        self._assigner = PortAssigner(reuse=reuse)\n\n        self._popped = False\n\n        self.lock = threading.Lock()\n        self.envs = []\n\n        self._n = n\n        if start_timeout is None:\n            start_timeout = 2 * self._n + 5\n        self.start_timeout = start_timeout\n        self._start()\n\n    def allocate(self, handles, initial=False, params={}):\n        self._handles = handles\n\n    def pop(self, n=None):\n        \"\"\"Call from main thread. Returns the list of newly-available (handle, env) pairs.\"\"\"\n        if self._popped:\n            assert n is None\n            return []\n        self._popped = True\n\n        envs = []\n        for i, instance in enumerate(self.instances):\n            env = remote.Remote(\n                handle=self._handles[i],\n                vnc_address='{}:{}'.format(instance.host, instance.vnc_port),\n                vnc_password='openai',\n                rewarder_address='{}:{}'.format(instance.host, instance.rewarder_port),\n                rewarder_password='openai',\n            )\n            envs.append(env)\n        return envs\n\n    def _start(self):\n        self.instances = [DockerInstance(self._assigner, self.runtime, label=str(i)) for i in range(self._n)]\n\n        [instance.start() for instance in self.instances]\n        if int(os.environ.get('OPENAI_REMOTE_VERBOSE', '1')) > 0:\n            self.start_logging(self.instances)\n        self.healthcheck(self.instances)\n\n    def close(self):\n        with self.lock:\n            [instance.close() for instance in self.instances]\n\n    def start_logging(self, instances):\n        containers = [instance._container for instance in instances]\n        labels = [str(instance.label) for instance in instances]\n        if all(instance.reusing for instance in instances):\n            # All containers are being reused, so only bother showing\n            # a subset of the backlog.\n            tail = 0\n        else:\n            # At least one container is new, so just show\n            # everything. It'd be nice to have finer-grained control,\n            # but this would require patching the log printer.\n            tail = 'all'\n        log_printer.build(containers, labels, log_args={'tail': tail})\n\n    def healthcheck(self, instances):\n        # Wait for boot\n        healthcheck.run(\n            ['{}:{}'.format(instance.assigner.info['host'], instance.vnc_port) for instance in instances],\n            ['{}:{}'.format(instance.assigner.info['host'], instance.rewarder_port) for instance in instances],\n            start_timeout=30,\n        )\n\ndef get_client():\n    \"\"\"\n    Set DOCKER_HOST (and probably DOCKER_TLS_VERIFY and DOCKER_CERT_PATH) to connect to a docker instance through TCP.\n    Leave DOCKER_HOST unset and it will use the default, typically unix:/var/run/docker.sock\n\n    It also needs to know how to connect to ports on the docker container after creating it.\n    Set DOCKER_NET_HOST to provide an IP address to connect to the VNC ports on\n    otherwise if DOCKER_HOST has a hostname, it will connect to the VNC ports using that name.\n    otherwise it connects using localhost\n    \"\"\"\n    info = {}\n    host = os.environ.get('DOCKER_HOST')\n    net_host = os.environ.get('DOCKER_NET_HOST')\n\n    client_api_version = os.environ.get('DOCKER_API_VERSION')\n    if not client_api_version:\n        client_api_version = \"auto\"\n\n    # IP to use for started containers\n    if net_host:\n        info['host'] = net_host\n    elif host:\n        info['host'] = urlparse.urlparse(host).netloc.split(':')[0]\n    else:\n        info['host'] = 'localhost'\n\n    verify = os.environ.get('DOCKER_TLS_VERIFY') == '1'\n    if verify: # use TLS\n        assert_hostname = None\n        cert_path = os.environ.get('DOCKER_CERT_PATH')\n        if cert_path:\n            client_cert = (os.path.join(cert_path, 'cert.pem'), os.path.join(cert_path, 'key.pem'))\n            ca_cert = os.path.join(cert_path, 'ca.pem')\n        else:\n            client_cert = ca_cert = None\n\n        tls_config = docker.tls.TLSConfig(\n            client_cert=client_cert,\n            ca_cert=ca_cert,\n            verify=verify,\n            assert_hostname=assert_hostname,\n        )\n        return docker.Client(base_url=host, tls=tls_config, version=client_api_version), info\n    else:\n        return docker.Client(base_url=host, version=client_api_version), info\n\nclass PortAssigner(object):\n    def __init__(self, reuse=False):\n        self.reuse = reuse\n        self.instance_id = 'universe-' + random_alphanumeric(length=6)\n        self.client, self.info = get_client()\n        self._next_port = 5900\n        self._refresh_ports()\n\n    def _refresh_ports(self):\n        ports = {}\n        for container in self.client.containers():\n            for port in container['Ports']:\n                # {u'IP': u'0.0.0.0', u'Type': u'tcp', u'PublicPort': 5000, u'PrivatePort': 500}\n                if port['Type'] == 'tcp' and 'PublicPort' in port:\n                    ports[port['PublicPort']] = container['Id']\n        logger.info('Ports used: %s', ports.keys())\n        self._ports = ports\n\n    def allocate_ports(self, num):\n        if self.reuse and self._next_port in self._ports:\n            vnc_id = self._ports[self._next_port]\n            rewarder_id = self._ports.get(self._next_port+10000)\n\n            # Reuse an existing docker container if it exists\n            if (self._next_port+10000) not in self._ports:\n                raise error.Error(\"Port {} was allocated but {} was not. This indicates unexpected state with spun-up VNC docker instances.\".format(self._next_port, self._next_port+1))\n            elif vnc_id != rewarder_id:\n                raise error.Error(\"Port {} is exposed from {} while {} is exposed from {}. Both should come from a single Docker instance running your environment.\".format(vnc_id, self._next_port, rewarder_id, self._next_port+10000))\n\n            base = self._next_port\n            self._next_port += 1\n            return base, base+10000, vnc_id\n        elif not self.reuse:\n            # Otherwise, allocate find the lowest free pair of\n            # ports. This doesn't work for the reuse case since on\n            # restart we won't remember where we spun up our\n            # containers.\n            while self._next_port in self._ports or (self._next_port+10000) in self._ports:\n                self._next_port += 1\n\n        base = self._next_port\n        self._next_port += 1\n\n        # And get started!\n        return base, base+10000, None\n\nclass DockerInstance(object):\n    def __init__(self, assigner, runtime, label='main'):\n        self._docker_closer_id = docker_closer.register(self)\n\n        self.label = label\n        self.assigner = assigner\n        self.name='{}-{}'.format(self.assigner.instance_id, self.label),\n\n        self.runtime = runtime\n\n        self._container_id = None\n        self._closed = False\n\n        self._container = None\n\n        self.host = self.assigner.info['host']\n        self.vnc_port = None\n        self.rewarder_port = None\n        self.reusing = None\n        self.started = False\n\n    def start(self, attempts=None):\n        if attempts is None:\n            # If we're reusing, we don't scan through ports for a free\n            # one.\n            if not self.assigner.reuse:\n                attempts = 20\n            else:\n                attempts = 1\n\n        for attempt in range(attempts):\n            self._spawn()\n            e = self._start()\n            if e is None:\n                return\n\n            time.sleep(random.uniform(1.0, 5.0))\n            self.assigner._refresh_ports()\n\n        raise error.Error('[{}] Could not start container after {} attempts. Last error: {}'.format(self.label, attempts, e))\n\n    def _spawn(self):\n        if self.runtime.image is None:\n            raise error.Error('No image specified')\n        assert self._container_id is None\n\n        self.vnc_port, self.rewarder_port, self._container_id = self.assigner.allocate_ports(2)\n        if self._container_id is not None:\n            logger.info('[%s] Reusing container %s on ports %s and %s', self.label, self._container_id[:12], self.vnc_port, self.rewarder_port)\n            self.reusing = True\n            self.started = True\n            return\n\n        self.reusing = False\n        logger.info('[%s] Creating container: image=%s. Run the same thing by hand as: %s',\n                    self.label,\n                    self.runtime.image,\n                    pretty_command(self.runtime.cli_command(self.vnc_port, self.rewarder_port)))\n        try:\n            container = self._spawn_container()\n        except docker.errors.NotFound as e:\n            # Looks like we need to pull the image\n            assert 'No such image' in e.explanation.decode('utf-8'), 'Expected NotFound error message message to include \"No such image\", but it was: {}. This is probably just a bug in this assertion and the assumption was incorrect'.format(e.explanation)\n\n            logger.info('Image %s not present locally; pulling', self.runtime.image)\n            self._pull_image()\n            # If we called pull_image from multiple processes (as we do with universe-starter-agent A3C)\n            # these will all return at the same time. We probably all got the same port numbers before the pull started,\n            # so wait a short random time and refresh our port numbers\n            time.sleep(random.uniform(0.5, 2.5))\n            self.assigner._refresh_ports()\n            self.vnc_port, self.rewarder_port, self._container_id = self.assigner.allocate_ports(2)\n            if self._container_id is not None:\n                logger.info('[%s] Reusing container %s on ports %s and %s', self.label, self._container_id[:12], self.vnc_port, self.rewarder_port)\n                self.reusing = True\n                self.started = True\n                return\n            # Try spawning again.\n            container = self._spawn_container()\n\n        self._container_id = container['Id']\n\n    def _pull_image(self):\n        output = self.client.pull(self.runtime.image, stream=True)\n        return progress_stream.get_digest_from_pull(\n            progress_stream.stream_output(output, sys.stdout))\n\n        # docker-compose uses this:\n        # try:\n        # except StreamOutputError as e:\n        #     if not ignore_pull_failures:\n        #         raise\n        #     else:\n        #         log.error(six.text_type(e))\n\n    def _spawn_container(self):\n        # launch instance, and refresh if error\n        container = self.client.create_container(\n            image=self.runtime.image,\n            command=self.runtime.command,\n            # environment=self.runtime.environment,\n            name=self.name,\n            host_config=self.client.create_host_config(\n                port_bindings={\n                    5900: self.vnc_port,\n                    15900: self.rewarder_port,\n                 },\n                **self.runtime.host_config),\n            labels={\n                'com.openai.automanaged': 'true',\n            }\n        )\n        return container\n\n    def _start(self):\n        # Need to start up the container!\n        if not self.started:\n            logger.debug('[%s] Starting container: id=%s', self.label, self._container_id)\n            try:\n                self.client.start(container=self._container_id)\n            except docker.errors.APIError as e:\n                if 'port is already allocated' in str(e.explanation):\n                    logger.info('[%s] Could not start container: %s', self.label, e)\n                    self._remove()\n                    return e\n                else:\n                    raise\n            else:\n                self.started = True\n\n        self._container = container.Container.from_id(self.client, self._container_id)\n        return None\n\n    def _remove(self):\n        logger.info(\"Killing and removing container: id=%s\", self._container_id)\n        try:\n            self.client.remove_container(container=self._container_id, force=True)\n        except docker.errors.APIError as e:\n            # This seems to happen occasionally when we try to delete a container immediately after creating it.\n            # But although we get an error trying to remove it, it usually goes away shortly\n            # A typical error message is\n            #   Driver aufs failed to remove root filesystem 0015803583d91741d25fce28ae0ef540b436853d1c90061caacaef97e3682403: \\\n            #   rename /var/lib/docker/aufs/mnt/69a72854511f1fbb9d7cb0ef0ce0787e573af0887c1213ba3a0c3a0cfd71efd2 \\\n            #   /var/lib/docker/aufs/mnt/69a72854511f1fbb9d7cb0ef0ce0787e573af0887c1213ba3a0c3a0cfd71efd2-removing: \\\n            #   device or resource busy\n            # Just proceed as if it had gone away\n            if 'device or resource busy' in str(e.explanation):\n                logger.info(\"[%s] Could not remove container: %s. You can always kill all automanaged environments on this Docker daemon via: docker rm -f $(docker ps -q -a -f 'label=com.openai.automanaged=true')\", self.label, e)\n                self._container_id = None\n                return e\n            else:\n                raise\n\n        self._container_id = None\n\n    def __del__(self):\n        self.close()\n\n    def close(self):\n        if self._closed:\n            return\n\n        docker_closer.unregister(self._docker_closer_id)\n\n        # Make sure 1. we were the onse who started it, 2. it's\n        # actually been started, and 3. we're meant to kill it.\n        if self._container_id and not self.assigner.reuse:\n            self._remove()\n\n        self._closed = True\n\n    @property\n    def client(self):\n        return self.assigner.client\n\nif __name__ == '__main__':\n    logging.getLogger().setLevel(logging.INFO)\n    from universe.runtimes import registration\n\n    # docker run --name test --rm -ti -p 5900:5900 -p 15900:15900 quay.io/openai/universe.gym-core\n    instance = DockerManager(\n        runtime=registration.runtime_spec('gym-core'),\n        n=2,\n    )\n    instance.start()\n    import ipdb;ipdb.set_trace()\n"
  },
  {
    "path": "universe/remotes/hardcoded_addresses.py",
    "content": "import logging\nimport os\nimport re\nimport six.moves.urllib.parse as urlparse\n\nfrom universe import error, utils\nfrom universe.remotes import remote\n\nlogger = logging.getLogger(__name__)\n\nclass HardcodedAddresses(object):\n    @classmethod\n    def build(cls, remotes, **kwargs):\n        parsed = urlparse.urlparse(remotes)\n        if parsed.scheme != 'vnc':\n            raise error.Error('HardcodedAddresses must be initialized with a string starting with vnc://: {}'.format(remotes))\n\n        addresses = parsed.netloc.split(',')\n        query = urlparse.parse_qs(parsed.query)\n        # We could support per-backend passwords, but no need for it\n        # right now.\n        password = query.get('password', [utils.default_password()])[0]\n        vnc_addresses, rewarder_addresses = parse_remotes(addresses)\n        res = cls(vnc_addresses, rewarder_addresses, vnc_password=password, rewarder_password=password, **kwargs)\n        return res, res.available_n\n\n    def __init__(self, vnc_addresses, rewarder_addresses, vnc_password, rewarder_password, start_timeout=None):\n        if vnc_addresses is not None:\n            self.available_n = len(vnc_addresses)\n        elif rewarder_addresses is not None:\n            self.available_n = len(rewarder_addresses)\n        else:\n            assert False\n\n        self.supports_reconnect = False\n        self.connect_vnc = vnc_addresses is not None\n        self.connect_rewarder = rewarder_addresses is not None\n        if rewarder_addresses is None:\n            logger.info(\"No rewarder addresses were provided, so this env cannot connect to the remote's rewarder channel, and cannot send control messages (e.g. reset)\")\n\n        self.vnc_addresses = vnc_addresses\n        self.vnc_password = vnc_password\n        self.rewarder_addresses = rewarder_addresses\n        self.rewarder_password = rewarder_password\n        if start_timeout is None:\n            start_timeout = 2 * self.available_n + 5\n        self.start_timeout = start_timeout\n\n        self._popped = False\n\n    def pop(self, n=None):\n        if self._popped:\n            assert n is None\n            return []\n        self._popped = True\n\n        remotes = []\n        for i in range(self.available_n):\n            if self.vnc_addresses is not None:\n                vnc_address = self.vnc_addresses[i]\n            else:\n                vnc_address = None\n\n            if self.rewarder_addresses is not None:\n                rewarder_address = self.rewarder_addresses[i]\n            else:\n                rewarder_address = None\n\n            name = self._handles[i]\n            env = remote.Remote(\n                handle=self._handles[i],\n                vnc_address=vnc_address,\n                vnc_password=self.vnc_password,\n                rewarder_address=rewarder_address,\n                rewarder_password=self.rewarder_password,\n            )\n            remotes.append(env)\n        return remotes\n\n    def allocate(self, handles, initial=False, params={}):\n        if len(handles) > self.available_n:\n            raise error.Error('Requested {} handles, but only have {} envs'.format(len(handles), self.available_n))\n        self.n = len(handles)\n        self._handles = handles\n\n    def close(self):\n        pass\n\ndef parse_remotes(remotes):\n    # Parse a list of remotes of the form:\n    #\n    # address:vnc_port+rewarder_port (e.g. localhost:5900+15900)\n    #\n    # either vnc_port or rewarder_port can be omitted, but not both\n\n    all_vnc = None\n    all_rewarder = None\n\n    vnc_addresses = []\n    rewarder_addresses = []\n\n    for remote in remotes:\n        # Parse off +, then :\n        if '+' in remote:\n            if all_vnc == False:\n                raise error.Error('Either all or no remotes must have rewarders: {}'.format(remotes))\n            all_vnc = True\n\n            remote, rewarder_port = remote.split('+')\n            if not re.match(r'^[0-9]+$', rewarder_port):\n                raise error.Error('Rewarder port must be an integer, not `{}`: {}'.format(rewarder_port, remotes))\n            rewarder_port = int(rewarder_port)\n        else:\n            if all_vnc == True:\n                raise error.Error('Either all or no remotes must have rewarders: {}'.format(remotes))\n            all_vnc = False\n\n            rewarder_port = None\n\n        if ':' in remote:\n            if all_rewarder == False:\n                raise error.Error('Either all or no remotes must have a VNC port: {}'.format(remotes))\n            all_rewarder = True\n\n            remote, vnc_port = remote.split(':')\n            if not re.match(r'^[0-9]+$', vnc_port):\n                raise error.Error('VNC port must be an integer, not `{}`: {}'.format(vnc_port, remotes))\n            vnc_port = int(vnc_port)\n        else:\n            if all_rewarder == True:\n                raise error.Error('Either all or no remotes must have a VNC port: {}'.format(remotes))\n            all_rewarder = False\n\n            vnc_port = None\n            all_rewarder = False\n\n        host = remote\n        if not re.match(r'^[-a-zA-Z0-9\\.\\_]+$', host):\n            raise error.Error('Invalid hostname for remote: {}'.format(remotes))\n\n        if rewarder_port is not None:\n            rewarder_address = '{}:{}'.format(host, rewarder_port)\n            rewarder_addresses.append(rewarder_address)\n\n        if vnc_port is not None:\n            vnc_address = '{}:{}'.format(host, vnc_port)\n            vnc_addresses.append(vnc_address)\n\n    if not all_vnc and not all_rewarder:\n        raise error.Error('You must provide either rewarder or a VNC port: {}'.format(remotes))\n\n    if not vnc_addresses:\n        vnc_addresses = None\n    if not rewarder_addresses:\n        rewarder_addresses = None\n    return vnc_addresses, rewarder_addresses\n"
  },
  {
    "path": "universe/remotes/healthcheck.py",
    "content": "import errno\nimport logging\nimport select\nimport socket\nimport time\n\nfrom universe import error, utils\nfrom gym.utils import reraise\n\nlogger = logging.getLogger(__name__)\n\ndef run(vnc_addresses, rewarder_addresses, timeout=None, start_timeout=None):\n    healthcheck = Healthcheck(vnc_addresses, rewarder_addresses, timeout=timeout, start_timeout=start_timeout)\n    healthcheck.run()\n\ndef host_port(address, default_port=None):\n    split = address.split(':')\n    if len(split) == 1:\n        host = split[0]\n        port = default_port\n    else:\n        host, port = split\n        port = int(port)\n    return host, port\n\nclass Healthcheck(object):\n    def __init__(self, vnc_addresses, rewarder_addresses, timeout=None, start_timeout=None):\n        self.timeout = timeout or (4 * len(vnc_addresses) + 20)\n        self.start_timeout = start_timeout\n\n        start_time = time.time()\n\n        self.sockets = {}\n        for address in vnc_addresses:\n            self._register_vnc(address, start_time)\n        for address in rewarder_addresses:\n            self._register_rewarder(address, start_time)\n\n    def _register_vnc(self, address, start_time=None):\n        if start_time is None:\n            start_time = time.time()\n\n        host, port = host_port(address, default_port=5900)\n\n        while True:\n            # In VNC, the server sends bytes upon connection\n            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n            try:\n                sock.connect((host, port))\n            except (socket.error, socket.gaierror) as e:\n                # ECONNREFUSED: VNC env hasn't come up yet\n                # ETIMEDOUT: the packets can't be delivered yet, such as can happen on kubernetes\n                # gaierror: can't resolve the address yet, which can also happen on kubernetes\n                expected = socket.errno.ECONNREFUSED == e.errno or socket.errno.ETIMEDOUT == e.errno or isinstance(e, socket.gaierror)\n                if self.start_timeout is None or not expected:\n                    reraise(suffix='while connecting to VNC server {}'.format(address))\n                logger.info('VNC server %s did not come up yet (error: %s). Sleeping for 1s.', address, e)\n                time.sleep(1)\n            else:\n                break\n\n            if time.time() - start_time > self.start_timeout:\n                raise error.Error('VNC server {} did not come up within {}s'.format(address, self.start_timeout))\n\n        self.sockets[sock] = ('vnc', address)\n\n    def _register_rewarder(self, address, start_time=None):\n        if start_time is None:\n            start_time = time.time()\n\n        host, port = host_port(address, default_port=15900)\n\n        while True:\n            # In WebSockets, the server sends bytes once we've upgraded the protocol\n            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n            try:\n                sock.connect((host, port))\n            except (socket.error, socket.gaierror) as e:\n                # ECONNREFUSED: VNC env hasn't come up yet\n                # ETIMEDOUT: the packets can't be delivered yet, such as can happen on kubernetes\n                # gaierror: can't resolve the address yet, which can also happen on kubernetes\n                expected = socket.errno.ECONNREFUSED == e.errno or socket.errno.ETIMEDOUT == e.errno or isinstance(e, socket.gaierror)\n                if self.start_timeout is None or not expected:\n                    reraise(suffix='while connecting to Rewarder server {}'.format(address))\n                logger.info('Rewarder server %s did not come up yet (error: %s). Sleeping for 1s.', address, e)\n                time.sleep(1)\n            else:\n                break\n\n            if time.time() - start_time > self.start_timeout:\n                raise error.Error('Rewarder server {} did not come up within {}s'.format(address, self.start_timeout))\n\n        # Send a websocket handshake.\n        # https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers\n        #\n        # The port 10003 is an arbitrary port that we don't actually connect to, but needs to be a valid part\n        # e.g Host: 127.0.0.1:GARBAGE results in the following error: (invalid port 'GARBAGE' in HTTP Host header '127.0.0.1:GARBAGE')\n        sock.send(b'GET / HTTP/1.1\\r\\nHost: 127.0.0.1:10003\\r\\nUpgrade: WebSocket\\r\\nConnection:Upgrade\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nSec-WebSocket-Version: 13\\r\\nauthorization: ' + utils.basic_auth_encode('openai').encode('utf-8') + b'\\r\\nopenai-observer: true\\r\\n\\r\\n')\n        self.sockets[sock] = ('rewarder', address)\n\n    def run(self):\n        target = time.time() + self.timeout\n        while self.sockets:\n            remaining = target - time.time()\n            if remaining < 0:\n                break\n            ready, _, _ = select.select(self.sockets.keys(), [], [], remaining)\n\n            # Go through the readable sockets\n            remote_closed = False\n            for sock in ready:\n                type, address = self.sockets.pop(sock)\n\n                # Connection was closed; try again.\n                #\n                # This is guaranteed not to block.\n                try:\n                    recv = sock.recv(1)\n                except socket.error as e:\n                    if e.errno == errno.ECONNRESET:\n                        recv = b''\n                    else:\n                        raise\n\n                if recv == b'':\n                    logger.info('Remote closed: address=%s', address)\n                    remote_closed = True\n                    if type == 'rewarder':\n                        self._register_rewarder(address)\n                    else:\n                        self._register_vnc(address)\n                else:\n                    logger.debug('Healthcheck passed for %s %s', type, address)\n\n                sock.close()\n\n            if remote_closed:\n                sleep = 1\n                logger.info('At least one sockets was closed by the remote. Sleeping %ds...', sleep)\n                time.sleep(sleep)\n\n        if self.sockets:\n            raise error.Error('Not all servers came up within {}s: {}'.format(self.timeout, list(self.sockets.values())))\n"
  },
  {
    "path": "universe/remotes/remote.py",
    "content": "class Remote(object):\n    def __init__(self, handle, vnc_address, vnc_password, rewarder_address, rewarder_password, name=None):\n        self.name = name\n        self.handle = handle\n        self.vnc_address = vnc_address\n        self.vnc_password = vnc_password\n        self.rewarder_address = rewarder_address\n        self.rewarder_password = rewarder_password\n\n    def __str__(self):\n        return 'Remote<{}:{}>'.format(self.handle, self.name)\n\n    def __repr__(self):\n        return str(self)\n"
  },
  {
    "path": "universe/rewarder/__init__.py",
    "content": "from universe.rewarder.rewarder_session import RewarderSession\nfrom universe.rewarder.env_status import EnvStatus, compare_ids\nfrom universe.rewarder.merge import merge_n, merge_infos, merge_reward_n, merge_observation_n\nfrom universe.rewarder.reward_buffer import RewardBuffer\n"
  },
  {
    "path": "universe/rewarder/connection_timer.py",
    "content": "import os\nimport re\nimport signal\nimport time\n\nfrom universe import error\nfrom universe.twisty import reactor\nfrom twisted.internet import defer, protocol\nimport twisted.internet.error\nimport logging\n\nlogger = logging.getLogger(__name__)\nextra_logger = logging.getLogger('universe.extra.'+__name__)\n\nclass ConnectionTimer(protocol.Protocol):\n    def connectionMade(self):\n        self.transport.loseConnection()\n\ndef start(endpoint):\n    start = time.time()\n    return endpoint.connect(\n        protocol.ClientFactory.forProtocol(ConnectionTimer)\n    ).addCallback(lambda _: time.time() - start)\n\ndef measure_clock_skew(label, host):\n    cmd = ['ntpdate', '-q', '-p', '8', host]\n    extra_logger.info('[%s] Starting network calibration with %s', label, ' '.join(cmd))\n    skew = Clockskew(label, cmd)\n    # TODO: search PATH for this?\n    process = reactor.spawnProcess(skew, '/usr/sbin/ntpdate', cmd, {})\n    # process = reactor.spawnProcess(skew, '/bin/sleep', ['sleep', '2'], {})\n\n    t = float(os.environ.get('UNIVERSE_NTPDATE_TIMEOUT', 20))\n    def timeout():\n        if process.pid:\n            logger.error('[%s] %s call timed out after %ss; killing the subprocess. This is ok, but you could have more accurate timings by enabling UDP port 123 traffic to your env. (Alternatively, you can try increasing the timeout by setting environment variable UNIVERSE_NTPDATE_TIMEOUT=10.)', label, ' '.join(cmd), t)\n            process.signalProcess(signal.SIGKILL)\n            process.reapProcess()\n    # TODO: make this part of the connection string\n    reactor.callLater(t, timeout)\n    return skew.deferred\n\nclass Clockskew(protocol.ProcessProtocol):\n    def __init__(self, label, cmd):\n        self.label = label\n        self._cmd = cmd\n\n        self.deferred = defer.Deferred()\n        self.out = []\n        self.err = []\n\n    def outReceived(self, data):\n        self.out.append(data)\n\n    def errReceived(self, data):\n        self.err.append(data)\n\n    def processExited(self, reason):\n        if isinstance(reason.value, twisted.internet.error.ProcessDone):\n            out = b''.join(self.out).decode('utf-8')\n            match = re.search('offset ([\\d.-]+) sec', out)\n            if match is not None:\n                offset = float(match.group(1))\n                self.deferred.callback(offset)\n            else:\n                self.deferred.errback(error.Error('Could not parse offset: %s', out))\n        else:\n            err = b''.join(self.err)\n            self.deferred.errback(error.Error('{} failed with status {}: stderr={!r}'.format(self._cmd, reason.value.exitCode, err)))\n\nclass ConnectionTimerException(Exception):\n    pass\n"
  },
  {
    "path": "universe/rewarder/env_status.py",
    "content": "import logging\nimport threading\n\nlogger = logging.getLogger()\n\ndef parse_episode_id(episode_id):\n    if episode_id is None:\n        return -1\n    return int(episode_id)\n\ndef generate_episode_id(parsed):\n    if parsed == -1:\n        return None\n    return str(parsed)\n\ndef compare_ids(a, b):\n    if a == b:\n        return 0\n    elif a is None:\n        return -1\n    elif b is None:\n        return 1\n    elif parse_episode_id(a) < parse_episode_id(b):\n        return -1\n    else:\n        return 1\n\nclass EnvStatus(object):\n    def __init__(self, label=None, primary=True):\n        self.cv = threading.Condition()\n        self._env_id = None\n        self._env_state = None\n        self._episode_id = '0'\n        self._fps = None\n        self.label = label or 'EnvStatus'\n        self.primary = primary\n\n    def env_info(self):\n        with self.cv:\n            return {\n                'env_state': self._env_state,\n                'env_id': self._env_id,\n                'episode_id': self._episode_id,\n                'fps': self._fps,\n            }\n\n    def set_env_info(self, env_state=None, env_id=None, episode_id=None, bump_past=None, fps=None):\n        \"\"\"Atomically set the environment state tracking variables.\n        \"\"\"\n        with self.cv:\n            if env_id is None:\n                env_id = self._env_id\n            if env_state is None:\n                env_state = self._env_state\n            if fps is None:\n                fps = self._fps\n            self.cv.notifyAll()\n\n            old_episode_id = self._episode_id\n            if self.primary:\n                current_id = parse_episode_id(self._episode_id)\n                # Bump when changing from resetting -> running\n                if bump_past is not None:\n                    bump_past_id = parse_episode_id(bump_past)\n                    current_id = max(bump_past_id+1, current_id+1)\n                elif env_state == 'resetting':\n                    current_id += 1\n                self._episode_id = generate_episode_id(current_id)\n                assert self._fps or fps\n            elif episode_id is False:\n                # keep the same episode_id: this is just us proactive\n                # setting the state to resetting after a done=True\n                pass\n            else:\n                assert episode_id is not None, \"No episode_id provided. This likely indicates a misbehaving server, which did not send an episode_id\"\n                self._episode_id = episode_id\n            self._fps = fps\n            logger.info('[%s] Changing env_state: %s (env_id=%s) -> %s (env_id=%s) (episode_id: %s->%s, fps=%s)', self.label, self._env_state, self._env_id, env_state, env_id, old_episode_id, self._episode_id, self._fps)\n            self._env_state = env_state\n            if env_id is not None:\n                self._env_id = env_id\n\n            return self.env_info()\n\n    @property\n    def episode_id(self):\n        with self.cv:\n            return self._episode_id\n\n    @property\n    def env_state(self):\n        with self.cv:\n            return self._env_state\n\n    @env_state.setter\n    def env_state(self, value):\n        # TODO: Validate env_state\n        self.set_env_info(value)\n\n    @property\n    def env_id(self):\n        with self.cv:\n            return self._env_id\n\n    @env_id.setter\n    def env_id(self, value):\n        self.set_env_info(None, env_id=value)\n\n    @property\n    def fps(self):\n        with self.cv:\n            return self._fps\n\n    def wait_for_env_state_change(self, start_state):\n        with self.cv:\n            while True:\n                if self._env_state != start_state:\n                    return self.env_info()\n                self.cv.wait(timeout=10)\n"
  },
  {
    "path": "universe/rewarder/merge.py",
    "content": "from universe import error\nimport six\n\ndef merge_infos(info1, info2):\n    \"\"\"We often need to aggregate together multiple infos. Most keys can\n    just be clobbered by the new info, but e.g. any keys which contain\n    counts should be added. The merge schema is indicated by the key\n    namespace.\n\n    Namespaces:\n\n    - stats.timers: Timing\n    - stats.gauges: Gauge values\n    - stats.*: Counts of a quantity\n    \"\"\"\n    for key, value in six.iteritems(info2):\n        if key in info1 and key.startswith('stats'):\n            if key.startswith('stats.timers'):\n                # timer\n                info1[key] += value\n            elif key.startswith('stats.gauges'):\n                # gauge\n                info1[key] = value\n            else:\n                # counter\n                info1[key] += value\n        else:\n            info1[key] = value\n\ndef merge_reward_n(accum_reward_n, reward_n):\n    for i in range(len(reward_n)):\n        if reward_n[i] is not None:\n            # Add rewards\n            accum_reward_n[i] += reward_n[i]\n\ndef merge_done_n(accum_done_n, done_n):\n    for i in range(len(done_n)):\n        # Copy over done if the episode is indeed none\n        if done_n[i]:\n            accum_done_n[i] = done_n[i]\n\ndef _merge_observation(accum_observation, observation):\n    \"\"\"\n    Old visual observation is discarded, because it is outdated frame.\n    Text observations are merged, because they are messages sent from the rewarder.\n    \"\"\"\n    if observation is None:\n        # We're currently masking. So accum_observation probably\n        # belongs to the previous episode. We may lose a \"text\"\n        # observation from the previous episode, but that's ok.\n        return None\n    elif accum_observation is None:\n        # Nothing to merge together\n        return observation\n\n    accum_observation['vision'] = observation.get('vision')\n    accum_observation['text'] = accum_observation.get('text', []) + observation.get('text', [])\n    return accum_observation\n\ndef merge_observation_n(accum_observation_n, observation_n):\n    # Merge observations.\n    for i in range(len(accum_observation_n)):\n        accum_observation_n[i] = _merge_observation(accum_observation_n[i], observation_n[i])\n\ndef merge_n(\n        accum_observation_n, accum_reward_n, accum_done_n, accum_info,\n        observation_n, reward_n, done_n, info,\n):\n    # Merge observation/reward/done\n    merge_observation_n(accum_observation_n, observation_n)\n    merge_reward_n(accum_reward_n, reward_n)\n    merge_done_n(accum_done_n, done_n)\n\n    # Merge together infos. We deep merge the 'n' key and do a\n    # simple merge on everything else.\n    accum_info_n = accum_info['n']\n    for accum_info_i, info_i in zip(accum_info_n, info['n']):\n        merge_infos(accum_info_i, info_i)\n\n    merge_infos(accum_info, info)\n    accum_info['n'] = accum_info_n\n"
  },
  {
    "path": "universe/rewarder/remote.py",
    "content": "# loaded inside of the environments\n\nimport logging\nimport os\nfrom universe import pyprofile\nimport sys\nis_py2 = sys.version[0] == '2'\nif is_py2:\n    import Queue as queue\nelse:\n    import queue as queue\nimport threading\nimport time\nimport ujson\nimport collections\n\nfrom autobahn.twisted import websocket\nfrom universe.twisty import reactor\n\nfrom universe import error, utils\n\nlogger = logging.getLogger(__name__)\n\nclass Exit(Exception):\n    pass\n\nclass RewarderProtocol(websocket.WebSocketServerProtocol):\n    connections = None\n\n    def onConnect(self, request):\n        if not os.path.exists('/usr/local/openai/privileged_state/password'):\n            raise error.Error('No such file: /usr/local/openai/privileged_state/password. (HINT: did the init script run /app/universe-envs/base/openai-setpassword?)')\n        with open('/usr/local/openai/privileged_state/password') as f:\n            password = f.read().strip()\n\n        self._message_id = 0\n        self._request = request\n        self._observer = request.headers.get('openai-observer') == 'true'\n        self.password = password\n\n        logger.info('Client connecting: peer=%s observer=%s', request.peer, self._observer)\n\n    def authenticate(self, request):\n        # Ugly, but it'll have to do for now.\n        authorization = request.headers.get('authorization')\n        if authorization is None:\n            logger.info('REJECT REASON: No authorization header supplied: %s', request.headers)\n            self.reject('No authorization header supplied. You must supply a basic authentication header.')\n            return\n        basic = utils.basic_auth_decode(authorization)\n        if basic is None:\n            logger.info('REJECT REASON: Invalid basic auth header: %s', request.headers)\n            self.reject('Could not parse authorization header. You must supply a basic authentication header.')\n            return\n        username, password = basic\n        if username != self.password:\n            logger.info('REJECT REASON: Invalid password: %r (%s expected; %s)', username, self.password, request.headers)\n            self.reject('Invalid password: {!r}. If you are using the allocator, you should see your password in the logs; if spinning up an environment by hand, it defaults to \"openai\". Connect as vnc://<ip>:<port>?password=<password>.'.format(username))\n            return\n\n    def onOpen(self):\n        logger.info('WebSocket connection established')\n        # Need to wait until onOpen to send messages\n        self.authenticate(self._request)\n        self.factory.agent_conn._register(self, observer=self._observer)\n\n        # Inform the agent about the current env status\n        env_info = self.factory.agent_conn.env_status.env_info()\n        # Immediately upon connection, let the agent know the current\n        # status.\n        self.factory.agent_conn.send_env_describe_from_env_info(\n            env_info,\n        )\n\n    def onMessage(self, payload, isBinary):\n        if not self.factory.agent_conn.check_message(self):\n            return\n\n        assert not isBinary, \"Binary websocket not supported\"\n        payload = ujson.loads(payload)\n\n        context = {\n            'start': time.time(),\n            'conn': self,\n        }\n        latency = context['start'] - payload['headers']['sent_at']\n        pyprofile.incr('rewarder_protocol.messages')\n        pyprofile.incr('rewarder_protocol.messages.{}'.format(payload['method']))\n\n        pyprofile.timing('rewarder_protocol.latency.rtt.skew_unadjusted', 2*latency)\n        if latency < 0:\n            pyprofile.incr('rewarder_protocol.latency.rtt.skew_unadjusted.negative')\n\n        if payload['method'] == 'v0.env.reset':\n            logger.info('Received reset message: %s', payload)\n            self.factory.agent_conn.control_buffer.recv_rpc(context, payload)\n        elif payload['method'] == 'v0.control.ping':\n            logger.debug('Received ping message: %s', payload)\n            parent_message_id = payload['headers']['message_id']\n            headers = {'parent_message_id': parent_message_id}\n            self.send_message('v0.reply.control.ping', {}, headers)\n        else:\n            logger.warn('Received unsupported message: %s', payload)\n\n    def onClose(self, wasClean, code, reason):\n        logger.info('WebSocket connection closed: %s', reason)\n        self.factory.agent_conn._unregister(self)\n\n    def send_message(self, method, body, headers):\n        id = self._message_id\n\n        self._message_id += 1\n        new_headers = {\n            'message_id': id,\n            'sent_at': time.time(),\n        }\n        if headers:\n            new_headers.update(headers)\n\n        payload = {\n            'method': method,\n            'body': body,\n            'headers': new_headers,\n        }\n\n        # This is a bit ugly, but decide how much we care\n        if (method != 'v0.reply.control.ping' and 'parent_message_id' in new_headers) or\\\n           method == 'v0.connection.close':\n            logger.info('Sending rewarder message: %s', payload)\n        else:\n            logger.debug('Sending rewarder message: %s', payload)\n\n        self.sendMessage(ujson.dumps(payload).encode('utf-8'), False)\n\n    def reject(self, message):\n        self.send_message('v0.connection.close', {'message': message}, {})\n        self.sendClose(code=1000, reason=message)\n        self.transport.loseConnection()\n\nclass ControlBuffer(object):\n    def __init__(self, cv):\n        self.buf = queue.Queue()\n        self.cv = cv\n\n    def recv_rpc(self, context, payload):\n        \"\"\"Call from any thread\"\"\"\n        logger.debug(\"Adding RPC payload to ControlBuffer queue: %s\", payload)\n        self.buf.put(('rpc', (context, payload)))\n        with self.cv:\n            self.cv.notifyAll()\n\n    def client_disconnect(self, conn, stats):\n        self.buf.put(('client_disconnect', (conn, stats)))\n\n    def get(self, *args, **kwargs):\n        \"\"\"Call from main thread.\"\"\"\n        payload = self.buf.get(*args, **kwargs)\n        logger.debug(\"Removing RPC payload from ControlBuffer queue: %s\", payload)\n        return payload\n\nclass AgentConn(object):\n    def __init__(self, env_status, cv, control_buffer, error_buffer, idle_timeout=None, exclusive=False):\n        self.error_buffer = error_buffer\n\n        self.env_status = env_status\n        self.control_buffer = control_buffer\n        self.cv = cv\n        self.conns = {}\n        self.exclusive = exclusive\n\n        self.idle_timeout = idle_timeout\n        self.last_disconnect_time = time.time()\n        self._idle_message_interval = 10 # for logging\n\n    def active_clients(self):\n        return [conn for conn, stats in self.conns.items() if stats['active']]\n\n    def listen(self, port=15900):\n        logger.info('Starting Rewarder on port=%s', port)\n        factory = websocket.WebSocketServerFactory()\n        factory.agent_conn = self\n        factory.protocol = RewarderProtocol\n\n        reactor.callFromThread(reactor.listenTCP, port, factory)\n\n    def check_message(self, conn):\n        with self.cv:\n            self.conns[conn]['messages'] += 1\n            if self.conns[conn]['active']:\n                return True\n            elif self.conns[conn]['observer']:\n                logger.info('CONNECTION STATUS: Marking connection as active: observer=%s peer=%s total_conns=%d', True, conn._request.peer, len(self.conns))\n                self.conns[conn]['active'] = True\n                return True\n            else:\n                # Note: if this exceptions, Autobahn will end up capturing\n                # the errors since its hooks are called via\n                # maybeDeferred. This won't always print the prettiest\n                # stack trace.\n\n                # This conn is neither active or an observer - before setting\n                # active, let's see if there are any existing active,\n                # non-observer conns.\n                active = len([o for o in self.conns.values() if not o['observer'] and o['active']])\n                if active > 0:\n                    # Already full up, sorry!\n                    logger.info('CONNECTION STATUS: Dropping new connection since already have %d non-observer conns (%d conns total)', active, len(self.conns))\n                    # Sometimes connecting clients will time out before\n                    # the connection is fully established, but the\n                    # rewarder would still count the session as having\n                    # come up. This, we try to wait until as late as\n                    # possible to decide if a client is active.\n                    conn.reject('The rewarder already has an active client. (HINT: if you obtained your environment through the allocator, make sure to run .configure(client_id=...) with a different client_id for each concurrent worker.)')\n                    return False\n                else:\n                    logger.info('CONNECTION STATUS: Marking connection as active: observer=%s peer=%s total_conns=%d', False, conn._request.peer, len(self.conns))\n                    self.conns[conn]['active'] = True\n                    return True\n\n    def _register(self, conn, observer=False):\n        with self.cv:\n            self.conns[conn] = {'messages': 0, 'observer': observer, 'active': False}\n            self.cv.notifyAll()\n\n    def _unregister(self, conn):\n        with self.cv:\n            try:\n                stats = self.conns.pop(conn)\n            except KeyError:\n                stats = None\n            else:\n                self.cv.notifyAll()\n\n            if stats is not None and stats['active']:\n                self.last_disconnect_time = time.time()\n                active = self.active_clients()\n                logger.info('[%s] Active client disconnected (sent %d messages). Still have %d active clients left', utils.thread_name(), stats['messages'], len(active))\n            else:\n                logger.info('[%s] Non-active client disconnected', utils.thread_name())\n\n            self.control_buffer.client_disconnect(conn, stats)\n\n    def _broadcast(self, method, body, headers=None, conn=None):\n        if conn:\n            conns = [conn]\n        else:\n            conns = self.conns\n\n        for conn in conns:\n            conn.send_message(method, body, headers)\n\n    def send_env_text(self, text, episode_id):\n        ''' text channel to communicate with the agent '''\n        reactor.callFromThread(self._send_env_text, text, episode_id)\n\n    def _send_env_text(self, text, episode_id):\n        self._broadcast('v0.env.text', {\n            'text': text\n        }, {'episode_id': episode_id})\n\n    def send_env_observation(self, observation, episode_id):\n        reactor.callFromThread(self._send_env_observation, observation, episode_id)\n\n    def _send_env_observation(self, observation, episode_id, conn=None):\n        self._broadcast('v0.env.observation', {\n            'observation': observation,\n        }, {'episode_id': episode_id}, conn=conn)\n\n    def send_env_reward(self, reward, done, info, episode_id):\n        pyprofile.incr('agent_conn.reward', reward)\n        if done:\n            pyprofile.incr('agent_conn.done')\n\n        reactor.callFromThread(self._send_env_reward, reward, done, info, episode_id)\n\n    def _send_env_reward(self, reward, done, info, episode_id):\n        self._broadcast('v0.env.reward', {\n            'reward': reward,\n            'done': done,\n            'info': info,\n        }, {'episode_id': episode_id})\n\n    def send_env_describe_from_env_info(self, env_info):\n        assert env_info['fps'] is not None, \"Missing fps: {}\".format(env_info)\n        self.send_env_describe(env_info['env_id'], env_info['env_state'], episode_id=env_info['episode_id'], fps=env_info['fps'])\n\n    def send_env_describe(self, env_id, env_state, episode_id, fps, headers=None, parent_message_id=None, parent_context=None):\n        reactor.callFromThread(self._send_env_describe, env_id, env_state, episode_id, fps, headers, parent_message_id, parent_context)\n\n    def _send_env_describe(self, env_id, env_state, episode_id, fps, headers=None, parent_message_id=None, parent_context=None):\n        conn = None\n        if headers is None:\n            headers = {}\n\n        if parent_message_id is not None:\n            headers['parent_message_id'] = parent_message_id\n            headers['parent_runtime'] = time.time() - parent_context['start']\n            conn = parent_context['conn']\n\n        headers['episode_id'] = episode_id\n\n        assert fps is not None\n        # TODO: decide how to handle multiple concurrent envs\n        self._broadcast('v0.env.describe', {\n            'env_id': env_id,\n            'env_state': env_state,\n            'fps': fps,\n        }, headers, conn)\n\n    def send_reply_error(self, *args, **kwargs):\n        reactor.callFromThread(self._send_reply_error, *args, **kwargs)\n\n    def _send_reply_error(self, message, parent_message_id, parent_context):\n        headers = {}\n        headers['parent_message_id'] = parent_message_id\n        headers['parent_runtime'] = time.time() - parent_context['start']\n        conn = parent_context['conn']\n\n        # TODO: decide how to handle multiple concurrent envs\n        self._broadcast('v0.reply.error', {\n            'message': message,\n        }, headers, conn)\n\n    def send_reply_env_reset(self, *args, **kwargs):\n        reactor.callFromThread(self._send_reply_env_reset, *args, **kwargs)\n\n    def _send_reply_env_reset(self, parent_message_id, parent_context, episode_id):\n        headers = {}\n        headers['parent_message_id'] = parent_message_id\n        headers['parent_runtime'] = time.time() - parent_context['start']\n        headers['episode_id'] = episode_id\n        conn = parent_context['conn']\n\n        # TODO: decide how to handle multiple concurrent envs\n        self._broadcast('v0.reply.env.reset', {}, headers, conn)\n\n    def check_status(self):\n        with self.cv:\n            if self.idle_timeout is None:\n                return\n\n            active = self.active_clients()\n            if len(active) == 0:\n                now = time.time()\n                idle_duration = now - self.last_disconnect_time\n\n                if self.idle_timeout is not None:\n                    utils.periodic_log(\n                        self, 'idle_timeout',\n                        'No active clients for %.2fs (total client: %d); will exit due to idle timeout after %.0fs',\n                        idle_duration, len(self.conns), self.idle_timeout, frequency=self._idle_message_interval)\n                else:\n                    utils.periodic_log(\n                        self, 'idle_for',\n                        'No active clients for %.2fs (total client: %d)',\n                        idle_duration, len(self.conns), frequency=self._idle_message_interval)\n\n                if self.idle_timeout is not None and idle_duration > self.idle_timeout:\n                    self.error_buffer.record(Exit('EXIT CAUSE: idle timeout exceeded after {:.2f} seconds'.format(idle_duration)), wrap=False)\n\nclass RewardLogger(object):\n    def __init__(self):\n        self.reset(log=False, episode_stats=True)\n\n    def reset(self, log=True, episode_stats=True):\n        if log:\n            self._log()\n\n        self.last_print = time.time()\n        # Could just maintain summary statistics, but we're not going\n        # to have more than fps rewards at once, so it's fine to just\n        # keep them all around.\n        self.reward = []\n        self.done = False\n        self.info = {}\n        self.count = 0\n\n        if episode_stats:\n            if log:\n                self._log_reset()\n            self.episode_reward = 0\n            self.episode_count = 0\n            self.episode_start = time.time()\n\n    def record(self, reward, done, info):\n        self.reward.append(reward)\n        self.done = self.done or done\n        self.info.update(info)\n        self.count += 1\n\n        self.episode_reward += reward\n        self.episode_count += 1\n\n        if time.time() - self.last_print > 1:\n            self._log()\n            self.reset(log=False, episode_stats=False)\n\n    def _log_reset(self):\n        logger.info('[%s] Ending previous episode: episode_reward=%s episode_count=%s episode_duration=%.2f', utils.thread_name(), self.episode_reward, self.episode_count, time.time() - self.episode_start)\n\n    def _log(self):\n        if 'rewarder.profile' in self.info:\n            self.info['rewarder.profile'] = '<{} bytes>'.format(len(str(self.info['rewarder.profile'])))\n\n        if len(self.reward) > 0:\n            min_reward = min(self.reward)\n            max_reward = max(self.reward)\n        else:\n            min_reward = '(empty)'\n            max_reward = '(empty)'\n\n        logger.info('[%s] Over past %.2fs, sent %s reward messages to agent: reward=%s reward_min=%s reward_max=%s done=%s info=%s',\n                    utils.thread_name(), time.time() - self.last_print, self.count,\n                    sum(self.reward), min_reward, max_reward,\n                    self.done, self.info)\n"
  },
  {
    "path": "universe/rewarder/reward_buffer.py",
    "content": "import logging\nimport threading\nimport time\n\nfrom universe import error\nfrom universe.rewarder import env_status, merge\n\nlogger = logging.getLogger(__name__)\nextra_logger = logging.getLogger('universe.extra.'+__name__)\n\nclass RewardState(object):\n    def __init__(self, label, episode_id):\n        self.label = label\n\n        self.count = 0\n        self.reward = 0.\n        self.text = []\n        self.done = False\n        self.info = {}\n        self._observation = None\n\n        self._episode_id = episode_id\n        self._env_state = None\n\n    def push_time(self, remote_time, local_time):\n        # Sometimes helpful diagnostic info\n        self.info['reward_buffer.remote_time'] = remote_time\n        self.info['reward_buffer.local_time'] = local_time\n\n    def set_env_info(self, env_state):\n        self._env_state = env_state\n\n    def push_text(self, text):\n        self.text.append(text)\n\n    def push_done(self, done, info):\n        # Consider yourself done whenever a reward crosses episode\n        # boundaries.\n        self.done = self.done or done\n        if done:\n            info['reward_buffer.done_time'] = time.time()\n        self.push_info(info)\n\n    def push_info(self, info):\n        merge.merge_infos(self.info, info)\n\n    def push(self, reward, done, info):\n        # extra_logger.debug('[%s] RewardState: pushing reward %s to episode_id %s', self.label, reward, self._episode_id)\n        self.count += 1\n        self.reward += reward\n\n        # Consider yourself done whenever a reward crosses episode\n        # boundaries.\n        self.push_done(done, info)\n\n    def pop_text(self):\n        text = self.text\n        self.text = []\n        return text\n\n    def pop_info(self):\n        info = self.info\n        self.info = {}\n        info['env.text'] = self.pop_text()\n        if self._observation is not None:\n            # Only used for the debugging gym-core envs with\n            # rewarder_observation set.\n            info['rewarder.observation'] = (self._observation, self._episode_id)\n        info['env_status.episode_id'] = self._episode_id\n        info['env_status.env_state'] = self._env_state\n        return info\n\n    def pop(self):\n        info = self.pop_info()\n\n        count = self.count\n        reward = self.reward\n        done = self.done\n\n        self.count = 0\n        self.reward = 0.\n        self.done = False\n\n        info['stats.reward.count'] = count\n        extra_logger.debug('[%s] RewardState: popping reward %s from episode_id %s', self.label, reward, self._episode_id)\n        return reward, done, info\n\n    def set_observation(self, observation):\n        self._observation = observation\n\n# Buffers up incoming rewards\nclass RewardBuffer(object):\n    def __init__(self, label):\n        self.cv = threading.Condition()\n        self.label = label\n\n        self._current_episode_id = None\n        self._reward_state = {}\n\n        self._masked = True\n\n        self._remote_env_state = None\n        self._remote_env_id = None\n        self._remote_episode_id = None\n        self._remote_fps = None\n\n    def reward_state(self, episode_id):\n        try:\n            return self._reward_state[episode_id]\n        except:\n            extra_logger.info('[%s] RewardBuffer: Creating new RewardState for episode_id=%s', self.label, episode_id)\n            reward_state = self._reward_state[episode_id] = RewardState(self.label, episode_id)\n            if self._current_episode_id is None and not self._masked:\n                extra_logger.info('[%s] RewardBuffer advancing: No active episode, so activating episode_id=%s', self.label, episode_id)\n                self._current_episode_id = episode_id\n                self._drop_below(episode_id)\n            if episode_id is not None and not self._masked:\n                # If we're masked we'll be dropping everything below the reset ID anyway\n                valid = self._valid_ids()\n                for id in valid:\n                    if id == episode_id:\n                        continue\n                    state = self._reward_state[id]\n                    if state.done:\n                        continue\n                    extra_logger.info('[%s] RewardBuffer received message for episode_id=%s but no done=True message for %s. Artificially marking %s as done=True.', self.label, episode_id, id, id)\n                    state.push_done(True, {'env_status.artificial.done': True})\n\n            return reward_state\n\n    def set_env_info(self, env_state, env_id, episode_id, fps):\n        with self.cv:\n            if self._remote_env_state is not None:\n                extra_logger.info('[%s] RewardBuffer changing env_state: %s (env_id=%s) -> %s (env_id=%s) (episode_id: %s->%s, fps=%s, masked=%s, current_episode_id=%s)', self.label, self._remote_env_state, self._remote_env_id, env_state, env_id, self._remote_episode_id, episode_id, fps, self._masked, self._current_episode_id)\n            else:\n                extra_logger.info('[%s] RewardBuffer: Initial env_state: %s (env_id=%s) (episode_id: %s, fps=%s, masked=%s, current_episode_id=%s)', self.label, env_state, env_id, episode_id, fps, self._masked, self._current_episode_id)\n\n            self._remote_env_state = env_state\n            self._remote_env_id = env_id\n            self._remote_episode_id = episode_id\n            self._remote_fps = fps\n\n            self.reward_state(episode_id).set_env_info(env_state)\n\n    def set_observation(self, episode_id, observation):\n        with self.cv:\n            self.reward_state(episode_id).set_observation(observation)\n\n    def push_time(self, episode_id, remote_time, local_time):\n        with self.cv:\n            self.reward_state(episode_id).push_time(remote_time, local_time)\n\n    def push_text(self, episode_id, text):\n        with self.cv:\n            self.reward_state(episode_id).push_text(text)\n            self.cv.notifyAll()\n\n    def push_info(self, episode_id, info):\n        # Just send some info\n        with self.cv:\n            self.reward_state(episode_id).push_info(info)\n\n    def push(self, episode_id, reward, done, info):\n        with self.cv:\n            self.reward_state(episode_id).push(reward, done, info)\n            self.cv.notifyAll()\n\n    def pop(self, peek=False):\n        with self.cv:\n            self.cv.notifyAll()\n            if peek:\n                # This happens when a higher layer wants to poll for\n                # new observations being ready, but doesn't want to\n                # pop any rewards.\n                max_id = self._max_id()\n                reward_state = self.reward_state(self._current_episode_id)\n                peek_state = self.reward_state(max_id)\n                peek_id = peek_state._episode_id\n                peek_state = peek_state._env_state\n                if self._masked:\n                    assert reward_state._episode_id is None\n                    assert reward_state._env_state is None\n                    peek_id = None\n                    peek_state = None\n                return 0, False, {\n                    'peek': True,\n\n                    'env_status.episode_id': reward_state._episode_id,\n                    'env_status.env_state': reward_state._env_state,\n\n                    'env_status.peek.episode_id': peek_id,\n                    'env_status.peek.env_state': peek_state,\n                }\n\n            reward, done, info = self.reward_state(self._current_episode_id).pop()\n            if done:\n                # We return the *observation* from the new,\n                # reward/done from the old, and a merged info with\n                # keys from the new taking precedence.\n                self._advance()\n\n                new_state = self.reward_state(self._current_episode_id)\n                try:\n                    info['env_status.complete.episode_id'] = info['env_status.episode_id']\n                except KeyError:\n                    pass\n                try:\n                    info['env_status.complete.env_state'] = info['env_status.env_state']\n                except KeyError:\n                    pass\n                info['env_status.episode_id'] = new_state._episode_id\n                info['env_status.env_state'] = new_state._env_state\n                new_text = self.reward_state(self._current_episode_id).pop_text()\n                if len(info['env.text']) > 0:\n                    extra_logger.info('[%s] RewardBuffer dropping env.text for completed episode %s: %s', self.label, info['env_status.episode_id'], info['env.text'])\n                info['env.text'] = new_text\n            return reward, done, info\n\n    def mask(self):\n        with self.cv:\n            extra_logger.info('[%s] RewardBuffer advancing: masking until reset completes; setting current_episode_id=None', self.label)\n            self._masked = True\n            self._current_episode_id = None\n\n    def reset(self, episode_id):\n        with self.cv:\n            extra_logger.info('[%s] RewardBuffer advancing: unmasking after explicit reset: episode_id=%s', self.label, episode_id)\n            self._masked = False\n            self._drop_below(episode_id, quiet=True)\n            self._current_episode_id = episode_id\n            self.push_info(episode_id, {'env_status.reset.episode_id': episode_id})\n\n    def _max_id(self):\n        valid_ids = self._valid_ids()\n        if len(valid_ids) > 0:\n            parsed = max(env_status.parse_episode_id(k) for k in valid_ids)\n            return env_status.generate_episode_id(parsed)\n        else:\n            return None\n\n    def _valid_ids(self):\n        return [r for r in self._reward_state.keys() if r is not None]\n\n    def _advance(self):\n        completed_episode_id = self._current_episode_id\n        del self._reward_state[completed_episode_id]\n\n        if None in self._reward_state:\n            extra_logger.warn('[%s] WARNING: RewardBuffer: while advancing from %s, None was in reward state: %s', self.label, completed_episode_id, self._reward_state)\n\n        max_id = self._max_id()\n        if max_id is not None:\n            self._current_episode_id = max_id\n            if env_status.compare_ids(completed_episode_id, self._current_episode_id) >= 0:\n                extra_logger.info(\"[%s] RewardBuffer advancing: setting episode_id=None until new data received. Rare condition reached where message for old environment received after new one: completed_episode_id=%r self._current_episode_id=%r (%r). This is ok, but something we may want to fix in the future\", self.label, completed_episode_id, self._current_episode_id, self._reward_state)\n                self._current_episode_id = None\n            else:\n                extra_logger.info('[%s] RewardBuffer advancing: has data for next episode: %s->%s', self.label, completed_episode_id, self._current_episode_id)\n                self._drop_below(self._current_episode_id)\n        else:\n            extra_logger.info('[%s] RewardBuffer advancing: setting episode_id=None until new data received (was episode_id=%s)', self.label, completed_episode_id)\n            self._current_episode_id = None\n\n    def _drop_below(self, episode_id, quiet=False):\n        dropped = set()\n        for stored_id in self._reward_state:\n            if env_status.compare_ids(stored_id, episode_id) < 0:\n                dropped.add(stored_id)\n\n        if len(dropped) > 0:\n            if quiet:\n                log = extra_logger.debug\n            else:\n                log = extra_logger.info\n            log('[%s] RewardBuffer: dropping stale episode data: dropped=%s episode_id=%s', self.label, dropped, episode_id)\n        for stored_id in dropped:\n            del self._reward_state[stored_id]\n\n    def wait_for_step(self, error_buffer=None, timeout=None):\n        # TODO: this might be cleaner using channels\n        with self.cv:\n            start = time.time()\n            while True:\n                if self.count != 0:\n                    return\n                elif timeout is not None and time.time() - start > timeout:\n                    raise error.Error('No rewards received in {}s'.format(timeout))\n\n                if error_buffer:\n                    error_buffer.check()\n\n                self.cv.wait(timeout=0.5)\n"
  },
  {
    "path": "universe/rewarder/reward_proxy_server.py",
    "content": "import json\nimport logging\nimport os\nimport time\n\nfrom autobahn.twisted import websocket\nfrom universe.twisty import reactor\nfrom twisted.internet import endpoints\n\nlogger = logging.getLogger(__name__)\n\nclass RewardServerClient(websocket.WebSocketClientProtocol, object):\n    def __init__(self):\n        super(RewardServerClient, self).__init__()\n        self.id = -1\n\n        self.proxy_server = None\n        self._connected = False\n\n    def onConnect(self, request):\n        self.id = self.factory.proxy_server.id\n        logger.info('[RewardProxyClient] [%d] Connected to rewarder', self.id)\n        self.proxy_server = self.factory.proxy_server\n        self._connected = True\n\n        buffered = self.proxy_server.pop_buffer()\n        logger.info('[RewardProxyClient] [%d] Flushing %d buffered messages', self.id, len(buffered))\n        for msg in buffered:\n            self.sendMessage(msg)\n\n    def onOpen(self):\n        logger.info('[RewardProxyClient] [%d] Rewarder websocket connection established', self.id)\n\n    def onMessage(self, msg, isBinary):\n        logger.debug('[RewardProxyClient] [%d] Received message from server: %s', self.id, msg)\n        self.proxy_server.sendMessage(msg)\n\n        # Record the message\n        self.proxy_server.record_message(msg.decode('utf-8'), from_rewarder=True)\n\n        # # Process the message for recording\n        # method, headers, body = unpack_message(msg)\n        #\n        # if method == \"env.reward\":\n        #     # {\"body\":{\"info\":{\"episode\":0},\"reward\":0.0,\"done\":false},\n        #     # \"headers\":{\"sent_at\":1473126129.231828928,\"message_id\":207},\n        #     # \"method\":\"env.reward\"}\n\n    def onClose(self, wasClean, code, reason):\n        logger.info('[RewardProxyClient] [%d] Rewarder websocket connection closed: %s', self.id, reason)\n\n    def close(self):\n        logger.info('[RewardProxyClient] [%d] Closing connection', self.id)\n        self.transport.loseConnection()\n\n\nclass RewardProxyServer(websocket.WebSocketServerProtocol, object):\n    _next_id = 0\n    _n_open_files = 0\n\n    @classmethod\n    def next_id(cls):\n        id = cls._next_id\n        cls._next_id += 1\n        return id\n\n    def __init__(self):\n        super(RewardProxyServer, self).__init__()\n        self.id = self.next_id()\n        self.client = None\n        self.file = None  # We do not open open the file until we have established an end-to-end connection\n        self.buffered = []\n\n        self._closed = False\n\n    def pop_buffer(self):\n        \"\"\"Called by the client once it's ready to start sending messages.\n        \"\"\"\n        buffered = self.buffered\n        self.buffered = []\n        return buffered\n\n    def begin_recording(self):\n        \"\"\"\n        Open the file and write the metadata header to describe this recording. Called after we establish an end-to-end connection\n        This uses Version 1 of our protocol\n\n        Version 0 can be seen here: https://github.com/openai/universe/blob/f85a7779c3847fa86ec7bb513a1da0d3158dda78/bin/recording_agent.py\n        \"\"\"\n        logger.info(\"[RewardProxyServer] [%d] Starting recording\", self.id)\n\n        if self._closed:\n            logger.error(\n                \"[RewardProxyServer] [%d] Attempted to start writing although client connection is already closed. Aborting\", self.id)\n            self.close()\n            return\n\n        if self._n_open_files != 0:\n            logger.error(\"[RewardProxyServer] [%d] WARNING: n open rewards files = %s. This is unexpected. Dropping connection.\", self.id, self._n_open_files)\n            self.close()\n            return\n\n        logfile_path = os.path.join(self.factory.logfile_dir, 'rewards.demo')\n        logger.info('Recording to {}'.format(logfile_path))\n        self.file = open(logfile_path, 'w')\n\n        self._n_open_files += 1\n        logger.info(\"[RewardProxyServer] [%d] n open rewards files incremented: %s\", self.id, self._n_open_files)\n\n        self.file.write(json.dumps({\n            'version': 1,\n            '_debug_version': '0.0.1',  # Give this an internal version for debugging corrupt reward.demo files # TODO, pull this from setup.py or the host docker image\n        }))\n        self.file.write('\\n')\n        self.file.flush()\n\n        logger.info(\"[RewardProxyServer] [%d] Wrote version number\", self.id)\n\n    def onConnect(self, request):\n        logger.info('[RewardProxyServer] [%d] Client connecting: %s', self.id, request.peer)\n        self._request = request\n\n    def onOpen(self):\n        logger.info(\"[RewardProxyServer] [%d] Websocket connection established\", self.id)\n        self.connect_upstream()\n\n    def connect_upstream(self, tries=1, max_attempts=7):\n        if self._closed:\n            logger.info(\"[RewardProxyServer] [%d] Attempted to connect upstream although client connection is already closed. Aborting\",\n                        self.id)\n            return\n\n        remote = getattr(self.factory, 'rewarder_address', 'localhost:15900')\n        endpoint = endpoints.clientFromString(reactor, 'tcp:' + remote)\n        client_factory = websocket.WebSocketClientFactory('ws://' + remote)\n        headers = {'authorization': self._request.headers['authorization']}\n        if self._request.headers.get('openai-observer'):\n            headers['openai-observer'] = self._request.headers.get('openai-observer')\n        client_factory.headers = headers\n        client_factory.protocol = RewardServerClient\n        client_factory.proxy_server = self\n        client_factory.endpoint = endpoint\n\n        logger.info(\"[RewardProxyServer] [%d] Connecting to upstream %s (try %d/%d)\", self.id, remote, tries, max_attempts)\n\n        def _connect_callback(client):\n            logger.info('[RewardProxyServer] [%d] Upstream connection %s established', self.id, remote)\n            self.client = client\n            if self.factory.logfile_dir:\n                self.begin_recording()\n\n        def _connect_errback(reason):\n            if tries < max_attempts:\n                # Somewhat arbitrary exponential backoff: should be\n                # pretty rare, and indicate that we're just starting\n                # up.\n                delay = 1.5 ** tries\n                logger.info('[RewardProxyServer] [%d] Connection to %s failed: %s. Try %d/%d; going to retry in %fs', self.id, remote, reason, tries, max_attempts, delay)\n                reactor.callLater(\n                    delay, self.connect_upstream,\n                    tries=tries+1, max_attempts=max_attempts)\n            else:\n                logger.error('[RewardProxyServer] [%d] Connection to %s failed: %s. Completed %d/%d atttempts; disconnecting.', self.id, remote, reason, tries, max_attempts)\n                self.transport.loseConnection()\n\n        endpoint.connect(client_factory).addCallbacks(_connect_callback, _connect_errback)\n\n    def close(self):\n        logger.info('[RewardProxyServer] [%d] Closing...', self.id)\n        self.transport.loseConnection()\n\n    def onClose(self, wasClean, code, reason):\n        logger.info('[RewardProxyServer] [%d] Client connection closed: %s', self.id, reason)\n        if self.client:\n            self.client.close()\n        if self.file:\n            self.file.close()\n\n        self._closed = True\n\n    def onMessage(self, msg, binary):\n        logger.debug('[RewardProxyServer] [%d] Received message from client: %s', self.id, msg)\n\n        # Pass the message on to the client\n        if self.client and self.client._connected:\n            self.client.sendMessage(msg)\n        else:\n            self.buffered.append(msg)\n\n        self.record_message(msg.decode('utf-8'), from_rewarder=False)\n\n    def record_message(self, msg, from_rewarder):\n        \"\"\"Record a message to our rewards.demo file if it is has been opened\"\"\"\n        if self.file:\n            # Include an authoritative timestamp (because the `sent_at` from the server is likely to be different\n            timestamped_message = {\n                'timestamp': time.time(),\n                'message': json.loads(msg),\n                'from_rewarder': from_rewarder,\n            }\n            self.file.write(json.dumps(timestamped_message))\n            self.file.write('\\n')\n            self.file.flush()\n"
  },
  {
    "path": "universe/rewarder/rewarder_client.py",
    "content": "import logging\nfrom universe import pyprofile\nimport time\nimport ujson\n\nfrom autobahn.twisted import websocket\nfrom twisted.internet import defer\n\nfrom universe import error\n\nlogger = logging.getLogger(__name__)\nextra_logger = logging.getLogger('universe.extra.'+__name__)\n\nclass RemoteError(error.Error):\n    pass\n\nclass RewarderClient(websocket.WebSocketClientProtocol):\n    def __init__(self):\n        super(RewarderClient, self).__init__()\n        self._closed = False\n        self._close_message = None\n\n        self._connected = False\n        self._requests = {}\n\n        self._reset = None\n        self._initial_reset = False\n\n        self._connection_result = defer.Deferred()\n\n    def send_reset(self, env_id, seed, fps, episode_id):\n        self._initial_reset = True\n        self._reset = {\n            'env_id': env_id,\n            'fps': fps,\n            'episode_id': episode_id,\n        }\n\n        return self.send('v0.env.reset', {\n            'seed': seed,\n            'env_id': env_id,\n            'fps': fps,\n        }, {'episode_id': episode_id}, expect_reply=True)\n\n    def _finish_reset(self, episode_id):\n        extra_logger.info('[%s] Running finish_reset: %s', self.factory.label, episode_id)\n        self.reward_buffer.reset(episode_id)\n\n    def onConnect(self, request):\n        self._message_id = 0\n        self._requests = {}\n\n        self.reward_buffer = self.factory.reward_buffer\n\n        assert not self._connection_result.called\n        self._connection_result.callback(self)\n        self._connected = True\n\n    def waitForWebsocketConnection(self):\n        return self._connection_result\n\n    def send(self, method, body, headers=None, expect_reply=False):\n        if headers is None:\n            headers = {}\n        if self._closed:\n            error_message = \"Can't send message to closed connection\"\n            if self._close_message:\n                error_message += \": {}\".format(self._close_message)\n            e = error.Error(error_message)\n            if expect_reply:\n                return defer.fail(e)\n            else:\n                raise e\n\n        id = self._message_id\n\n        self._message_id += 1\n        new_headers = {\n            'message_id': id,\n            'sent_at': time.time(),\n        }\n        new_headers.update(headers)\n\n        payload = {\n            'method': method,\n            'body': body,\n            'headers': new_headers,\n        }\n\n        extra_logger.info('[%s] Sending message to rewarder: %s', self.factory.label, payload)\n        self.sendMessage(ujson.dumps(payload).encode('utf-8'), False)\n\n        if expect_reply:\n            d = defer.Deferred()\n            self._requests[id] = (payload, d)\n            return d\n        else:\n            return None\n\n    def _manual_recv(self, method, body, headers={}):\n        \"\"\"Used in the tests\"\"\"\n        headers.setdefault('sent_at', time.time())\n        return self.recv(self._make_context(), {'method': method, 'body': body, 'headers': headers})\n\n    def recv(self, context, response):\n        method = response['method']\n        body = response['body']\n        headers = response['headers']\n\n        remote_time = headers['sent_at']\n        local_time = context['start']\n\n        episode_id = headers.get('episode_id')\n        if episode_id is not None:\n            self.reward_buffer.push_time(episode_id, remote_time, local_time)\n\n        # Gets called by RewarderClient\n        if method == 'v0.env.reward':\n            episode_id = headers['episode_id']\n            reward = body['reward']\n            done = body['done']\n            info = body['info']\n            extra_logger.debug('[%s] Received %s: reward=%s done=%s info=%s episode_id=%s', self.factory.label, method, reward, done, info, episode_id)\n            pyprofile.incr('rewarder_client.reward', reward)\n            if done:\n                pyprofile.incr('rewarder_client.done')\n            self.reward_buffer.push(episode_id, reward, done, info)\n        elif method == 'v0.env.text':\n            episode_id = headers['episode_id']\n            text = body['text']\n            extra_logger.debug('[%s] Received %s: text=%s episode_id=%s', self.factory.label, method, text, episode_id)\n            self.reward_buffer.push_text(episode_id, text)\n        elif method == 'v0.env.observation':\n            episode_id = headers['episode_id']\n            jsonable = body['observation']\n            extra_logger.debug('[%s] Received %s: observation=%s episode_id=%s', self.factory.label, method, jsonable, episode_id)\n            self.reward_buffer.set_observation(episode_id=episode_id, observation=jsonable)\n        elif method == 'v0.env.describe':\n            episode_id = headers['episode_id']\n            env_id = body['env_id']\n            env_state = body['env_state']\n            fps = body['fps']\n            extra_logger.info('[%s] Received %s: env_id=%s env_state=%s episode_id=%s',\n                              self.factory.label, method, env_id, env_state, episode_id)\n            self.reward_buffer.set_env_info(env_state, env_id=env_id, episode_id=episode_id, fps=fps)\n        elif method == 'v0.reply.env.reset':\n            episode_id = headers['episode_id']\n            self._finish_reset(episode_id)\n        elif method in ['v0.reply.error', 'v0.reply.control.ping']:\n            assert headers.get('parent_message_id') is not None\n        elif method == 'v0.connection.close':\n            assert headers.get('parent_message_id') is None\n            logger.debug('Server hanging up: %s', body['message'])\n\n            self._close_message = body['message']\n            e = error.Error(body['message'])\n            self.factory.record_error(e)\n        else:\n            logger.error('Unrecognized websocket method: method=%s body=%s headers=%s (consider adding to rewarder_state.py)', method, body, headers)\n            return\n\n        parent_id = headers.get('parent_message_id')\n        if parent_id is not None:\n            try:\n                spec = self._requests.pop(parent_id)\n            except KeyError:\n                logger.error('[%s] Received extra reply to %d; ignoring: method=%s body=%s headers=%s ', self.factory.label, parent_id, method, body, headers)\n            else:\n                request, d = spec\n                if method != 'v0.reply.error':\n                    d.callback((context, request, response))\n                else:\n                    e = RemoteError('[{}] Remote error: {}'.format(self.factory.label, body['message']))\n                    d.errback(e)\n\n    def _make_context(self):\n        return {'start': time.time()}\n\n    def onMessage(self, payload, isBinary):\n        extra_logger.debug('[%s] Received payload: %s', self.factory.label, payload)\n        assert not isBinary\n        payload = ujson.loads(payload)\n\n        context = self._make_context()\n        latency = context['start'] - payload['headers']['sent_at']\n        pyprofile.incr('rewarder_protocol.messages')\n        pyprofile.incr('rewarder_protocol.messages.{}'.format(payload['method']))\n\n        # Double latency to model RTT\n        pyprofile.timing('rewarder_protocol.latency.rtt.skew_unadjusted', 2*latency)\n        if latency < 0:\n            pyprofile.incr('rewarder_protocol.latency.rtt.skew_unadjusted.negative')\n\n        self.recv(context, payload)\n\n    def onClose(self, wasClean, code, reason):\n        if self._close_message:\n            return\n\n        if not self._connected:\n            assert not self._connection_result.called\n            self._connection_result.errback(error.ConnectionError(reason))\n            return\n\n        if not self._closed:\n            error_message = 'Lost connection: {} (clean={} code={})'.format(reason, wasClean, code)\n            reason = error.Error(error_message)\n            # TODO: it's not an error if we requested it\n            self.factory.record_error(reason)\n        else:\n            reason = error.Error(\"We closed the connection: {}\".format(reason))\n\n        for request, d in self._requests.values():\n            d.errback(reason)\n\n    def close(self, code=1000, reason=None):\n        self._closed = True\n        extra_logger.info('[%s] Client closing websocket connection because of call to close(code=%s, reason=%s)', self.factory.label, code, reason)\n        self.sendClose(code, reason)\n        self.transport.loseConnection()\n"
  },
  {
    "path": "universe/rewarder/rewarder_session.py",
    "content": "from autobahn.twisted import websocket\nimport logging\nimport numpy as np\nimport threading\nimport time\n\nfrom twisted.python import failure\nfrom twisted.internet import defer, endpoints\nimport twisted.internet.error\n\nfrom universe import utils\nfrom universe.twisty import reactor\nfrom universe.rewarder import connection_timer, env_status, reward_buffer, rewarder_client\nfrom universe.utils import display\n\nlogger = logging.getLogger(__name__)\nextra_logger = logging.getLogger('universe.extra.'+__name__)\n\ndef _ping(client):\n    return client.send('v0.control.ping', {}, expect_reply=True)\n\nclass RewarderSession(object):\n    def __init__(self):\n        self.lock = threading.RLock()\n\n        self.i = 0\n\n        # Mutated by main thread exclusively\n        self.names_by_id = {}\n        self.reward_buffers = {}\n        self.env_statuses = {}\n        self.errors = {}\n        self.networks = {}\n\n        self.clients = {}\n\n    def close(self, name=None, reason=u'closed by RewarderSession.close'):\n        if name is None:\n            names = list(self.names_by_id.values())\n        else:\n            logger.info('[%s] Closing rewarder connection', name)\n            names = [name]\n        self.ids_by_name = {name: id for id, name in self.names_by_id.items()}\n\n        for name in names:\n            with self.lock:\n                id = self.ids_by_name.pop(name, None)\n                if id is None:\n                    # already closed\n                    continue\n\n                del self.names_by_id[id]\n                del self.reward_buffers[id]\n                del self.env_statuses[id]\n                self.errors.pop(id, None)\n\n                network = self.networks.pop(id)\n                network.close()\n\n                client = self.clients.pop(id, None)\n                if client is not None:\n                    reactor.callFromThread(client.close, reason=reason)\n\n    def connect(self, name, address, label, password, env_id=None, seed=None, fps=60,\n                start_timeout=None, observer=False, skip_network_calibration=False):\n        if name in self.reward_buffers:\n            self.close(name, reason='closing previous connection to reconnect with the same name')\n\n        network = Network()\n        self.names_by_id[self.i] = name\n        self.reward_buffers[self.i] = reward_buffer.RewardBuffer(label)\n        self.env_statuses[self.i] = env_status.EnvStatus(label=label, primary=False)\n        self.networks[self.i] = network\n\n        reactor.callFromThread(self._connect,\n                               name=name,\n                               address=address,\n                               env_id=env_id,\n                               seed=seed,\n                               fps=fps,\n                               i=self.i,\n                               network=network,\n                               env_status=self.env_statuses[self.i],\n                               reward_buffer=self.reward_buffers[self.i],\n                               label=label,\n                               start_timeout=start_timeout,\n                               password=password,\n                               observer=observer,\n                               skip_network_calibration=skip_network_calibration,\n        )\n        self.i += 1\n        return network\n\n    def _already_closed(self, i):\n        # Lock must be held\n        return i not in self.names_by_id\n\n    # Call only from Twisted thread\n\n    # TODO: probably time to convert to kwargs\n    @defer.inlineCallbacks\n    def _connect(self, name, address, env_id, seed, fps, i, network, env_status, reward_buffer,\n                 label, password, start_timeout,\n                 observer, skip_network_calibration,\n                 attempt=0, elapsed_sleep_time=0,\n    ):\n        endpoint = endpoints.clientFromString(reactor, 'tcp:'+address)\n        factory = websocket.WebSocketClientFactory('ws://'+address)\n        factory.protocol = rewarder_client.RewarderClient\n\n        assert password, \"Missing password: {} for rewarder session\".format(password)\n        factory.headers = {'authorization': utils.basic_auth_encode(password), 'openai-observer': 'true' if observer else 'false'}\n        factory.i = i\n\n        # Various important objects\n        factory.endpoint = endpoint\n        factory.env_status = env_status\n        factory.reward_buffer = reward_buffer\n\n        # Helpful strings\n        factory.label = label\n        factory.address = address\n\n        # Arguments to always send to the remote reset call\n        factory.arg_env_id = env_id\n        factory.arg_fps = fps\n\n        def record_error(e):\n            if isinstance(e, failure.Failure):\n                e = e.value\n\n            # logger.error('[%s] Recording rewarder error: %s', factory.label, e)\n            with self.lock:\n                # drop error on the floor if we're already closed\n                if self._already_closed(factory.i):\n                    extra_logger.info('[%s] Ignoring error for already closed connection: %s', label, e)\n                elif factory.i not in self.clients:\n                    extra_logger.info('[%s] Received error for connection which has not been fully initialized: %s', label, e)\n                    # We could handle this better, but right now we\n                    # just mark this as a fatal error for the\n                    # backend. Often it actually is.\n                    self.errors[factory.i] = e\n                else:\n                    extra_logger.info('[%s] Recording fatal error for connection: %s', label, e)\n                    self.errors[factory.i] = e\n\n        def retriable_error(e, error_message):\n            if isinstance(e, failure.Failure):\n                e = e.value\n\n            if self._already_closed(factory.i):\n                logger.error('[%s] Got error, but giving up on reconnecting, since %d already disconnected', factory.label, factory.i)\n                return\n\n            # Also need to handle DNS errors, so let's just handle everything for now.\n            #\n            # reason.trap(twisted.internet.error.ConnectError, error.ConnectionError)\n            if elapsed_sleep_time < start_timeout:\n                sleep = min((2 * attempt+1), 10)\n                logger.error('[%s] Waiting on rewarder: %s. Retry in %ds (slept %ds/%ds): %s', factory.label, error_message, sleep, elapsed_sleep_time, start_timeout, e)\n                reactor.callLater(\n                    sleep, self._connect, name=name, address=address,\n                    env_id=env_id, seed=seed, fps=fps, i=i, network=network,\n                    env_status=env_status, reward_buffer=reward_buffer, label=label,\n                    attempt=attempt+1, elapsed_sleep_time=elapsed_sleep_time+sleep,\n                    start_timeout=start_timeout, password=password,\n                    observer=observer, skip_network_calibration=skip_network_calibration,\n                )\n            else:\n                logger.error('[%s] %s. Retries exceeded (slept %ds/%ds): %s', factory.label, error_message, elapsed_sleep_time, start_timeout, e)\n                record_error(e)\n\n        factory.record_error = record_error\n\n        try:\n            retry_msg = 'establish rewarder TCP connection'\n            client = yield endpoint.connect(factory)\n            extra_logger.info('[%s] Rewarder TCP connection established', factory.label)\n\n            retry_msg = 'complete WebSocket handshake'\n            yield client.waitForWebsocketConnection()\n            extra_logger.info('[%s] Websocket client successfully connected', factory.label)\n\n            if not skip_network_calibration:\n                retry_msg = 'run network calibration'\n                yield network.calibrate(client)\n                extra_logger.info('[%s] Network calibration complete', factory.label)\n\n            retry_msg = ''\n\n            if factory.arg_env_id is not None:\n                # We aren't picky about episode ID: we may have\n                # already receieved an env.describe message\n                # telling us about a resetting environment, which\n                # we don't need to bump post.\n                #\n                # tl;dr hardcoding 0.0 here avoids a double reset.\n                reply = yield self._send_env_reset(client, seed=seed, episode_id='0')\n            else:\n                # No env_id requested, so we just proceed without a reset\n                reply = None\n            # We're connected and have measured the\n            # network. Mark everything as ready to go.\n            with self.lock:\n                if factory.i not in self.names_by_id:\n                    # ID has been popped!\n                    logger.info('[%s] Rewarder %d started, but has already been closed', factory.label, factory.i)\n                    client.close(reason='RewarderSession: double-closing, client was closed while RewarderSession was starting')\n                elif reply is None:\n                    logger.info('[%s] Attached to running environment without reset', factory.label)\n                else:\n                    context, req, rep = reply\n                    logger.info('[%s] Initial reset complete: episode_id=%s', factory.label, rep['headers']['episode_id'])\n                self.clients[factory.i] = client\n        except Exception as e:\n            if retry_msg:\n                retriable_error(e, 'failed to ' + retry_msg)\n            else:\n                record_error(e)\n\n    def pop_errors(self):\n        errors = {}\n        with self.lock:\n            if self.errors:\n                for i, error in self.errors.items():\n                    name = self.names_by_id[i]\n                    errors[name] = error\n                self.errors.clear()\n        return errors\n\n    def reset(self, seed=None, env_id=None):\n        with self.lock:\n            for i, reward_buffer in self.reward_buffers.items():\n                reward_buffer.mask()\n        reactor.callFromThread(self._reset, seed=seed, env_id=env_id)\n\n    def _reset(self, seed=None, env_id=None):\n        with self.lock:\n            for client in self.clients.values():\n                d = self._send_env_reset(client, seed=seed, env_id=env_id)\n                # Total hack to capture the variable in the closure\n                def callbacks(client):\n                    def success(reply): pass\n                    def fail(reason): client.factory.record_error(reason)\n                    return success, fail\n                success, fail = callbacks(client)\n                d.addCallback(success)\n                d.addErrback(fail)\n\n    def _send_env_reset(self, client, seed=None, episode_id=None, env_id=None):\n        if episode_id is None:\n            episode_id = client.factory.env_status.episode_id\n        logger.info('[%s] Sending reset for env_id=%s fps=%s episode_id=%s', client.factory.label, client.factory.arg_env_id, client.factory.arg_fps, episode_id)\n        return client.send_reset(\n            env_id=client.factory.arg_env_id if env_id is None else env_id,\n            seed=seed,\n            fps=client.factory.arg_fps,\n            episode_id=episode_id)\n\n    def pop(self, warn=True, peek_d=None):\n        reward_d = {}\n        done_d = {}\n        info_d = {}\n        err_d = self.pop_errors()\n\n        for i, reward_buffer in self.reward_buffers.items():\n            name = self.names_by_id[i]\n\n            reward, done, info = reward_buffer.pop(peek_d.get(name))\n            reward_d[name] = reward\n            done_d[name] = done\n            info_d[name] = info\n\n        # TODO: use FPS here rather than 60\n        if warn and any(info.get('stats.reward.count', 0) > 60 for info in info_d.values()):\n            logger.warn('WARNING: returning more than 60 aggregated rewards: %s. Either your agent is not keeping up with the framerate, or you should have called \".reset()\" to clear pending rewards and reset the environments to a known state.',\n                        {name: '{} (episode_id={})'.format(info['stats.reward.count'], info.get('env_status.episode_id')) for name, info in info_d.items()})\n\n        return reward_d, done_d, info_d, err_d\n\n    def wait(self, timeout=None):\n        deadline = time.time() + timeout\n        for client in self.clients:\n            if timeout is not None:\n                remaining_timeout = deadline - time.time()\n            else:\n                remaining_timeout = None\n            client.reward_buffer.wait_for_step(timeout=remaining_timeout)\n\n    # Hack to test actions over websockets\n    # TODO: Carve websockets out of rewarder pkg (into vnc_env? - and move this there)\n    def send_action(self, action_n, env_id):\n        reactor.callFromThread(self._send_action, env_id, action_n)\n        return self.pop_errors()\n\n    def _send_action(self, env_id, action_n):\n        with self.lock:\n            for n, client in zip(action_n, self.clients.values()):\n                self._send_env_action(client, env_id, action_n[n])\n\n    def _send_env_action(self, client, env_id, action_n):\n        if len(action_n) == 0:\n            # Hack to skip empty actions. TODO: Find source (throttle?) and fix\n            return\n        message = {\n            'env_id': env_id,\n            'action': action_n,\n        }\n        client.send('v0.agent.action', message, expect_reply=False)\n\n    def rewards_count(self):\n        # TODO: any reason to lock these?\n        return [client.reward_buffer.count for client in self.clients]\n\n    def pop_observation(self):\n        return [client.reward_buffer.pop_observation() for client in self.clients]\n\n    # def _connection_time(self):\n    #     deferreds = []\n    #     for client in self.clients:\n    #         endpoint = client.factory.endpoint\n    #         d = connection_timer.start(endpoint)\n    #         deferreds.append(d)\n\n    #     d = defer.DeferredList(deferreds, fireOnOneErrback=True, consumeErrors=True)\n    #     return d\n\n# Run this in Twisty therad\nclass Network(object):\n    def __init__(self):\n        self.connection_samples = 10\n        self.application_ping_samples = 10\n\n        self.connection_time_m = None\n        self.lock = threading.Lock()\n\n        self.recalibrate = None\n        self.client = None\n\n        self._ntpdate_reversed_clock_skew = None\n        self._reversed_clock_skew = None\n\n    def active(self):\n        with self.lock:\n            return self._reversed_clock_skew is not None\n\n    # Used by external consumers\n    def reversed_clock_skew(self):\n        with self.lock:\n            if self._ntpdate_clock_skew is not None:\n                return self._ntpdate_reversed_clock_skew\n            else:\n                return self._reversed_clock_skew\n\n    def _report(self):\n        connection_time = display.display_timestamps(self.connection_time_m)\n        if self._ntpdate_clock_skew is not None:\n            ntpdate_clock_skew = display.display_timestamp(self._ntpdate_clock_skew[0])\n        else:\n            ntpdate_clock_skew = None\n        clock_skew = display.display_timestamps_pair(self.clock_skew_m)\n        application_rtt = display.display_timestamps(self.application_rtt_m)\n        request_overhead = display.display_timestamps(self.request_overhead_m)\n        response_overhead = display.display_timestamps(self.response_overhead_m)\n\n        extra_logger.info('[%s] Network calibration: ntpdate_clock_skew=%s clock_skew=%s connection_time=%s application_rtt=%s request_overhead=%s response_overhead=%s',\n                    self.client.factory.label, ntpdate_clock_skew, clock_skew, connection_time, application_rtt,\n                    request_overhead, response_overhead)\n\n    def _start(self):\n        def calibrate():\n            d = defer.Deferred()\n            def fail(reason):\n                logger.error('[%s] Could not recalibrate network: %s', self.client.factory.label, reason)\n            d.addErrback(fail)\n            self._start_measure_connection_time(d)\n            self._start()\n        self.recalibrate = reactor.callLater(5 * 60, calibrate)\n\n    def close(self):\n        if self.recalibrate:\n            try:\n                self.recalibrate.cancel()\n            except twisted.internet.error.AlreadyCalled:\n                pass\n\n    # Called externally\n    def calibrate(self, client):\n        d = defer.Deferred()\n        def success(res):\n            # If we succeed, kick off the periodic 5 minute\n            # recalibrations.\n            self._start()\n            return res\n        d.addCallback(success)\n\n        self.client = client\n\n        # Kinda a hack. Idea is to try using the ntpdate -q offset if\n        # we can.\n        skew = self._start_measure_clock_skew()\n        def succeed(offset):\n            with self.lock:\n                self._ntpdate_clock_skew = np.array([offset, offset])\n                self._ntpdate_reversed_clock_skew = np.array([-offset, -offset])\n            self._start_measure_connection_time(d)\n        skew.addCallback(succeed)\n\n        def fail(reason):\n            with self.lock:\n                self._ntpdate_clock_skew = None\n                self._ntpdate_reversed_clock_skew = None\n\n            extra_logger.info('[%s] Could not determine clock skew with ntpdate; falling back to application-level ping: %s', self.client.factory.label, reason.value)\n            self._start_measure_connection_time(d)\n        skew.addErrback(fail)\n\n        return d\n\n    def _start_measure_connection_time(self, d):\n        connection_time_m = np.zeros(self.connection_samples)\n        self._measure_connection_time(d, connection_time_m, 0)\n\n    def _measure_connection_time(self, d, connection_time_m, i):\n        extra_logger.debug('[%s] Measuring connection time (%d/%d)', self.client.factory.label, i+1, len(connection_time_m))\n        endpoint = self.client.factory.endpoint\n        timer = connection_timer.start(endpoint)\n\n        def success(delta):\n            connection_time_m[i] = delta\n            if i+1 < len(connection_time_m):\n                self._measure_connection_time(d, connection_time_m, i+1)\n            else:\n                self.connection_time_m = connection_time_m\n                self._start_measure_application_ping(d)\n        def fail(reason):\n            d.errback(reason)\n        timer.addCallback(success)\n        timer.addErrback(fail)\n\n    def _start_measure_application_ping(self, d=None):\n        clock_skew_m = np.zeros((self.application_ping_samples, 2))\n        request_overhead_m = np.zeros((self.application_ping_samples))\n        response_overhead_m = np.zeros((self.application_ping_samples))\n        application_rtt_m = np.zeros((self.application_ping_samples))\n\n        self._measure_application_ping(d, clock_skew_m, request_overhead_m, response_overhead_m, application_rtt_m, 0)\n\n    def _measure_application_ping(self, d, clock_skew_m, request_overhead_m, response_overhead_m, application_rtt_m, i):\n        extra_logger.debug('[%s] Issuing an application-level ping (%d/%d)', self.client.factory.label, i+1, len(clock_skew_m))\n        start = time.time()\n        ping = _ping(self.client)\n\n        def success(res):\n            context, request, response = res\n            end = time.time()\n\n            request_sent_at = request['headers']['sent_at'] # local\n            response_sent_at = response['headers']['sent_at'] # remote\n            response_received_at = context['start'] # local\n\n            # We try to put bounds on clock skew by subtracting\n            # local and remote times, for local and remote events\n            # that are causally related.\n            #\n            # For example, suppose that the following local/remote\n            # logical timestamps apply to a request (for a system\n            # with clock skew of 100):\n            #\n            # request_sent       local: 0   remote: 100\n            # request_recieved   local: 1   remote: 101\n            # response_sent      local: 2   remote: 102\n            # response_received  local: 3   remote: 103\n            #\n            # Then:\n            #\n            # # Remote event *after* local is upper bound\n            # request_recieved.remote - request_sent.local = 101\n            # # Remote event *before* local is lower bound\n            # response_sent.remote - response_received.local = 102 - 3 = 99\n            #\n            # There's danger of further clock drift over time, but\n            # we don't need these to be fully accurate, and this\n            # should be fine for now.\n            clock_skew_m[i, :] = (response_sent_at-response_received_at, response_sent_at-request_sent_at)\n            request_overhead_m[i] = request_sent_at - start\n            response_overhead_m[i] = end - response_received_at\n            application_rtt_m[i] = response_received_at - request_sent_at\n\n            if i+1 < len(clock_skew_m):\n                self._measure_application_ping(d, clock_skew_m, request_overhead_m, response_overhead_m, application_rtt_m, i+1)\n            else:\n                self.clock_skew_m = clock_skew_m\n                self.request_overhead_m = request_overhead_m\n                self.response_overhead_m = response_overhead_m\n                self.application_rtt_m = application_rtt_m\n\n                self._report()\n                self._update_exposed_metrics()\n\n                # Ok, all done!\n                if d is not None:\n                    d.callback(self)\n        ping.addCallback(success)\n        ping.addErrback(d.errback)\n\n    def _update_exposed_metrics(self):\n        with self.lock:\n            self._clock_skew = self.clock_skew_m.mean(axis=0) # add to local time to get remote time, as (min, max) values\n            self._reversed_clock_skew = -self._clock_skew[[1, 0]] # add to remote time to get local time, in format (min, max)\n\n\n    def _start_measure_clock_skew(self):\n        host = self.client.factory.address.split(':')[0]\n        return connection_timer.measure_clock_skew(self.client.factory.label, host)\n"
  },
  {
    "path": "universe/rewarder/tests/test_reward_buffer.py",
    "content": "from universe.rewarder import reward_buffer\n\ndef test_prereset():\n    buf = reward_buffer.RewardBuffer('buf')\n    buf.push('1', 2, False, {'key': 'value'})\n    reward, done, info = buf.pop()\n    assert reward == 0\n    assert done is False\n    print(info)\n\ndef test_mask_peek():\n    buf = reward_buffer.RewardBuffer('buf')\n    buf.set_env_info('running', 'test-v0', '1', fps=60)\n    buf.push('1', 1, False, {'key': 'value'})\n    reward, done, info = buf.pop(peek=True)\n    assert info['env_status.episode_id'] is None\n    assert info['env_status.env_state'] is None\n    assert info['env_status.peek.episode_id'] is None\n    assert info['env_status.peek.env_state'] is None\n\ndef test_single():\n    buf = reward_buffer.RewardBuffer('buf')\n    buf.reset('1')\n    buf.push('1', 1, False, {'key': 'value'})\n    reward, done, info = buf.pop()\n    assert reward == 1.0\n    assert done is False\n    assert info['key'] == 'value'\n    assert info['env_status.episode_id'] == '1'\n    assert info['env_status.reset.episode_id'] == '1'\n    assert info['env.text'] == []\n\ndef test_multiple():\n    buf = reward_buffer.RewardBuffer('buf')\n    buf.reset('1')\n    buf.push('1', 1, False, {'key': 'value1'})\n    buf.push_text('1', 'text1')\n\n    buf.push('2', 2, False, {'key': 'value2'})\n    buf.push_text('2', 'text2')\n    buf.push_text('2', 'text3')\n    reward, done, info = buf.pop()\n    assert reward == 1.0 # old\n    assert done is True # old\n    assert info['key'] == 'value1', 'Info: {}'.format(info) # old\n    assert info['env_status.episode_id'] == '2', 'got: {}, expected: {}'.format(info['env_status.episode_id'], '1')\n    assert info['env_status.complete.episode_id'] == '1'\n    assert info['env_status.reset.episode_id'] == '1'\n    assert info['env.text'] == ['text2', 'text3'] # new\n\n    reward, done, info = buf.pop()\n    assert reward == 2.0 # new\n    assert done is False\n    assert info['key'] == 'value2'\n    assert info['env_status.episode_id'] == '2'\n    assert 'env_status.reset.episode_id' not in info\n    assert info['env.text'] == []\n\ndef test_double_reset():\n    buf = reward_buffer.RewardBuffer('buf')\n    buf.reset('1')\n    buf.set_env_info('running', 'test-v0', '1', fps=60)\n    buf.push('1', 1, False, {'key': 'value1'})\n    buf.set_env_info('resetting', 'test-v0', '2', fps=60)\n    buf.push('2', 20, False, {'key': 'value2'})\n\n    reward, done, info = buf.pop(peek=True)\n    assert reward == 0\n    assert done == False\n    assert 'env_status.artificial.done' not in info\n    assert info['env_status.episode_id'] == '1'\n    assert info['env_status.env_state'] == 'running'\n    assert info['env_status.peek.episode_id'] == '2'\n    assert info['env_status.peek.env_state'] == 'resetting'\n\n    buf.set_env_info('running', 'test-v0', '2', fps=60)\n\n    reward, done, info = buf.pop(peek=True)\n    assert reward == 0\n    assert done == False\n    assert 'env_status.artificial.done' not in info\n    assert info['env_status.episode_id'] == '1'\n    assert info['env_status.env_state'] == 'running'\n    assert info['env_status.peek.episode_id'] == '2'\n    assert info['env_status.peek.env_state'] == 'running'\n"
  },
  {
    "path": "universe/runtimes/.agignore",
    "content": "flashgames.json\n"
  },
  {
    "path": "universe/runtimes/__init__.py",
    "content": "import os\nimport yaml\n\nfrom universe.runtimes.registration import register_runtime\n\nwith open(os.path.join(os.path.dirname(__file__), '../runtimes.yml')) as f:\n    spec = yaml.load(f)\n\n# If you have a local repo, do something like\n# export OPENAI_DOCKER_REPO=docker.openai.com  (this one only for openai folks)\ndocker_repo = os.environ.get('OPENAI_DOCKER_REPO', 'quay.io/openai')\n\nregister_runtime(\n    id='gym-core',\n    kind='docker',\n    image=docker_repo + '/universe.gym-core:{}'.format(spec['gym-core']['tag']),\n)\n\nregister_runtime(\n    id='flashgames',\n    kind='docker',\n    image=docker_repo + '/universe.flashgames:{}'.format(spec['flashgames']['tag']),\n    host_config={\n        'privileged': True,\n        'cap_add': ['SYS_ADMIN'],\n        'ipc_mode': 'host',\n    },\n    default_params={'cpu': 3.9, 'livestream_url': None},\n    server_registry_file=os.path.join(os.path.dirname(__file__), 'flashgames.json'),\n)\n\nregister_runtime(\n    id='world-of-bits',\n    kind='docker',\n    image=docker_repo + '/universe.world-of-bits:{}'.format(spec['world-of-bits']['tag']),\n    host_config={\n        'privileged': True,\n        'cap_add': ['SYS_ADMIN'],\n        'ipc_mode': 'host'\n    })\n\nregister_runtime(\n    id='vnc-windows',\n    kind='windows',\n)\n\ndel spec\n"
  },
  {
    "path": "universe/runtimes/flashgames.json",
    "content": "{\"flashgames.StealthboundLevelPack-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.StealthboundLevelPack-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000085\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cede3579d6.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Scribble2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Scribble2-v0\", \"human_url\": \"http://armorgames.com/play/52\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/scribble-2-52.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Sirtet-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Sirtet-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000067\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570ce9beca345.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpacePunkRacerLvl8-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.SpacePunkRacerLvl8-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/space-punk-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0012/4902/live/embeddable_124902.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.StreetRace-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.StreetRace-v0\", \"human_url\": \"http://www.kongregate.com/games/fightclub69/street-race\", \"regions\": null, \"height\": 300, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"https://cdn2.kongcdn.com/game_icons/0044/5801/250x200.jpg?i10c=img.resize(width:171,height:137)\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GalacticGems2-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\", \"match 3\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GalacticGems2-v0\", \"human_url\": \"http://www.kongregate.com/games/MikRad/galactic-gems-2\", \"regions\": null, \"height\": 527, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0016/0474/live/Galactic_Gems_2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SistersOfNoMercy-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SistersOfNoMercy-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Sisters-Of-No-Mercy,576742227280295889\", \"regions\": null, \"height\": 880, \"width\": 660, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://games.cdn.spilcloud.com/s/sistersOfNoMercy_final.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Popopop2-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\", \"bubble\", \"mouse only\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Popopop2-v0\", \"human_url\": \"http://www.kongregate.com/games/Rob_Almighty/popopop-2\", \"regions\": null, \"height\": 600, \"width\": 620, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0005/6988/live/Popopop2.3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MonsterRun-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MonsterRun-v0\", \"human_url\": \"http://www.gamesbutler.com/game/4042/monster-run/\", \"regions\": null, \"height\": 420, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/b793232686691e2c.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Kinetikz3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Kinetikz3-v0\", \"human_url\": \"http://armorgames.com/play/3291\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/kinetikz-3-3291.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CircuitSuperCarsRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CircuitSuperCarsRacing-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/Circuit-Super-Cars-Racing.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/d/file/20140319/988b598450345d60587bb54afd459965.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GunnerMayhem-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"adventure\", \"our\", \"shooting\", \"2 player\", \"2pg\", \"highscore\", \"shooter\", \"survive\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GunnerMayhem-v0\", \"human_url\": \"http://old.2pg.com/game/gunner-mayhem/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/G/gunner-mayhem.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JellySnake-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JellySnake-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/jelly-snake\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/39935/game.swf?1397469707\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacerLvl2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacerLvl2-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/3927/live/embeddable_93927.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GasSand-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GasSand-v0\", \"human_url\": \"http://www.miniclip.com/games/gas-and-sand/en/\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PunchBallJump-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PunchBallJump-v0\", \"human_url\": \"http://old.2pg.com/game/punch-ball-jump/play/\", \"regions\": null, \"height\": 525, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/P/punch-ball-jump.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FiveTil-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FiveTil-v0\", \"human_url\": \"http://armorgames.com/play/43\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/five-til-43.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EasterBunnyEggs-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"action\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EasterBunnyEggs-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Easter-Bunny-Eggs,576742227280291408\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://games.cdn.spilcloud.com/container_df9aa4793b5/1396454361_easter_bunny_eggs_spil.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FormulaRacerLvl5-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FormulaRacerLvl5-v0\", \"human_url\": \"http://www.kongregate.com/games/turboNuke/formula-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0010/9268/live/FormulaRacer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SweetTooth-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SweetTooth-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/sweet-tooth\", \"regions\": null, \"height\": 390, \"width\": 520, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/3129/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AssembleBots-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AssembleBots-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25225\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae260366384.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MexicoRex-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MexicoRex-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25637\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eeb3bd1663.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MonkeyGems-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.MonkeyGems-v0\", \"human_url\": \"http://www.arkadium.com/games/monkey-gems/\", \"regions\": null, \"height\": 444, \"width\": 640, \"extra_files\": {\"relative\": {\"files\": [\"data/monkeygems_config.xml\", \"data/monkeygems_leveldata_en-US.xml\", \"data/monkeygems_sounds.xml\", \"data/levels/level0.xml\", \"data/levels/level2.xml\", \"data/resources.swf\", \"data/levels/minigame2.xml\", \"data/levels/level3.xml\", \"data/levels/level4.xml\", \"data/levels/level5.xml\", \"data/levels/level6.xml\", \"data/levels/level7.xml\", \"data/levels/level8.xml\", \"data/levels/level9.xml\", \"data/levels/level10.xml\", \"data/External_Sounds/bonus_point_tally.mp3\", \"data/External_Sounds/button_press.mp3\", \"data/External_Sounds/cocbomb_explode.mp3\", \"data/External_Sounds/cocbomb_pickup.mp3\", \"data/External_Sounds/cocobomb_tick.mp3\", \"data/External_Sounds/fruit_hit.mp3\", \"data/External_Sounds/gem_added_1.mp3\", \"data/External_Sounds/gem_added_2.mp3\", \"data/External_Sounds/intro_movie.mp3\", \"data/External_Sounds/match_1.mp3\", \"data/External_Sounds/match_2.mp3\", \"data/External_Sounds/match_3.mp3\", \"data/External_Sounds/match_4.mp3\", \"data/External_Sounds/match_5.mp3\", \"data/External_Sounds/match_6.mp3\", \"data/External_Sounds/match_7.mp3\", \"data/External_Sounds/monkey_noise_1.mp3\", \"data/External_Sounds/monkey_noise_2.mp3\", \"data/External_Sounds/monkey_noise_3.mp3\", \"data/External_Sounds/monkey_noise_4.mp3\", \"data/External_Sounds/monkey_noise_5.mp3\", \"data/External_Sounds/multiplier_activated.mp3\", \"data/External_Sounds/music/gameLoop.mp3\", \"data/External_Sounds/music/introAmbience.mp3\", \"data/External_Sounds/music/introMusic.mp3\", \"data/External_Sounds/music/jg_sting_lose.mp3\", \"data/External_Sounds/music/jg_sting_neutral.mp3\", \"data/External_Sounds/music/jg_sting_win.mp3\", \"data/External_Sounds/music/minigameLoop.mp3\", \"data/External_Sounds/music/rolling_loop.mp3\", \"data/External_Sounds/placecard_fall.mp3\", \"data/External_Sounds/play_button.mp3\", \"data/External_Sounds/points_bonus.mp3\", \"data/External_Sounds/reverse_activated.mp3\", \"data/External_Sounds/rollover.mp3\", \"data/External_Sounds/slow_activated.mp3\", \"data/External_Sounds/snake_head_tail_match.mp3\", \"data/External_Sounds/taget_pickup.mp3\", \"data/External_Sounds/throw_gem_1.mp3\", \"data/External_Sounds/throw_gem_2.mp3\", \"data/External_Sounds/throw_gem_3.mp3\", \"data/External_Sounds/transition.mp3\", \"data/External_Sounds/ui.mp3\", \"data/External_Sounds/warning_sound.mp3\", \"config.txt\", \"data/external_images/levels/background.jpg\", \"data/logger_config.xml\", \"data/external_loggers/gameplay-logger.swf\", \"data/external_loggers/google-analytics-logger.swf\", \"data/external_loggers/gameplay-logger.swf\", \"data/levels/level0.xml\", \"data/levels/level2.xml\", \"data/levels/minigame2.xml\", \"data/levels/level3.xml\", \"data/levels/level4.xml\", \"data/levels/minigame2.xml\", \"data/levels/level5.xml\", \"data/levels/level6.xml\", \"data/levels/level7.xml\", \"data/levels/level8.xml\", \"data/levels/minigame2.xml\", \"data/levels/level9.xml\", \"data/levels/level10.xml\", \"data/external_images/levels/background.jpg\", \"data/external_images/levels/background10.jpg\", \"data/external_images/levels/background2.jpg\", \"data/external_images/levels/background3.jpg\", \"data/external_images/levels/background4.jpg\", \"data/external_images/levels/background5.jpg\", \"data/external_images/levels/background6.jpg\", \"data/external_images/levels/background7.jpg\", \"data/external_images/levels/background8.jpg\", \"data/external_images/levels/background9.jpg\", \"data/external_images/levels/foreground.png\", \"data/external_images/levels/level10-front.png\", \"data/external_images/levels/level3-front.png\", \"data/external_images/levels/level4-front.png\", \"data/external_images/levels/level5-front.png\", \"data/external_images/levels/level7-front.png\", \"data/external_images/minigame/background.jpg\"], \"base\": \"http://amsarkadium-a.akamaihd.net/assets/global/game/monkey-gems/b26a4e9b-b507-4d60-94c5-b3911e1bf0d9\"}}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://amsarkadium-a.akamaihd.net/assets/global/game/monkey-gems/b26a4e9b-b507-4d60-94c5-b3911e1bf0d9/monkey-gems.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl2-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CitySkyTyping-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CitySkyTyping-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/city-sky-typing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/24129/game.swf?1359377887\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TheBoomlandsWorldWars-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TheBoomlandsWorldWars-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/the-boomlands-world-wars\", \"regions\": null, \"height\": 650, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/38711/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BlobsStory-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BlobsStory-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Blob's-Story-2,576742227280292724\", \"regions\": null, \"height\": 720, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/b/Blobs_story/Blob.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MushroomFarmDefender-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MushroomFarmDefender-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/mushroom-farm-defender\", \"regions\": null, \"height\": 500, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/15198/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Match3Adventure-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Match3Adventure-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/match-3-adventure\", \"regions\": null, \"height\": 610, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/21904/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PenguinCubes-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PenguinCubes-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Penguin-Cubes,576742227280289226\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/p/penguincubes.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeavyLegion2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HeavyLegion2-v0\", \"human_url\": \"http://1000webgames.com/play-9770-Heavy-Legion-2.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/heavylegion2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl9-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl9-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Autoattack-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Autoattack-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000090\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cee8bd3c0d.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Retron-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Retron-v0\", \"human_url\": \"http://armorgames.com/play/512\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/retron-512.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PerilousJourney2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PerilousJourney2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25606\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eea9e735df.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FluffRush-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FluffRush-v0\", \"human_url\": \"http://www.gamesbutler.com/game/6453/fluff-rush/\", \"regions\": null, \"height\": 400, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/9ff5e14c5b05ddc3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Tumblestump2-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Tumblestump2-v0\", \"human_url\": \"http://www.miniclip.com/games/tumblestump-2/en/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/tumblestump-2/en/Tumblestump2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlappyAdventure-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlappyAdventure-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/flappy-adventure\", \"regions\": null, \"height\": 650, \"width\": 450, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/124560/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Conquerium-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Conquerium-v0\", \"human_url\": \"http://www.kongregate.com/games/BerzerkStudio/conquerium\", \"regions\": null, \"height\": 480, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/4716/live/embeddable_174716.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RunNGun-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RunNGun-v0\", \"human_url\": \"http://www.miniclip.com/games/run-n-gun/en/\", \"regions\": null, \"height\": 400, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/run-n-gun/en/rungun.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BombThePiratePigs-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BombThePiratePigs-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25200\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae2562a31e5.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CemeteryRoad-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CemeteryRoad-v0\", \"human_url\": \"http://www.kongregate.com/games/fightclub69/cemetery-road\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"https://cdn3.kongcdn.com/game_icons/0048/7983/250x200.jpg?i10c=img.resize(width:171,height:137)\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ExperimentalShooter2-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ExperimentalShooter2-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Experimental-Shooter-2,576742227280289294\", \"regions\": null, \"height\": 700, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/e/Experimental_shooter/experimental_shooter2_final.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JollySwipe-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\", \"1 player\", \"flash\", \"shooting\", \"matching\", \"monsters\", \"free\", \"idnet\", \"idnet highscore\", \"idnet save\", \"idnet achievements\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JollySwipe-v0\", \"human_url\": \"http://www.y8.com/games/jolly_swipe\", \"regions\": null, \"height\": 640, \"width\": 360, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/91995/original/jolly_swipe.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TtRacer-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TtRacer-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/tt-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0018/7756/live/embeddable_187756.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RhythmSnake-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RhythmSnake-v0\", \"human_url\": \"http://armorgames.com/play/101\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/rhythm-snake-101.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Fizzion-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Fizzion-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/fizzion\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/130403/game.swf?1424948746\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Alien-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Alien-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/alien\", \"regions\": null, \"height\": 400, \"width\": 300, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/295/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Contra3TheAlienWars-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Contra3TheAlienWars-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25154\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae2490c41ed.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AcidFactory-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AcidFactory-v0\", \"human_url\": \"http://www.miniclip.com/games/acid-factory/en/\", \"regions\": null, \"height\": 501, \"width\": 782, \"extra_files\": {\"relative\": {\"files\": [\"cave1.txt\"], \"base\": \"http://www.miniclip.com/games/acid-factory/en\"}}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/acid-factory/en/acidfactory.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LongJump-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LongJump-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/long-jump\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/22907/game.swf?1344258815\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TwinkleStarRush-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TwinkleStarRush-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Twinkle-Star-Rush,576742227280285062\", \"regions\": null, \"height\": 680, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/t/Twinkle_star_rush/twinkle_star_rush.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Weirdville-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.Weirdville-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/weirdville/\", \"regions\": null, \"height\": 449, \"width\": 611, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/weirdville/weirdville.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AtvRide-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AtvRide-v0\", \"human_url\": \"http://1000webgames.com/play-10038-ATV-Ride.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/atvride.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Dropblox-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Dropblox-v0\", \"human_url\": \"http://armorgames.com/play/779\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/dropblox-779.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WreckRoad-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.WreckRoad-v0\", \"human_url\": \"http://turbonuke.com/games.php?game=wreckroad\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://turbonuke.com/flashgames/monstertruckfever.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Minicarting-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Minicarting-v0\", \"human_url\": \"http://www.dailygames.com/games/minicarting.html\", \"regions\": null, \"height\": 419, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.dailygames.com/games/minicarting.html\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ExtremeAirWars-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ExtremeAirWars-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/extreme-air-wars\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/39716/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Wheelers-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.Wheelers-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/wheelers\", \"regions\": null, \"height\": 300, \"width\": 450, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/1341/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpacePunkRacerLvl6-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.SpacePunkRacerLvl6-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/space-punk-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0012/4902/live/embeddable_124902.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacerLvl8-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacerLvl8-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/3927/live/embeddable_93927.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl13-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl13-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MusicStomp-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MusicStomp-v0\", \"human_url\": \"http://armorgames.com/play/1363\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/music-stomp-1363.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlowerGuardian-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlowerGuardian-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Flower-Guardian,576742227280290484\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/f/Flowerguardian/FlowerGuardian.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IsoblockerMaster-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IsoblockerMaster-v0\", \"human_url\": \"http://www.y8.com/games/isoblocker_master\", \"regions\": null, \"height\": 480, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/101661/original/isoblocker_master.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BushRoyalRampage-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BushRoyalRampage-v0\", \"human_url\": \"http://www.miniclip.com/games/bush-royal-rampage/en/\", \"regions\": null, \"height\": 455, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/bush-royal-rampage/en/bushroyalrampage.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Sundrops-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Sundrops-v0\", \"human_url\": \"http://notdoppler.com/sundrops.php\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/sundrops.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TowerCollapseDeluxe-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TowerCollapseDeluxe-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/tower-collapse-deluxe\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/130844/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GalaxyDefender-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GalaxyDefender-v0\", \"human_url\": \"http://armorgames.com/play/2929\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/galaxy-defender-2929.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JamesTheSpaceZebra-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JamesTheSpaceZebra-v0\", \"human_url\": \"http://armorgames.com/play/207/james-the-space-zebra\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/james-the-space-zebr-207.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MiniMachines-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.MiniMachines-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/Mini-Machines.html\", \"regions\": null, \"height\": 480, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/flash10/Mini-Machines.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl2-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperCandyGems-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperCandyGems-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/super-candy-gems\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/133479/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MotoTrialMania-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MotoTrialMania-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25573\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee9eeb99ab.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HighSpeedChase-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HighSpeedChase-v0\", \"human_url\": \"http://www.johnnytwoshoes.com/game/highspeedchase\", \"regions\": null, \"height\": 500, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.addictinggames.com/newGames/car-games/highspeedchase/highspeedchase.swf?c=18\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CableCapers2-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CableCapers2-v0\", \"human_url\": \"http://www.miniclip.com/games/cable-capers-2/en/\", \"regions\": null, \"height\": 436, \"width\": 546, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/cable-capers-2/en/cablecapers.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperbikeRacer-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.SuperbikeRacer-v0\", \"human_url\": \"http://notdoppler.com/superbikeracer.php\", \"regions\": null, \"height\": 480, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/superbikeracer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpinSprint-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SpinSprint-v0\", \"human_url\": \"http://armorgames.com/play/1379\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/spin-sprint-1379.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ElainesBakery-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ElainesBakery-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Elaine's-Bakery,576742227280289065\", \"regions\": null, \"height\": 700, \"width\": 420, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/e/elains_bakery.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PouJetpack-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PouJetpack-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/pou-jetpack\", \"regions\": null, \"height\": 700, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/128690/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AlchemySwap-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AlchemySwap-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25158\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae24a30f566.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HalloweenJam-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HalloweenJam-v0\", \"human_url\": \"http://armorgames.com/play/1385\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/halloween-jam-1385.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MineHero-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"arcade\", \"kids\", \"our\", \"1 player\", \"2 players\", \"2pg\", \"bombs\", \"bubbles\", \"free\", \"fun\", \"hero\", \"keyboard\", \"kids\", \"mine\", \"pixelated\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MineHero-v0\", \"human_url\": \"http://old.2pg.com/game/mine-hero/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/M/mine_hero_2pg.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Jumprunner-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Jumprunner-v0\", \"human_url\": \"http://www.gamesbutler.com/game/7786/jumprunner/\", \"regions\": null, \"height\": 240, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/72bd3d7c7668233b.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DumperRush-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.DumperRush-v0\", \"human_url\": \"http://www.cartitans.com/game/dumper-rush/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/dumper-rush.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SchoolBusRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.SchoolBusRacing-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/school-bus-racing\", \"regions\": null, \"height\": 430, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/38524/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BalloonHero-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BalloonHero-v0\", \"human_url\": \"http://www.y8.com/games/balloon_hero\", \"regions\": null, \"height\": 460, \"width\": 690, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/91742/original/balloon_hero.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer2Lvl8-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacer2Lvl8-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0011/8219/live/embeddable_118219.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MarshmallowsEscape-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MarshmallowsEscape-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000189\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570e2e291f339.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Astroman-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"action\", \"our\", \"2 player\", \"2pg\", \"action\", \"astroman\", \"astronaut\", \"collecting\", \"space\", \"spaceship\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Astroman-v0\", \"human_url\": \"http://old.2pg.com/game/astroman/play/\", \"regions\": null, \"height\": 450, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/A/astroman.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CandyMatch-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CandyMatch-v0\", \"human_url\": \"http://www.neongames.com/game/Candy+Match\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesonly.net/uploaded/swf/snowqueen.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer2Lvl4-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacer2Lvl4-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0011/8219/live/embeddable_118219.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DotsRevamped-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DotsRevamped-v0\", \"human_url\": \"http://notdoppler.com/dots-revamped.php\", \"regions\": null, \"height\": 400, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/dots-revamped.swf?1\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PumpkinCollector-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PumpkinCollector-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/pumpkin-collector\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/133872/game.swf?1445252260\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.V8MuscleCars3-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.V8MuscleCars3-v0\", \"human_url\": \"http://insanehero.com/mygames/V8MuscleCars3/index.html\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://insanehero.com/mygames/V8MuscleCars3/v8musclecars3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CharlieTheDuck-v0\": {\"readme_header\": null, \"categories\": [\"jump and run\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CharlieTheDuck-v0\", \"human_url\": \"http://www.platformgames.com/game/Charlie+the+Duck\", \"regions\": null, \"height\": 369, \"width\": 495, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.platformgames.com/uploaded/swf/charlietheduck.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl15-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl15-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dRallyFever-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.3dRallyFever-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-rally-fever/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-rally-fever.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Zevil2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Zevil2-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Zevil-2,576742227280295814\", \"regions\": null, \"height\": 700, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://files.cdn.spilcloud.com/flash/Zevil2/zevil_2_securex.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NukeDefense-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NukeDefense-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/nuke-defense\", \"regions\": null, \"height\": 524, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/35163/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RollTheCluster-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RollTheCluster-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/roll-the-cluster\", \"regions\": null, \"height\": 480, \"width\": 760, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/129856/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlyAwayRabbit2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlyAwayRabbit2-v0\", \"human_url\": \"http://www.gamesbutler.com/game/4314/fly-away-rabbit-2/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/647d27d84a1350d5.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl5-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl5-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchJong-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MatchJong-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/match-jong\", \"regions\": null, \"height\": 600, \"width\": 360, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/131164/game.swf?1430134103\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Aerorumble-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Aerorumble-v0\", \"human_url\": \"http://armorgames.com/play/10431\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/aerorumble-10431.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DeathDiceOverdose-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DeathDiceOverdose-v0\", \"human_url\": \"http://www.gamesbutler.com/game/2449/death-dice-overdose/\", \"regions\": null, \"height\": 450, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/deathdicea.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HappyEasterEggs-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HappyEasterEggs-v0\", \"human_url\": \"http://www.neongames.com/game/Happy+Easter+Eggs\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesonly.net/uploaded/swf/happyeastereggs.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WishTotemsLevelPack-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WishTotemsLevelPack-v0\", \"human_url\": \"http://www.gamesbutler.com/game/15499/wish-totems-level-pack/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/wishTotems_lvlgb.swf?goto=norm\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl12-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl12-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Popopop-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\", \"bubble\", \"mouse only\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Popopop-v0\", \"human_url\": \"http://www.kongregate.com/games/Rob_Almighty/popopop\", \"regions\": null, \"height\": 600, \"width\": 620, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0003/7854/live/Popopop_Final9_.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AlienTransporter-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AlienTransporter-v0\", \"human_url\": \"http://armorgames.com/play/17954\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/alien-transporter-17954.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperbikeExtreme-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.SuperbikeExtreme-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/superbike-extreme\", \"regions\": null, \"height\": 430, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/22044/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ParkingFury-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ParkingFury-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000152\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570e0de592b1a.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl4-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl4-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperPuzzlePlatformer-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperPuzzlePlatformer-v0\", \"human_url\": \"http://www.gamesbutler.com/game/5840/super-puzzle-platformer/\", \"regions\": null, \"height\": 400, \"width\": 320, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/14336e24782f011f.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ToyRacers-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ToyRacers-v0\", \"human_url\": \"http://www.cartitans.com/game/toy-racers/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/toy-racers.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ArkanoidGame-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ArkanoidGame-v0\", \"human_url\": \"http://www.y8.com/games/arkanoid_game\", \"regions\": null, \"height\": 450, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/44622/original/arkanoid_game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"internet.SlitherIOEasy-v0\": {\"categories\": [\"mmo\"], \"height\": 300, \"width\": 502, \"server_timestep_limit\": null, \"tags\": {}, \"id\": \"internet.SlitherIOEasy-v0\", \"rewarder\": true, \"url\": \"http://slither.io/\", \"enable_internet\": true, \"autostart\": true}, \"flashgames.SliceTheBoxRemaster-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SliceTheBoxRemaster-v0\", \"human_url\": \"http://armorgames.com/play/15584\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/slice-the-box-remast-15584.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DualDimension-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DualDimension-v0\", \"human_url\": \"http://armorgames.com/play/17972\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/dual-dimension-17972.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleTanksTd15-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BubbleTanksTd15-v0\", \"human_url\": \"http://armorgames.com/play/6338\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/bubble-tanks-td-15-6338.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PiggyWiggy-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PiggyWiggy-v0\", \"human_url\": \"http://notdoppler.com/piggywiggy.php\", \"regions\": null, \"height\": 460, \"width\": 690, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/piggywiggy.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Flashcycle2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Flashcycle2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000072\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570ceac150b02.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SkyQuest-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SkyQuest-v0\", \"human_url\": \"http://notdoppler.com/skyquest.php\", \"regions\": null, \"height\": 480, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/skyquest.swf?15\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SkyIsland-v0\": {\"readme_header\": null, \"categories\": [\"sparsereward\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SkyIsland-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/skyisland/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/skyisland/skyisland.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.DeepForest3dRace-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.DeepForest3dRace-v0\", \"human_url\": \"http://www.cartitans.com/game/deep-forest-3d-race/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/deep-forest-3d-race.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BunnyCannon-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BunnyCannon-v0\", \"human_url\": \"http://notdoppler.com/bunnycannon.php\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/bunnycannon.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FormulaRacer-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FormulaRacer-v0\", \"human_url\": \"http://www.kongregate.com/games/turboNuke/formula-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0010/9268/live/FormulaRacer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Offroaders-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.Offroaders-v0\", \"human_url\": \"http://notdoppler.com/offroaders.php\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/offroaders.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ElClassico-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ElClassico-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25190\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae25455c248.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BuildBalance2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BuildBalance2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25581\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eea38e7f62.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MasterDifference-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MasterDifference-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000175\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570e1c39120de.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl7-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl7-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl16-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl16-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JungleEagle-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JungleEagle-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/jungle-eagle\", \"regions\": null, \"height\": 500, \"width\": 650, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/125342/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Canopy-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Canopy-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/canopy/\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/canopy/canopy.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.RacerKartz-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RacerKartz-v0\", \"human_url\": \"http://old.2pg.com/game/racer-kartz/play/\", \"regions\": null, \"height\": 520, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/racerkartz2player.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Goldextraction-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Goldextraction-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/goldextraction\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/128693/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MummyMadness-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MummyMadness-v0\", \"human_url\": \"http://www.gamesbutler.com/game/25597/mummy-madness/\", \"regions\": null, \"height\": 480, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/edd7926ed359da07.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RacingSupercarChampionship-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.RacingSupercarChampionship-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/Racing-Supercar-Championship.html\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/d/file/20160217/80bebcdefd7ffc44ae72c904855e1953.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dUrbanMadness2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.3dUrbanMadness2-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-urban-madness-2/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/upload/games/1876/7308727498.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HappyBallz-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HappyBallz-v0\", \"human_url\": \"http://1000webgames.com/play-7033-Happy-Ballz.html\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/sponsor-1000webgames-HappyBallz.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AmigoPancho4Travel-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AmigoPancho4Travel-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Amigo-Pancho-4:-Travel,576742227280290755\", \"regions\": null, \"height\": 690, \"width\": 460, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/a/Amigo_Pancho4/AmigoPancho4.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ObamaAlienDefense-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ObamaAlienDefense-v0\", \"human_url\": \"http://www.miniclip.com/games/obama-alien-defense/en/\", \"regions\": null, \"height\": 400, \"width\": 590, \"extra_files\": {\"relative\": {\"files\": [\"levels/game.intro.swf\", \"component.txt\", \"levels/newyork.json\", \"avatarloader.txt\", \"levels/london.json\", \"levels/newyork.intro.swf\", \"levels/newyork.assets.swf\", \"levels/shared.assets.swf\", \"levels/global.assets.swf\", \"levels/global.sounds.swf\"], \"base\": \"http://www.miniclip.com/games/obama-alien-defense/en\"}}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/obama-alien-defense/en/obama-alien-defense.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpacePunkRacerLvl4-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.SpacePunkRacerLvl4-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/space-punk-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0012/4902/live/embeddable_124902.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DinoMeatHunt3Extra-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DinoMeatHunt3Extra-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25397\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae31b572e41.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SaveTheDummyHolidays-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SaveTheDummyHolidays-v0\", \"human_url\": \"http://www.gamesbutler.com/game/18677/save-the-dummy-holidays/\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/save-the-dumhol3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IceRun-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IceRun-v0\", \"human_url\": \"http://www.kongregate.com/games/rumblesushi/ice-run\", \"regions\": null, \"height\": 422, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0016/7488/live/embeddable_167488.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Zed-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Zed-v0\", \"human_url\": \"http://www.miniclip.com/games/zed/en/\", \"regions\": null, \"height\": 390, \"width\": 546, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/zed/en/zed.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ZooRacer-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ZooRacer-v0\", \"human_url\": \"http://www.kongregate.com/games/citizenphil/zoo-racer\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0011/2729/live/zoo_racer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchToEnjoyLevelPack-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\", \"match 3\", \"mouse only\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MatchToEnjoyLevelPack-v0\", \"human_url\": \"http://www.kongregate.com/games/charstudio/match-to-enjoy-level-pack\", \"regions\": null, \"height\": 527, \"width\": 620, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0015/5971/live/game_match_to_enjoy_level_pack_mathnook_kong.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BigWheelsTrial-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BigWheelsTrial-v0\", \"human_url\": \"http://1000webgames.com/play-10106-Big-Wheels-Trial.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/bigwheelstrial.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RapaNui-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.RapaNui-v0\", \"human_url\": \"http://www.neongames.com/game/Rapa+Nui\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesonly.net/uploaded/swf/rapanui.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NOfficialWebVersion-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NOfficialWebVersion-v0\", \"human_url\": \"http://www.kongregate.com/games/MetanetSoftware/n\", \"regions\": null, \"height\": 600, \"width\": 792, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0002/4483/live/embeddable_24483.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GsSoccerWorldCup-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GsSoccerWorldCup-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25201\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae2565284bf.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchTheBugz-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.MatchTheBugz-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/match-the-bugz\", \"regions\": null, \"height\": 420, \"width\": 560, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/3023/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AlienAssault-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AlienAssault-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/alien-assault\", \"regions\": null, \"height\": 392, \"width\": 670, \"extra_files\": {\"absolute\": [\"http://x.fogdev.com/api/libv3-5.swf\"]}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/38203/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TastyFruits-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"fun\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TastyFruits-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Tasty-Fruits,576742227280291236\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/t/Tasty_Fruits/tasty_fruits.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.StrikeForceKitty-v0\": {\"readme_header\": null, \"categories\": [\"1 player\", \"flash\", \"action\", \"fish\", \"series\", \"collecting\", \"animal\", \"kitten\", \"cat\", \"running\", \"free\", \"idnet\", \"idnet highscore\", \"idnet save\", \"idnet achievements\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.StrikeForceKitty-v0\", \"human_url\": \"http://www.y8.com/games/strikeforce_kitty\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/76347/original/strikeforce_kitty.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.UltimateLegend-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.UltimateLegend-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25233\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae261bbc4ce.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ExploreTheCandies-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ExploreTheCandies-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/explore-the-candies\", \"regions\": null, \"height\": 480, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/134961/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BoatDrive-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BoatDrive-v0\", \"human_url\": \"http://1000webgames.com/play-10030-Boat-Drive.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/boatdrive.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Hearts-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Hearts-v0\", \"human_url\": \"http://armorgames.com/play/838\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/hearts-838.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NinjaPandaCouple-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"adventure\", \"our\", \"1 player\", \"2 players\", \"2playergames\", \"animal\", \"free\", \"fun\", \"journey\", \"kids\", \"ninja\", \"panda\", \"run\", \"runner\", \"running\", \"speed\", \"timing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NinjaPandaCouple-v0\", \"human_url\": \"http://old.2pg.com/game/ninja-panda-couple/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/ninjapandacouple2pg.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Match3PresentBoxSaga-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Match3PresentBoxSaga-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/match-3--present-box-saga\", \"regions\": null, \"height\": 720, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/131263/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Hamsterball-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Hamsterball-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/hamsterball\", \"regions\": null, \"height\": 440, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/14992/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WarBerlinIdle-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WarBerlinIdle-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25373\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae30e48d439.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleMover-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.BubbleMover-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Bubble-Mover,576742227280284474\", \"regions\": [{\"coordinates\": [474, 139, 505, 99], \"type\": \"noclick\"}], \"height\": 550, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/b/bubble_mover/bubble_mover.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.F1RacingChallenge-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.F1RacingChallenge-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/F1-Racing-Challenge.html\", \"regions\": null, \"height\": 375, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/d/file/20140206/af8f5c023cea506ac794cda339fb820f.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BoxBlocks-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BoxBlocks-v0\", \"human_url\": \"http://www.y8.com/games/box_blocks\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/121559/original/box_blocks.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FormulaRacerLvl4-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FormulaRacerLvl4-v0\", \"human_url\": \"http://www.kongregate.com/games/turboNuke/formula-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0010/9268/live/FormulaRacer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LuxUltimate-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"adventure\", \"our\", \"1 player\", \"2 players\", \"2pg\", \"flash\", \"highscore\", \"pixelated\", \"runner\", \"running\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.LuxUltimate-v0\", \"human_url\": \"http://old.2pg.com/game/lux-ultimate/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/lux_ultimate_2pg_1375621235.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Knockers-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Knockers-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/knockers\", \"regions\": null, \"height\": 440, \"width\": 400, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/245/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Business-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Business-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25442\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae342d06573.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl3-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl3-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CattlepultPlayerPack-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CattlepultPlayerPack-v0\", \"human_url\": \"http://armorgames.com/play/356\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/cattlepult-player-pa-356.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PenguinSkate2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PenguinSkate2-v0\", \"human_url\": \"http://armorgames.com/play/506\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/penguin-skate-2-506.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TouchTheBubbles4-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TouchTheBubbles4-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/touch-the-bubbles-4\", \"regions\": null, \"height\": 495, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/38928/game.swf?1379932825\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Mimelet-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.Mimelet-v0\", \"human_url\": \"http://www.miniclip.com/games/mimelet/en/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/mimelet/en/mimelet.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlashRace-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlashRace-v0\", \"human_url\": \"http://www.y8.com/games/flash_race\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/671/original/flash_race.dcr?1462198647\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl8-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl8-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EasterEggsChallenge-v0\": {\"readme_header\": null, \"categories\": [\"1 player\", \"flash\", \"girl\", \"matching\", \"animal\", \"rabbit\", \"free\", \"match 3\", \"idnet\", \"idnet highscore\", \"idnet achievements\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.EasterEggsChallenge-v0\", \"human_url\": \"http://www.y8.com/games/easter_eggs_challenge\", \"regions\": [{\"coordinates\": [212, 59, 128, 106], \"type\": \"noclick\"}, {\"coordinates\": [17, 48, 128, 47], \"type\": \"noclick\"}], \"height\": 570, \"width\": 760, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109875/original/easter_eggs_challenge.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Tosuta-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Tosuta-v0\", \"human_url\": \"http://armorgames.com/play/309\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/to-suta-309.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IdleChop-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IdleChop-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000093\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cef013a1f8.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ZombieTdReborn-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.ZombieTdReborn-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Zombie-TD:-Reborn,576742227280285285\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/z/zombie_tower_defense/Zombie_tower_defense.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HiredHeroes-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HiredHeroes-v0\", \"human_url\": \"http://www.kongregate.com/games/Badim/hired-heroes\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0015/9794/live/embeddable_159794.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleHitValentine-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BubbleHitValentine-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Bubble-Hit-Valentine,576742227280284223\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/b/bubble_hit_valentine/bubble_hit_valentine.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SmashTheSwine-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SmashTheSwine-v0\", \"human_url\": \"http://old.2pg.com/game/smash-the-swine/play/\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/S/smash-the-swine.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FpaWorld1Remix-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FpaWorld1Remix-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000114\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/game-1466499647.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GalacticGems-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\", \"match 3\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.GalacticGems-v0\", \"human_url\": \"http://www.kongregate.com/games/MikRad/galactic-gems\", \"regions\": null, \"height\": 527, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0012/9386/live/Galactic_Gems.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FormulaRacer2012-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.FormulaRacer2012-v0\", \"human_url\": \"http://www.kongregate.com/games/turboNuke/formula-racer-2012\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0014/2671/live/FormulaRacer2012.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl4-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl4-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FredFigglehorn-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FredFigglehorn-v0\", \"human_url\": \"http://www.miniclip.com/games/fred-figglehorn/en/\", \"regions\": null, \"height\": 400, \"width\": 938, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/fred-figglehorn/en/fred.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RhythmBlasterV2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RhythmBlasterV2-v0\", \"human_url\": \"http://armorgames.com/play/102\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/rhythm-blaster-v2-102.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ChickCannont-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ChickCannont-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/chick-cannon-2\", \"regions\": null, \"height\": 500, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/38904/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WarHeroes-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WarHeroes-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25403\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae3208ee8a3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.KamikazeRace-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.KamikazeRace-v0\", \"human_url\": \"http://www.kongregate.com/games/orbgames/kamikaze-race\", \"regions\": null, \"height\": 400, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://assets.kongregate.com/gamez/0004/0198/live/kamikaze-race.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Cooliobeat-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Cooliobeat-v0\", \"human_url\": \"http://armorgames.com/play/104\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/cooliobeat-104.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SliceTheBox-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SliceTheBox-v0\", \"human_url\": \"http://armorgames.com/play/14864\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/slice-the-box-14864.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl6-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl6-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BlackAndWhiteEscapeTheOffice-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BlackAndWhiteEscapeTheOffice-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25570\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee9e1be0a3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GunExpress-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.GunExpress-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/gun-express\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0008/6188/live/GunExpress.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PiratesAndCannons-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PiratesAndCannons-v0\", \"human_url\": \"http://www.gamesbutler.com/game/25336/pirates-and-cannons/\", \"regions\": null, \"height\": 480, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/0cca539b4e158630.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ParallelLevels-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ParallelLevels-v0\", \"human_url\": \"http://armorgames.com/play/15784\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/parallel-levels-15784.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PinataWarriors-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PinataWarriors-v0\", \"human_url\": \"http://old.2pg.com/game/pinata-warriors/play/\", \"regions\": null, \"height\": 525, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/pinata-warriors.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.UrbanMicroRacers-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.UrbanMicroRacers-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/urban-micro-racers\", \"regions\": null, \"height\": 500, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/22001/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DisasterWillStrikeUltimateDisaster-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DisasterWillStrikeUltimateDisaster-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000049\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570ce76ae376d.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Cleopatra-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Cleopatra-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25157\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae249d461e7.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CarsVsRobots-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CarsVsRobots-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Cars-vs.-Robots,576742227280285426\", \"regions\": null, \"height\": 720, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/c/cars_vs_robots/Cars_vs_robots.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Cattlepult-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Cattlepult-v0\", \"human_url\": \"http://armorgames.com/play/208\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/cattlepult-208.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AWeekendAtTweetys-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AWeekendAtTweetys-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000278\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570ec2568de50.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FormulaXspeed3d-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FormulaXspeed3d-v0\", \"human_url\": \"http://www.y8.com/games/formula_xspeed_3d\", \"regions\": null, \"height\": 480, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/92201/original/formula_xspeed_3d.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PlaneRace-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PlaneRace-v0\", \"human_url\": \"http://1000webgames.com/play-9179-Plane-Race.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/planerace.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeroRoofTop-v0\": {\"readme_header\": null, \"categories\": [\"1 player\", \"flash\", \"mouse skill\", \"running\", \"jumping\", \"free\", \"idnet\", \"idnet highscore\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeroRoofTop-v0\", \"human_url\": \"http://www.y8.com/games/hero_roof_top\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/119142/original/hero_roof_top.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRaceLvl7-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.NeonRaceLvl7-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/7872/live/embeddable_97872.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.YepisJourney-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.YepisJourney-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/yepis-journey\", \"regions\": null, \"height\": 640, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/38546/game.swf?1374486404\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl10-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl10-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl14-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl14-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HungryLittlePenguins-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HungryLittlePenguins-v0\", \"human_url\": \"http://1000webgames.com/play-7839-Hungry-Little-Penguins.html\", \"regions\": null, \"height\": 375, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/hungry-little-penguins.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RingsideHero-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RingsideHero-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25167\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae24e1cd888.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl4-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl4-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BoxingLiveRound2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BoxingLiveRound2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000016\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570c1765ed094.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HalloweenExplorer-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HalloweenExplorer-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/halloween-explorer\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/133265/game.swf?1442315789\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FallDamage-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FallDamage-v0\", \"human_url\": \"http://armorgames.com/play/12289\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/fall-damage-12289.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ParachuteRetrospect-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ParachuteRetrospect-v0\", \"human_url\": \"http://armorgames.com/play/50\", \"regions\": null, \"height\": 550, \"width\": 400, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/parachute-retrospect-50.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ZombieDemolisher3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ZombieDemolisher3-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25617\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eeadb4dd65.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GalaxyMission-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"action\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GalaxyMission-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Galaxy-Mission,576742227280295981\", \"regions\": null, \"height\": 540, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://files.cdn.spilcloud.com/flash/galaxymission_1908/galaxymission_1908.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DolphinVolleyball-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DolphinVolleyball-v0\", \"human_url\": \"http://old.2pg.com/game/dolphin-volleyball/play/\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/D/dolphin_volleyball.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GravityGuy-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GravityGuy-v0\", \"human_url\": \"http://www.miniclip.com/games/gravity-guy/en/\", \"regions\": null, \"height\": 501, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/gravity-guy/en/gravityguy.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MidnightMiner-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MidnightMiner-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25335\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae2faa41fb4.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Paintwars-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Paintwars-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25393\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae3192c6579.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ChristmasBubbles-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ChristmasBubbles-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Christmas-Bubbles,576742227280290287\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash//c/Christmas_bubbles/christmasbubbles.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl11-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl11-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GalacticGems2LevelPack-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\", \"match 3\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GalacticGems2LevelPack-v0\", \"human_url\": \"http://www.kongregate.com/games/MikRad/galactic-gems-2-level-pack\", \"regions\": null, \"height\": 527, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://assets.kongregate.com/gamez/0017/0262/live/Galactic_Gems_2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GiantsAndDwarvesTd-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GiantsAndDwarvesTd-v0\", \"human_url\": \"http://www.kongregate.com/games/LabuGames/giants-and-dwarves-td\", \"regions\": null, \"height\": 500, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0016/9695/live/embeddable_169695.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Growbox-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Growbox-v0\", \"human_url\": \"http://armorgames.com/play/4613\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/growbox-4613.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ZombieTowerDefenseReborn-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ZombieTowerDefenseReborn-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Zombie-Tower-Defense:-Reborn,576742227280285143\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/z/zombie_tower_defense/Zombie_tower_defense.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.VectorRunner-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.VectorRunner-v0\", \"human_url\": \"http://www.kongregate.com/games/DigYourOwnGrave/vector-runner\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://assets.kongregate.com/gamez/0001/9779/live/VectorRunner_KONG_secure.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PrincessToTheRescue-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PrincessToTheRescue-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Princess-to-the-Rescue,576742227280287927\", \"regions\": null, \"height\": 700, \"width\": 525, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/p/Princess%20To%20Rescue.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BirdsFeeding-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BirdsFeeding-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/birds-feeding\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/93042/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.UrbanFatburner-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.UrbanFatburner-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Urban-Fatburner,576742227280284530\", \"regions\": null, \"height\": 700, \"width\": 420, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/u/UrbanFatburner.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RabbitRustler-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RabbitRustler-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/rabbitrustler/\", \"regions\": null, \"height\": 450, \"width\": 650, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/rabbitrustler/rabbitrustler.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.MazeEye-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MazeEye-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000194\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570eafdee309f.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WarOfTheShard-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WarOfTheShard-v0\", \"human_url\": \"http://www.kongregate.com/games/WakefieldStudios/war-of-the-shard\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0020/1620/live/embeddable_201620.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AnotherLife2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AnotherLife2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25202\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae256b03607.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Blosics2LevelPack-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Blosics2LevelPack-v0\", \"human_url\": \"http://notdoppler.com/blosics2levelpack.php\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/blosics2levelpack.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BulletFury-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BulletFury-v0\", \"human_url\": \"http://1000webgames.com/play-9982-Bullet-Fury.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/bulletfury.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TattooArtist-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TattooArtist-v0\", \"human_url\": \"http://armorgames.com/play/515\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/tattoo-artist-515.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ClaustrophobiumFourStepsFromDeath-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ClaustrophobiumFourStepsFromDeath-v0\", \"human_url\": \"http://armorgames.com/play/15986\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/laustrophobium-in-fo-15986.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Stand-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Stand-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000176\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570e1c42c5b46.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Stalingrad2-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Stalingrad2-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/stalingrad-2\", \"regions\": null, \"height\": 480, \"width\": 630, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/14961/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ToonEscapeSpookHouse-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ToonEscapeSpookHouse-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25526\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee8f38ee12.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AliceNixsAdventure-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AliceNixsAdventure-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Alice-&%20Nix%E2%80%99s%20Adventure,576742227280284532\", \"regions\": null, \"height\": 600, \"width\": 450, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/a/AliceAndNix.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.1001ArabianNights-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.1001ArabianNights-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/1001-Arabian-Nights,576742227280287096\", \"regions\": null, \"height\": 510, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/0/1001_arabian_nights/1001_arabian_nights.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchAndSpell-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MatchAndSpell-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/match-and-spell\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/135829/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpanishLiga2016-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SpanishLiga2016-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25265\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae26cc586b7.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubblePop-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"action\", \"kids\", \"our\", \"1 player\", \"2 players\", \"2pg\", \"bubbles\", \"collecting\", \"free\", \"fun\", \"ghosts\", \"keyboard\", \"kids\", \"pop\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BubblePop-v0\", \"human_url\": \"http://old.2pg.com/game/bubble-pop/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/B/bubble_pop_2pg.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FormulaRacerLvl7-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FormulaRacerLvl7-v0\", \"human_url\": \"http://www.kongregate.com/games/turboNuke/formula-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0010/9268/live/FormulaRacer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JamesTheCircusZebra-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.JamesTheCircusZebra-v0\", \"human_url\": \"http://armorgames.com/play/206/james-the-circus-zebra\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/james-the-circus-zeb-206.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.InsaneCircle-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.InsaneCircle-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25633\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eeb31a1dc1.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl13-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl13-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BaldEagleJigsawPuzzle-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BaldEagleJigsawPuzzle-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/bald-eagle-jigsaw-puzzle\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/17094/game.swf?1366132894\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EpicBattleFantasy4-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EpicBattleFantasy4-v0\", \"human_url\": \"http://www.kongregate.com/games/kupo707/epic-battle-fantasy-4\", \"regions\": null, \"height\": 500, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0016/7318/live/embeddable_167318.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Blosics2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Blosics2-v0\", \"human_url\": \"http://notdoppler.com/blosics2.php\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/blosics2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacerLvl4-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacerLvl4-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/3927/live/embeddable_93927.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RubbleRacer-v0\": {\"readme_header\": null, \"categories\": [\"obstacles\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RubbleRacer-v0\", \"human_url\": \"http://www.andkon.com/arcade/obstacles/rubbleracer/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/obstacles/rubbleracer/rubbleracer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Helixteus-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Helixteus-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000094\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cef078ac69.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Phit-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Phit-v0\", \"human_url\": \"http://armorgames.com/play/21\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/phit-21.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl6-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl6-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Infinitix-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Infinitix-v0\", \"human_url\": \"http://armorgames.com/play/12818\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/infinitix-12818.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpacePunkRacer-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.SpacePunkRacer-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/space-punk-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0012/4902/live/embeddable_124902.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PaintWars-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PaintWars-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25393\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae3192c6579.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Free_to_use-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Free_to_use-v0\", \"human_url\": \"http://armorgames.com/play/12712\", \"regions\": null, \"height\": \"\", \"width\": \"\", \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/rocket-santa-12712.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.VanguardWars-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.VanguardWars-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25431\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae338f0a396.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DrinkBeerNeglectFamily-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DrinkBeerNeglectFamily-v0\", \"human_url\": \"http://www.gamesbutler.com/game/24301/drink-beer-neglect-family/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/4196a64b1b90ccc4.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EatToWin-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EatToWin-v0\", \"human_url\": \"http://old.2pg.com/game/eat-to-win/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/eattowin.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.OceanMatch-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.OceanMatch-v0\", \"human_url\": \"http://www.neongames.com/game/Ocean+Match\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesonly.net/uploaded/swf/oceanmatch.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HoldTheFort-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HoldTheFort-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25512\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee8a1dde6b.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlashsBounty-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlashsBounty-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000075\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570ceb5ff084c.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RocketBootsInc-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RocketBootsInc-v0\", \"human_url\": \"http://www.gamesbutler.com/game/18363/rocket-boots-inc/\", \"regions\": null, \"height\": 450, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/rocketbootmanv.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpeedBusters-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SpeedBusters-v0\", \"human_url\": \"http://www.cartitans.com/game/speed-busters/\", \"regions\": null, \"height\": 458, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/speed-busters.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NuttyBoom-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NuttyBoom-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Nutty-Boom,576742227280285491\", \"regions\": null, \"height\": 720, \"width\": 540, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/n/Nutty_boom/Nutty_Boom.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PuzzleRescuePrime-v0\": {\"readme_header\": null, \"categories\": [\"mouse only\", \"match 3\", \"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PuzzleRescuePrime-v0\", \"human_url\": \"http://armorgames.com/play/15809\", \"regions\": null, \"height\": 540, \"width\": 580, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/puzzle-rescue-prime-15809.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DigToChina-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DigToChina-v0\", \"human_url\": \"http://www.gamesbutler.com/game/19566/dig-to-china/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/DigToChina_mb.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ColorZapper-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ColorZapper-v0\", \"human_url\": \"http://1000webgames.com/play-8601-Color-Zapper.html\", \"regions\": null, \"height\": 400, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/colorzapper.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ArmyPursuit-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ArmyPursuit-v0\", \"human_url\": \"http://www.cartitans.com/game/army-pursuit/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/army-pursuit.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EuroKicks2016-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EuroKicks2016-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25488\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee7469e9d5.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GalacticGems2NewFrontiers-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\", \"match 3\", \"mouse only\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.GalacticGems2NewFrontiers-v0\", \"human_url\": \"http://www.kongregate.com/games/MikRad/galactic-gems-2-new-frontiers\", \"regions\": null, \"height\": 527, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0020/8507/live/Galactic_Gems_2_NF.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RedBeard-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RedBeard-v0\", \"human_url\": \"http://www.miniclip.com/games/red-beard/en/\", \"regions\": null, \"height\": 366, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/red-beard/en/redbeard.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MusicSmash-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MusicSmash-v0\", \"human_url\": \"http://armorgames.com/play/1362\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/music-smash-1362.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.StreetRace2Nitro-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.StreetRace2Nitro-v0\", \"human_url\": \"http://insanehero.com/mygames/StreetRace2/index.html\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://insanehero.com/mygames/StreetRace2/streetrace2nitro.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer2Bike-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacer2Bike-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0011/8219/live/embeddable_118219.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TractorTrial-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TractorTrial-v0\", \"human_url\": \"http://1000webgames.com/play-8867-Tractor-Trial.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/tractortrial.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GrappleCat-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GrappleCat-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/grapple-cat\", \"regions\": null, \"height\": 405, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/129904/game.swf?1420731083\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BikeTrial2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BikeTrial2-v0\", \"human_url\": \"http://1000webgames.com/play-7937-Bike-Trial-2.html\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/biketrial2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TheBravestHunter-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TheBravestHunter-v0\", \"human_url\": \"http://www.kongregate.com/games/artlogicgames/the-bravest-hunter\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/7765/live/embeddable_177765.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GoKart3d-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GoKart3d-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/go-kart-three-d\", \"regions\": null, \"height\": 358, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/24482/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.KartRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.KartRacing-v0\", \"human_url\": \"http://www.dailygames.com/games/kart-racing.html\", \"regions\": null, \"height\": 369, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.dailygames.com/games/kart-racing.html\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TowerOfPisa-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TowerOfPisa-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/tower-of-pisa\", \"regions\": null, \"height\": 650, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/138996/game.swf?1468934560\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Colorwars-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Colorwars-v0\", \"human_url\": \"http://armorgames.com/play/105\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/colorwars-105.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FeedMeMoar-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FeedMeMoar-v0\", \"human_url\": \"http://www.kongregate.com/games/vinchkovsky/feed-me-moar\", \"regions\": null, \"height\": 525, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/3713/live/embeddable_173713.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GemPop-v0\": {\"readme_header\": null, \"categories\": [\"1 player\", \"flash\", \"jewel\", \"free\", \"idnet\", \"bubble shooter\", \"idnet highscore\", \"idnet save\", \"idnet achievements\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GemPop-v0\", \"human_url\": \"http://www.y8.com/games/gem_pop\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/110217/original/gem_pop.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl11-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl11-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Zombality-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Zombality-v0\", \"human_url\": \"http://www.miniclip.com/games/zombality/en/\", \"regions\": null, \"height\": 420, \"width\": 853, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/zombality/en/Zombality.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GemstoneCastle-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GemstoneCastle-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/gemstone-castle\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/15051/game.swf?1320254437\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GhostClimb2Player-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GhostClimb2Player-v0\", \"human_url\": \"http://old.2pg.com/game/ghost-climb-2-player/play/\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/G/ghost_climb_2pg.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dLaSupercars2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.3dLaSupercars2-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-la-supercars-2/\", \"regions\": null, \"height\": 330, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/upload/games/1909/8745189532.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Typeasaurus-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Typeasaurus-v0\", \"human_url\": \"http://armorgames.com/play/15880\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/typeasaurus-15880.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SantaMan-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SantaMan-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/santa-man\", \"regions\": null, \"height\": 520, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/135194/game.swf?1449756797\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TapRocket-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TapRocket-v0\", \"human_url\": \"http://www.kongregate.com/games/jseldon/tap-rocket\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/2017/live/embeddable_192017.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WoollyBearJigsawPuzzle-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WoollyBearJigsawPuzzle-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/woolly-bear-jigsaw-puzzle\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/17180/game.swf?1304178547\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BraveHeads-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BraveHeads-v0\", \"human_url\": \"http://www.y8.com/games/brave_heads\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/110579/original/brave_heads.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BoxRacers-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BoxRacers-v0\", \"human_url\": \"http://www.kongregate.com/games/FreeWorldGroup/box-racers\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"https://cdn4.kongcdn.com/game_icons/0007/2205/box_100x75.jpg?i10c=img.resize(width:171,height:137)\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Gloom-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Gloom-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25247\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae2666abee4.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.KingRolla-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.KingRolla-v0\", \"human_url\": \"http://www.gamesbutler.com/game/15330/king-rolla/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/kingRolla_GB.swf?goto=norm\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BikeTrial-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BikeTrial-v0\", \"human_url\": \"http://1000webgames.com/play-7775-Bike-Trial.html\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/bike-trial.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.4x4Monster3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.4x4Monster3-v0\", \"human_url\": \"http://1000webgames.com/play-8993-4x4-Monster-3.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/4x4monster3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SantaSituation-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SantaSituation-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/santasituation\", \"regions\": null, \"height\": 500, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/23896/game.swf?1357139442\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LilyFighters-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LilyFighters-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/lily-fighters\", \"regions\": null, \"height\": 320, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/22901/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.XmasChains-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.XmasChains-v0\", \"human_url\": \"http://www.gamesbutler.com/game/18379/xmas-chains/\", \"regions\": null, \"height\": 600, \"width\": 540, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/32363a60b3d47c8b.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DotGrowth-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DotGrowth-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000168\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570e1bfa69b4c.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FreecellDuplex-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FreecellDuplex-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25258\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae26ac0f4f4.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CoasterRacer3-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer-3\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/5738/live/embeddable_175738.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DragonVsMonster-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DragonVsMonster-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/dragon-vs-monster\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/38294/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SlipSlideSloth-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SlipSlideSloth-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Slip-Slide-Sloth,576742227280284594\", \"regions\": null, \"height\": 700, \"width\": 510, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/s/slip_slide_sloth/slip_slide_sloth.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PicnicPanicTd-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PicnicPanicTd-v0\", \"human_url\": \"http://armorgames.com/play/668\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/picnic-panic-td-668.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IceCreamFromSpace-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IceCreamFromSpace-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25474\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae360b962eb.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer2Lvl5-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacer2Lvl5-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0011/8219/live/embeddable_118219.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LuckyBalls-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LuckyBalls-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/lucky-balls\", \"regions\": null, \"height\": 420, \"width\": 560, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/2750/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl3-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FormulaRacerLvl6-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FormulaRacerLvl6-v0\", \"human_url\": \"http://www.kongregate.com/games/turboNuke/formula-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0010/9268/live/FormulaRacer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MysticIndiaPop-v0\": {\"readme_header\": null, \"categories\": [\"bubble shooter\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MysticIndiaPop-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Mystic-India%20Pop,576742227280285107\", \"regions\": null, \"height\": 634, \"width\": 870, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/m/mystic_india_pop/mystic_india_pop.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GemMania-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GemMania-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/gem-mania\", \"regions\": null, \"height\": 420, \"width\": 760, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/1103/game.swf?1438702680\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PiggysCupcakeQuest-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PiggysCupcakeQuest-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/piggys-cupcake-quest\", \"regions\": null, \"height\": 700, \"width\": 900, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/87995/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MonsterTruckFever-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MonsterTruckFever-v0\", \"human_url\": \"http://www.kongregate.com/games/fightclub69/monster-truck-fever\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"https://cdn3.kongcdn.com/game_icons/0048/3603/250x200.jpg?i10c=img.resize(width:171,height:137)\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DriftRunners-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.DriftRunners-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/drift-runners\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0003/9130/live/DriftRunners.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacerLvl6-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacerLvl6-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/3927/live/embeddable_93927.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BullfrogJigsawPuzzle-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BullfrogJigsawPuzzle-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/bullfrog-jigsaw-puzzle\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/17039/game.swf?1304178248\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PlopPlopLite-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PlopPlopLite-v0\", \"human_url\": \"http://armorgames.com/play/1641\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/plop-plop-lite-1641.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoffeeClicker-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CoffeeClicker-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000125\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cf60f0b569.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DancingWithShadows-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DancingWithShadows-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/evil-minion\", \"regions\": null, \"height\": 400, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/15172/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.OfficeTrap-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.OfficeTrap-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/officetrap/\", \"regions\": null, \"height\": 550, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/officetrap/officetrap.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.TheProfessionals3-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TheProfessionals3-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/fart-blaster\", \"regions\": null, \"height\": 480, \"width\": 650, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/15262/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EggzBlast-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EggzBlast-v0\", \"human_url\": \"http://www.arkadium.com/games/eggz-blast/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {\"relative\": {\"files\": [\"data/locale/en-US/strings.xml\", \"data/leveldata/eggz_as3_leveldata-classic-ex.xml\", \"data/eggz_as3_config.xml\", \"data/skins/classic.swf\", \"data/external_sounds/classic/rollover.mp3\", \"data/external_sounds/classic/mainloop.mp3\", \"data/external_sounds/classic/newgamesound.mp3\", \"data/external_sounds/classic/wallbouncesound.mp3\", \"data/external_sounds/classic/tictac.mp3\", \"data/external_sounds/classic/rollersound.mp3\", \"data/external_sounds/classic/plateclicksound.mp3\", \"data/external_sounds/classic/nextlinesound.mp3\", \"data/external_sounds/classic/nextlevelsound.mp3\", \"data/external_sounds/classic/glass.mp3\", \"data/external_sounds/classic/gameoversound.mp3\", \"data/external_sounds/classic/firesound.mp3\", \"data/external_sounds/classic/bombsound.mp3\", \"data/external_sounds/classic/barnyardintro.mp3\", \"data/external_sounds/classic/timercountdown.mp3\", \"data/external_sounds/classic/startGame.mp3\", \"data/external_sounds/classic/gulp.mp3\", \"config.txt\"], \"base\": \"http://amsarkadium-a.akamaihd.net/assets/global/game/eggz-blast/c5e2b877-e177-4897-befd-c1d0e22405ff\"}}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://amsarkadium-a.akamaihd.net/assets/global/game/eggz-blast/c5e2b877-e177-4897-befd-c1d0e22405ff/eggz-blast.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SonicBubbles-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SonicBubbles-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/sonicbubbles\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/23816/game.swf?1355936182\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dSportRampage-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3dSportRampage-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-sport-rampage/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-sport-rampage.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFuture-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFuture-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GSwitch-v0\": {\"readme_header\": null, \"categories\": [\"obstacle\", \"noscore\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GSwitch-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/gswitch/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/gswitch/gswitch.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.SpinSoar-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SpinSoar-v0\", \"human_url\": \"http://armorgames.com/play/1378\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/spin-soar-1378.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CowboyVsUfos-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CowboyVsUfos-v0\", \"human_url\": \"http://www.y8.com/games/cowboy_vs_ufos\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/90822/original/cowboy_vs_ufos.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DragonFortress-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DragonFortress-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25618\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eeadfc6c1a.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TrollingLionJump-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TrollingLionJump-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25316\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae2ed17e913.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ShootTheCircle-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ShootTheCircle-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25451\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae34783256c.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CatchTheStar-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CatchTheStar-v0\", \"human_url\": \"http://www.gamesbutler.com/game/3414/catch-the-star/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/catch_the_star.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FrozenImps-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FrozenImps-v0\", \"human_url\": \"http://www.gamesbutler.com/game/4348/frozen-imps/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/c045dc879131d648.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl10-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl10-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ChockABox-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ChockABox-v0\", \"human_url\": \"http://www.gamesbutler.com/game/3602/chock-a-box/\", \"regions\": null, \"height\": 500, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/chockABox.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SurfBuggy-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SurfBuggy-v0\", \"human_url\": \"http://www.gamesbutler.com/game/12131/surf-buggy/\", \"regions\": null, \"height\": 550, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/f84a91d791158368.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Scribble-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Scribble-v0\", \"human_url\": \"http://armorgames.com/play/51\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/scribble-51.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HungerHunter-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HungerHunter-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/hunger-hunter\", \"regions\": null, \"height\": 550, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/130016/game.swf?1421838711\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpaceMadness-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SpaceMadness-v0\", \"human_url\": \"http://armorgames.com/play/6156\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/space-madness-6156.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CopperheadJigsawPuzzle-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CopperheadJigsawPuzzle-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/copperhead-jigsaw-puzzle\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/17063/game.swf?1304178301\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CrystalCurse-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CrystalCurse-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Crystal-Curse,576742227280295053\", \"regions\": null, \"height\": 576, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://files.cdn.spilcloud.com/flash/CrystalCurseSpilgamesv7.swf?gp=1\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl8-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl8-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Bimmin2-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Bimmin2-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Bimmin-2,576742227280285141\", \"regions\": null, \"height\": 640, \"width\": 352, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/b/bimmin_2/Bimmin2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MidnightCanine-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MidnightCanine-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Midnight-Canine,576742227280284355\", \"regions\": null, \"height\": 600, \"width\": 450, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/m/MidnightCanine.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EasterBunnyCollectCarrots-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EasterBunnyCollectCarrots-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/easter-bunny-collect-carrots\", \"regions\": null, \"height\": 520, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/136995/game.swf?1458743075\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EffingWorms-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EffingWorms-v0\", \"human_url\": \"http://www.kongregate.com/games/EffingGames/effing-worms\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0008/5093/live/embeddable_85093.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl5-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl5-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Dodge-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Dodge-v0\", \"human_url\": \"http://armorgames.com/play/2963\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/dodge-2963.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Filler2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Filler2-v0\", \"human_url\": \"http://www.kongregate.com/games/SimianLogic/filler-2\", \"regions\": null, \"height\": 527, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0004/5215/live/filler2_kong.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Rbots-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Rbots-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Rbots,576742227280287400\", \"regions\": null, \"height\": 630, \"width\": 420, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/r/Rbots/RBots.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BlacksmithLab-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BlacksmithLab-v0\", \"human_url\": \"http://www.gamesbutler.com/game/25789/blacksmith-lab/\", \"regions\": null, \"height\": 525, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/blacksmithlab.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeroesOfMangaraTheFrostCrown-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HeroesOfMangaraTheFrostCrown-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000122\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cf4eb958c7.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Crane-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Crane-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Crane,576742227280283740\", \"regions\": null, \"height\": 720, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/c/Crane/Crane.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Cloud9-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Cloud9-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Cloud-9,576742227280284453\", \"regions\": null, \"height\": 320, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/c/cloud9/Cloud9_Girl.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LaserCannon3LevelsPack-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LaserCannon3LevelsPack-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000105\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570ceffa6050e.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DoodleGod2Walkthrough-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DoodleGod2Walkthrough-v0\", \"human_url\": \"http://www.kongregate.com/games/Badim/doodle-god-2-walkthrough\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0011/2258/live/embeddable_112258.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SmileyShowdown-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SmileyShowdown-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/smiley-showdown-2\", \"regions\": null, \"height\": 500, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/24529/game.swf?1380293746\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacerLvl3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacerLvl3-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/3927/live/embeddable_93927.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NinjaTrainingWorlds-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NinjaTrainingWorlds-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/parkour\", \"regions\": null, \"height\": 600, \"width\": 670, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/24373/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PoliceHotRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PoliceHotRacing-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/Police-Hot-Racing.html\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/flash10/Police-Hot-Racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ArmySpeeder-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ArmySpeeder-v0\", \"human_url\": \"http://www.cartitans.com/game/army-speeder/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/army-speeder.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpacePunkRacerLvl5-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.SpacePunkRacerLvl5-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/space-punk-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0012/4902/live/embeddable_124902.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LevelEditor3-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LevelEditor3-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Level-Editor-3,576742227280290903\", \"regions\": null, \"height\": 700, \"width\": 525, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://files.cdn.spilcloud.com/10/1432719159_level-editor-3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpectrumRunner-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SpectrumRunner-v0\", \"human_url\": \"http://www.kongregate.com/games/DigYourOwnGrave/spectrum-runner\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0011/6439/live/SpectrumRunner_secure.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BulletHeaven-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BulletHeaven-v0\", \"human_url\": \"http://www.kongregate.com/games/kupo707/bullet-heaven\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0010/8868/live/embeddable_108868.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BloodyMonstersPack2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BloodyMonstersPack2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000145\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cfb6966daf.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WhatsInsideTheBox-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WhatsInsideTheBox-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25523\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee8da97daa.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PumpkinMan-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PumpkinMan-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/pumpkin-man\", \"regions\": null, \"height\": 520, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/134070/game.swf?1445956649\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Dots-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Dots-v0\", \"human_url\": \"http://notdoppler.com/dots.php\", \"regions\": null, \"height\": 400, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/dots.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DriveToWreck2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DriveToWreck2-v0\", \"human_url\": \"http://1000webgames.com/play-9442-Drive-To-Wreck-2.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/drivetowreck2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CursedTreasureDontTouchMyGems-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CursedTreasureDontTouchMyGems-v0\", \"human_url\": \"http://notdoppler.com/cursedtreasure-donttouchmygems.php\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/cursedtreasure-donttouchmygems.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl13-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl13-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CastleRush-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CastleRush-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000174\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570e1c314df29.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Moosters-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Moosters-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Moosters,576742227280292396\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/m/Moosters/moosters.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HowDareYou-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HowDareYou-v0\", \"human_url\": \"http://www.kongregate.com/games/Geovizz/how-dare-you\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0020/3585/live/embeddable_203585.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GolfRun-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GolfRun-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/golf-run\", \"regions\": null, \"height\": 400, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/3317/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PearlBreaking-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PearlBreaking-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/pearl-breaking\", \"regions\": null, \"height\": 500, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/23609/game.swf?1354643738\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Lazerman-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Lazerman-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Lazerman,576742227280288022\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/l/Lazerman/lazerman.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.V8MuscleCars-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.V8MuscleCars-v0\", \"human_url\": \"http://insanehero.com/mygames/V8MuscleCars/index.html\", \"regions\": null, \"height\": 270, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://insanehero.com/mygames/V8MuscleCars/musclecars.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TheSilentPlanet-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TheSilentPlanet-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000608\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570f58ef42eb7.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AeroDefense-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AeroDefense-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/aero-defense\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/137425/game.swf?1460736899\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Resonance-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Resonance-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Resonance,576742227280287219\", \"regions\": null, \"height\": 700, \"width\": 525, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/r/Resonance/Resonance.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleHitPonyParade-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.BubbleHitPonyParade-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Bubble-Hit:-Pony-Parade,576742227280283866\", \"regions\": [{\"coordinates\": [493, 165, 220, 342], \"type\": \"noclick\"}], \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/b/bubble_hit_pony_parade/Bubble_Hit_Pony_Parade.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DeathCabin-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DeathCabin-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Death-Cabin,576742227280295342\", \"regions\": null, \"height\": 0, \"width\": 0, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://files.cdn.spilcloud.com/flash/DeathCabin.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DeadHungry2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DeadHungry2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000164\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570e1bead8df5.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DirkValentine-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DirkValentine-v0\", \"human_url\": \"http://www.nitrome.com/games/dirkvalentine/\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.nitrome.com/games/dirkvalentine/dirkvalentine.swf?v=10.0.0.0\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TurboCrew-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TurboCrew-v0\", \"human_url\": \"http://www.cartitans.com/game/turbo-crew/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/turbo-crew.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GardenRush-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GardenRush-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000170\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570e1c04ad079.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpectrumHeist-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SpectrumHeist-v0\", \"human_url\": \"http://armorgames.com/play/13386\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/spectrum-heist-13386.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AmigoPancho3SheriffSancho-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AmigoPancho3SheriffSancho-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Amigo-Pancho-3:-Sheriff-Sancho,576742227280287710\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/a/Amigo_pancho_3/AmigoPancho3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BlackForce-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BlackForce-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Black-Force,576742227280284173\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/b/BlackForce/BlackForce.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LineGameLimeEdition-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LineGameLimeEdition-v0\", \"human_url\": \"http://notdoppler.com/linegame-limeedition.php\", \"regions\": null, \"height\": 525, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/linegame-limeedition.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DragonChain-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DragonChain-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Dragon-Chain,576742227280289216\", \"regions\": null, \"height\": 510, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/d/Dragon-Chain/Dragon_Chain_v1.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CardinalQuest2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CardinalQuest2-v0\", \"human_url\": \"http://www.kongregate.com/games/randomnine/cardinal-quest-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9258/live/embeddable_179258.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DriftRunners2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.DriftRunners2-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/drift-runners-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0007/6628/live/embeddable_76628.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeySummer-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeySummer-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Hey-Summer,576742227280292511\", \"regions\": [{\"coordinates\": [601, 54, 84, 47], \"type\": \"noclick\"}], \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/h/Hey%20Summer/hey_summer_spil.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NightDrivin-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NightDrivin-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25264\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae26c9186c8.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LooneyAndJohny-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LooneyAndJohny-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/looney-and-johny\", \"regions\": null, \"height\": 475, \"width\": 775, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/38730/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"internet.SlitherIO-v0\": {\"categories\": [\"mmo\"], \"height\": 300, \"width\": 502, \"server_timestep_limit\": null, \"tags\": {}, \"id\": \"internet.SlitherIO-v0\", \"rewarder\": true, \"url\": \"http://slither.io/\", \"enable_internet\": true, \"autostart\": true}, \"flashgames.VirtualRacer-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.VirtualRacer-v0\", \"human_url\": \"http://www.cartitans.com/game/virtual-racer/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/virtual-racer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MonkeyManic-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MonkeyManic-v0\", \"human_url\": null, \"regions\": null, \"height\": 384, \"width\": 384, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/monkeymanic/monkeymanic.swf\", \"enable_internet\": false, \"serve_from_domain\": [\"andkon.com\"]}, \"flashgames.BulletHeaven2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BulletHeaven2-v0\", \"human_url\": \"http://www.kongregate.com/games/kupo707/bullet-heaven-2\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0024/7191/live/embeddable_247191.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Helicrane-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Helicrane-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/helicrane\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/130677/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CrapImBroke-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CrapImBroke-v0\", \"human_url\": \"http://www.gamesbutler.com/game/23248/crap!-i'm-broke/\", \"regions\": null, \"height\": 400, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/6a5b4c04d29c6efd.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Pointer-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Pointer-v0\", \"human_url\": \"http://notdoppler.com/pointer.php\", \"regions\": null, \"height\": 420, \"width\": 575, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/pointer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DragonFunflap-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DragonFunflap-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/dragon-funflap\", \"regions\": null, \"height\": 575, \"width\": 768, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/37961/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Skytrip-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Skytrip-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25366\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae30af7d6be.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperAdventurePalsBattleArena-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperAdventurePalsBattleArena-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25174\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae2509ad6c5.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CurveFever-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CurveFever-v0\", \"human_url\": \"http://www.games68.com/games.php?id=2126575\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/511136fc20ee0.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperK9-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperK9-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/super-k9\", \"regions\": null, \"height\": 400, \"width\": 600, \"extra_files\": {\"relative\": {\"files\": [\"level1.xml\", \"level2.xml\", \"level3.xml\", \"level4.xml\"], \"base\": \"http://www.freegamesforyourwebsite.com/game/super-k9\"}}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/12345/game.swf\", \"enable_internet\": false, \"serve_from_domain\": \"freeonlinegames.com\"}, \"flashgames.Sieger2LevelPack-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Sieger2LevelPack-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25528\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee8fb7ea9f.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IdleFarmer-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IdleFarmer-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000140\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cf951c5959.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterCars2Contact-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CoasterCars2Contact-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/Coaster-Cars-2-contact.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/flash4/Coaster-Cars-2-contact.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Stalingrad-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Stalingrad-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/stalingrad\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/14569/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NadiasRage-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"action\", \"adventure\", \"our\", \"1 player\", \"2 players\", \"2pg\", \"action\", \"blood\", \"fast\", \"flash\", \"free\", \"highscore\", \"multiplayer\", \"pixelated\", \"runner\", \"running\", \"survive\", \"zombies\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NadiasRage-v0\", \"human_url\": \"http://old.2pg.com/game/nadias-rage/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/nadias-rage.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MonsterTruckRally-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.MonsterTruckRally-v0\", \"human_url\": \"http://insanehero.com/mygames/MonsterTruckRally/index.html\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://insanehero.com/mygames/MonsterTruckRally/monstertruckrally.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CloseCombat-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CloseCombat-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/close-combat\", \"regions\": null, \"height\": 433, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/10195/game.swf\", \"enable_internet\": false, \"serve_from_domain\": \"freeonlinegames.com\"}, \"flashgames.HeroSimulator-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HeroSimulator-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000033\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cdfe5518e2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IceSlide-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IceSlide-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/ice-slide\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/23644/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.VideoGameMonster-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.VideoGameMonster-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Video-Game-Monster,576742227280295519\", \"regions\": null, \"height\": 720, \"width\": 520, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://files.cdn.spilcloud.com/flash/VideoGameMonstersV6.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Blosics3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Blosics3-v0\", \"human_url\": \"http://notdoppler.com/blosics3.php\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/blosics3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dSpeedFever-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3dSpeedFever-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-speed-fever/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-speed-fever.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ItsDarkInHell-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ItsDarkInHell-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/It%E2%80%99s-Dark-in-Hell,576742227280284687\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/i/ItsDarkInHell/its_dark_in_hell.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FrozenIslandsNewHorizons-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FrozenIslandsNewHorizons-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000025\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570c2227e1961.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AmigoPanchoInAfghanistan-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AmigoPanchoInAfghanistan-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25424\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae332255b8a.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GlobalRallyRacer-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GlobalRallyRacer-v0\", \"human_url\": \"http://turbonuke.com/games.php?game=globalrallyracer\", \"regions\": null, \"height\": 377, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://turbonuke.com/flashgames/turborally.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Firebug-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Firebug-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/firebug/\", \"regions\": null, \"height\": 540, \"width\": 660, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/firebug/firebug.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.Colorfill-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Colorfill-v0\", \"human_url\": \"http://armorgames.com/play/1632\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/colorfill-1632.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BlockysEscape-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BlockysEscape-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000023\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570c1f688b844.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MushyMishy-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MushyMishy-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25642\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eeb58a34c8.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ModelCarRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ModelCarRacing-v0\", \"human_url\": \"http://www.y8.com/games/model_car_racing\", \"regions\": null, \"height\": 343, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/72088/original/model_car_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MadpetSkateboarder2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MadpetSkateboarder2-v0\", \"human_url\": \"http://www.gamesbutler.com/game/8197/madpet-skateboarder-2/\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/808254660c6dd73d.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Madburger3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Madburger3-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000070\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cea906b079.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchTheFruits-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MatchTheFruits-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/match-the-fruits\", \"regions\": null, \"height\": 495, \"width\": 660, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/130460/game.swf?1425384870\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MarblesShooter-v0\": {\"readme_header\": null, \"categories\": [\"1 player\", \"flash\", \"shooting\", \"ball\", \"girl\", \"matching\", \"free\", \"match 3\", \"idnet\", \"bubble shooter\", \"idnet highscore\", \"idnet save\", \"idnet achievements\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MarblesShooter-v0\", \"human_url\": \"http://www.y8.com/games/marbles_shooter\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/106816/original/marbles_shooter.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NoughtsAndCrossesExtreme-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NoughtsAndCrossesExtreme-v0\", \"human_url\": \"http://old.2pg.com/game/noughts-and-crosses-extreme/play/\", \"regions\": null, \"height\": 480, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/N/noughts-and-crosses-extreme.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer2Lvl9-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacer2Lvl9-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0011/8219/live/embeddable_118219.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MarsColonyTd-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MarsColonyTd-v0\", \"human_url\": \"http://1000webgames.com/play-9852-Mars-Colony-TD.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/mars-colony-td.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpacemanMax-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SpacemanMax-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Spaceman-Max,576742227280285516\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/s/Spaceman_max/spaceman_max.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.KitchenRestaurantCleanUp-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.KitchenRestaurantCleanUp-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25412\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae32a818de9.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DoubleEdged-v0\": {\"readme_header\": null, \"categories\": [\"fighting\", \"noscore\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DoubleEdged-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/doubleedged/\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/doubleedged/doubleedged.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.DontPanic-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DontPanic-v0\", \"human_url\": \"http://armorgames.com/play/11366\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/dont-panic-11366.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl9-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl9-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MysteriousPirateJewels-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MysteriousPirateJewels-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Mysterious-Pirate-Jewels,576742227280291805\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://games.cdn.spilcloud.com/container_df9aa4793b5/1398853638_mysteriouspiratejewels.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DetectiveConrad-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DetectiveConrad-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/pointless\", \"regions\": null, \"height\": 400, \"width\": 360, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/3145/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AnimeClicker2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AnimeClicker2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000053\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570ce7dd8ff69.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Ditloid-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Ditloid-v0\", \"human_url\": \"http://www.gamesbutler.com/game/4070/ditloid/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/0b48701f0bcc080a.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WishTotems-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WishTotems-v0\", \"human_url\": \"http://www.gamesbutler.com/game/11540/wish-totems/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/062b2d8ab1ab511a.swf?goto=norm\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpaceColony-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.SpaceColony-v0\", \"human_url\": \"http://www.cartitans.com/game/space-colony/\", \"regions\": null, \"height\": 458, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/space-colony.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Stargrazer-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Stargrazer-v0\", \"human_url\": \"http://armorgames.com/play/14095\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/stargrazer-14095.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Colordefense-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Colordefense-v0\", \"human_url\": \"http://armorgames.com/play/106\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/colordefense-106.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.21Balloons-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.21Balloons-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/21-balloons\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/38435/game.swf?1372772447\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Clusterobot-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Clusterobot-v0\", \"human_url\": \"http://armorgames.com/play/1513\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/clusterobot-1513.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpacePunkRacerLvl3-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.SpacePunkRacerLvl3-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/space-punk-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0012/4902/live/embeddable_124902.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AspenSecret-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AspenSecret-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25644\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eeb5f070a0.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl8-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl8-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Cooliodj-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Cooliodj-v0\", \"human_url\": \"http://armorgames.com/play/103\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/cooliodj-103.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Nook-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Nook-v0\", \"human_url\": \"http://armorgames.com/play/6376\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/nook-6376.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Legor9-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Legor9-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25591\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eea61c62ac.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Commando-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Commando-v0\", \"human_url\": \"http://www.miniclip.com/games/commando/en/\", \"regions\": null, \"height\": 300, \"width\": 400, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/commando/en/commando.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MotherLoad-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MotherLoad-v0\", \"human_url\": null, \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0004/6879/live/motherloaddemo.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CastleSolitaire-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CastleSolitaire-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Castle-Solitaire,576742227280283526\", \"regions\": null, \"height\": 700, \"width\": 510, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/c/castle_solitaire/castle_solitaire.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WackyStrike-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WackyStrike-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25426\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae33511b43d.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Gameinit-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Gameinit-v0\", \"human_url\": \"http://www.gamesbutler.com/game/24358/game-init/\", \"regions\": null, \"height\": 480, \"width\": 704, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/game_init_060415.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl7-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl7-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterCars2Megacross-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CoasterCars2Megacross-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/Coaster-Cars-2-megacross.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/flash4/Coaster-Cars-2-megacross.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlappyPanda-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlappyPanda-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/flappy-panda\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/130999/game.swf?1429190148\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MissionEscapeTheDojo-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MissionEscapeTheDojo-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25540\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee93752380.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ClimbOrDrown2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ClimbOrDrown2-v0\", \"human_url\": \"http://www.gamesbutler.com/game/18063/climb-or-drown-2/\", \"regions\": null, \"height\": 500, \"width\": 450, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/climbordrown2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpaceBounty-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SpaceBounty-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/space-bounty\", \"regions\": null, \"height\": 580, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/15023/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PlaneRace2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PlaneRace2-v0\", \"human_url\": \"http://1000webgames.com/play-9947-Plane-Race-2.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/planerace2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JollySwipeLevelPack-v0\": {\"readme_header\": null, \"categories\": [\"1 player\", \"flash\", \"shooting\", \"matching\", \"fun\", \"funny\", \"free\", \"idnet\", \"idnet highscore\", \"idnet save\", \"idnet achievements\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JollySwipeLevelPack-v0\", \"human_url\": \"http://www.y8.com/games/jolly_swipe_level_pack\", \"regions\": null, \"height\": 640, \"width\": 360, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/110216/original/jolly_swipe_lp.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.V8MuscleCars2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.V8MuscleCars2-v0\", \"human_url\": \"http://insanehero.com/mygames/V8MuscleCars2/index.html\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://insanehero.com/mygames/V8MuscleCars2/v8musclecars2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AmericanRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.AmericanRacing-v0\", \"human_url\": \"http://www.kongregate.com/games/turboNuke/american-racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0015/6925/live/AmericanRacing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BirdSlice-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BirdSlice-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/bird-slice\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/128707/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TutiFruti-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TutiFruti-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/tuti-fruti\", \"regions\": null, \"height\": 600, \"width\": 710, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/39604/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AirWar1941-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AirWar1941-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/air-war-1941\", \"regions\": null, \"height\": 600, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/130205/game.swf?1423063288\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlashRacer-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlashRacer-v0\", \"human_url\": \"http://armorgames.com/play/1321\", \"regions\": null, \"height\": 600, \"width\": 650, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/flash-racer-1321.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dFuriousDriver-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3dFuriousDriver-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-furious-driver/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-furious-driver.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl5-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl5-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SkyKnight2-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SkyKnight2-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/sky-knight-2\", \"regions\": null, \"height\": 570, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/37789/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Pel-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Pel-v0\", \"human_url\": \"http://armorgames.com/play/2011\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/pel-2011.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SmileyJumpFest-v0\": {\"readme_header\": null, \"categories\": [\"match 3\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.SmileyJumpFest-v0\", \"human_url\": \"http://www.smileygamer.com/ourgames/smileyjumpfest.html\", \"regions\": null, \"height\": 400, \"width\": 540, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.smileygamer.com/ourgames/SmileyJumpFest.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MonsterLabFeedThemAll-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MonsterLabFeedThemAll-v0\", \"human_url\": \"http://www.gamesbutler.com/game/25201/monster-lab:-feed-them-all/\", \"regions\": null, \"height\": 600, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/MonsterLab_GamesButler2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.StreetRace3-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.StreetRace3-v0\", \"human_url\": \"http://insanehero.com/mygames/StreetRace3/index.html\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://insanehero.com/mygames/StreetRace3/streetrace3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SmileyPuzzle2-v0\": {\"readme_header\": null, \"categories\": [\"match 3\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.SmileyPuzzle2-v0\", \"human_url\": \"http://www.kongregate.com/games/SmileyGamer/smiley-puzzle-2\", \"regions\": null, \"height\": 540, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0013/0459/live/smileypuzzle2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JungleCrash-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JungleCrash-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/jungle-crash\", \"regions\": [{\"coordinates\": [475, 57, 535, 30], \"type\": \"noclick\"}], \"height\": 500, \"width\": 520, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/2883/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Mrbirdie-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Mrbirdie-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/mrbirdie\", \"regions\": null, \"height\": 640, \"width\": 820, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/129975/game.swf?1421666755\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Gluey2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Gluey2-v0\", \"human_url\": \"http://notdoppler.com/gluey2.php\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/gluey2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FoxSnakeJigsawPuzzle-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FoxSnakeJigsawPuzzle-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/fox-snake-jigsaw-puzzle\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/17024/game.swf?1304178365\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PaperDefense-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PaperDefense-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Paper-Defense,576742227280284997\", \"regions\": null, \"height\": 420, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/p/PaperDefense/PaperDefense.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dMuscleCarRacer-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3dMuscleCarRacer-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-muscle-car-racer/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-muscle-car-racer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FrogEatFlies-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FrogEatFlies-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/frog-eat-flies\", \"regions\": null, \"height\": 568, \"width\": 528, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/138140/game.swf?1464269993\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NewSiberianSupercarsRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.NewSiberianSupercarsRacing-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/New-Siberian-SuperCars-Racing.html\", \"regions\": null, \"height\": 375, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/d/file/20130910/e178ce75aee29e77358ac3f3421b257d.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl7-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl7-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Gemcraft-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Gemcraft-v0\", \"human_url\": \"http://armorgames.com/play/1716\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/gemcraft-1716.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PirateRunAway-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PirateRunAway-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/pirate-run-away\", \"regions\": null, \"height\": 480, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/133133/game.swf?1441621081\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ReleaseTheMooks3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ReleaseTheMooks3-v0\", \"human_url\": \"http://www.gamesbutler.com/game/11238/release-the-mooks-3/\", \"regions\": null, \"height\": 500, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/2cafb3d8a428cec8.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CatGodVsSunKing2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CatGodVsSunKing2-v0\", \"human_url\": \"http://www.kongregate.com/games/nerdook/cat-god-vs-sun-king-2\", \"regions\": null, \"height\": 480, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0016/8603/live/embeddable_168603.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl4-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl4-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Deliveryman-v0\": {\"readme_header\": null, \"categories\": [\"keyboard only\", \"old school\", \"puzzle\", \"pixel\", \"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Deliveryman-v0\", \"human_url\": \"http://armorgames.com/play/7032\", \"regions\": null, \"height\": \"\", \"width\": \"\", \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/deliveryman-7032.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Bullets-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Bullets-v0\", \"human_url\": \"http://armorgames.com/play/1526\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/bullets-1526.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRaceLvl4-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.NeonRaceLvl4-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/7872/live/embeddable_97872.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CrystalStoryIi-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CrystalStoryIi-v0\", \"human_url\": \"http://www.kongregate.com/games/lan14n/crystal-story-ii\", \"regions\": null, \"height\": 450, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/0066/live/embeddable_190066.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoastRunners-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.CoastRunners-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coast-runners\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0010/6635/live/CoastRunners.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DragonChronicles-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DragonChronicles-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Dragon-Chronicles,576742227280284419\", \"regions\": null, \"height\": 700, \"width\": 525, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/d/dragon_chronicles/DragonChronicle.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BackHome-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BackHome-v0\", \"human_url\": \"http://www.gamesbutler.com/game/4345/back-home/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/c0b6560e524b2321.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GunpowderAndFeathers-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\", \"sparsereward\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GunpowderAndFeathers-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/gunpowderandfeathers/\", \"regions\": null, \"height\": 525, \"width\": 650, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/gunpowderandfeathers/gunpowderandfeathers.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.KangoIslands-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.KangoIslands-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25374\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae30ea46ab6.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Blix-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Blix-v0\", \"human_url\": \"http://www.y8.com/games/blix\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/121639/original/blix.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IslandDefense-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IslandDefense-v0\", \"human_url\": \"http://www.y8.com/games/island_defense\", \"regions\": null, \"height\": 800, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/110358/original/island_defense.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Pointless-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Pointless-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/pointless\", \"regions\": null, \"height\": 400, \"width\": 360, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/3145/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HoleInOne-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HoleInOne-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25663\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eebc4281b2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperBomb-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperBomb-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25232\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae2619f23d9.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.30Seconds-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.30Seconds-v0\", \"human_url\": \"http://www.gamesbutler.com/game/2406/30-seconds/\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/30seconds.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SmileyPuzzleGirlEdition-v0\": {\"readme_header\": null, \"categories\": [\"match 3\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SmileyPuzzleGirlEdition-v0\", \"human_url\": \"http://www.smileygamer.com/ourgames/spge.html\", \"regions\": null, \"height\": 400, \"width\": 540, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.smileygamer.com/ourgames/SmileyPuzzleGirlEdition.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DuskDrive-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.DuskDrive-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/dusk-drive\", \"regions\": null, \"height\": 512, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0022/3733/live/embeddable_223733.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpacePunkRacerLvl7-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.SpacePunkRacerLvl7-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/space-punk-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0012/4902/live/embeddable_124902.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Ics2-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Ics2-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/ICS-2,576742227280298418\", \"regions\": null, \"height\": 720, \"width\": 540, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://files.cdn.spilcloud.com/df9aa4793b5/ICSII-12-01/ICSII.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperBattleCity2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperBattleCity2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25168\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae24e8d8e16.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BugsGotGuns-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BugsGotGuns-v0\", \"human_url\": \"http://old.2pg.com/game/bugs-got-guns/play/\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/Bugs-Got-Guns.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DungeonBlocks-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DungeonBlocks-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/dungeon-blocks\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/122005/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ShortCircuit-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ShortCircuit-v0\", \"human_url\": \"http://armorgames.com/play/1369\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/short-circuit-1369.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl8-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl8-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl16-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl16-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BalloonGods-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BalloonGods-v0\", \"human_url\": \"http://old.2pg.com/game/balloon-gods/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/B/balloon-gods.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PinBalls-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.PinBalls-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Pin-Balls,576742227280283910\", \"regions\": [{\"coordinates\": [95, 173, 105, 32], \"type\": \"noclick\"}], \"height\": 600, \"width\": 730, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/p/pinballs/pin_balls_family.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterCarsCJackTrack-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CoasterCarsCJackTrack-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/Coaster-Cars-C-Jack-track.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/flash4/Coaster-Cars-C-Jack-track.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleBlubbs-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BubbleBlubbs-v0\", \"human_url\": \"http://armorgames.com/play/272\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/bubble-blubbs-272.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FitItQuick-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FitItQuick-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/fit-it-quick\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesforwebsites.com/game/fit-it-quick\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ParticleWarsExtreme-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ParticleWarsExtreme-v0\", \"human_url\": \"http://armorgames.com/play/10915\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/particle-wars-extrem-10915.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DiamondCrashMania-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DiamondCrashMania-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/diamond-crash-mania\", \"regions\": null, \"height\": 640, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/130174/game.swf?1422975934\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Hotspot-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Hotspot-v0\", \"human_url\": \"http://notdoppler.com/hotspot.php\", \"regions\": null, \"height\": 470, \"width\": 570, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/hotspot.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RiseOfChampions-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RiseOfChampions-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000099\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cef7cbbd9b.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FairyDefense-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FairyDefense-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Fairy-Defense,576742227280289553\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {\"absolute\": [\"http://api.configar.org/cf/pb/1/settings/0/0/bb131084ad822fdda12a4298ff20a460\"]}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/a10/fairydefense/FairyDefense.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Stalingrad3-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Stalingrad3-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/stalingrad-3\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/15082/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlashBombs-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.FlashBombs-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/flash-bombs\", \"regions\": null, \"height\": 440, \"width\": 728, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/14898/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PigDestroyer-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PigDestroyer-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25242\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae263c6da8b.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl14-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl14-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PrincessBubblesRescuePrince-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PrincessBubblesRescuePrince-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Princess-Bubbles:-Rescue-Prince,576742227280288544\", \"regions\": null, \"height\": 500, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/p/Princess_Bubbles.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NinjaPandaArena-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"arcade\", \"our\", \"1 player\", \"2 players\", \"2pg\", \"arcade\", \"collecting\", \"flash\", \"free\", \"fruits\", \"keyboard\", \"ninja\", \"ninjas\", \"pandas\", \"survive\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NinjaPandaArena-v0\", \"human_url\": \"http://old.2pg.com/game/ninja-panda-arena/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/N/ninja-panda-arena.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PingPongSurvival-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PingPongSurvival-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/ping-pong-survival\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/133266/game.swf?1442326056\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BalloonsPop-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BalloonsPop-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25515\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee8b819e87.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MonkeyBlast-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MonkeyBlast-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/monkey-blast\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/122780/game.swf?1401789576\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ZombiesMustDie-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ZombiesMustDie-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Zombies-Must-Die!,576742227280283826\", \"regions\": null, \"height\": 700, \"width\": 420, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/z/ZombiesMustDie/zombie_localizing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DriftRunners3d-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DriftRunners3d-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/drift-runners-3d\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0015/2352/live/DriftRunners3D.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SnailBob4-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SnailBob4-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Snail-Bob-4,576742227280288106\", \"regions\": null, \"height\": 640, \"width\": 520, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/s/SnailBob4/SnailBobSpace.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Funkostroll-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Funkostroll-v0\", \"human_url\": \"http://armorgames.com/play/6592\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/funk-o-stroll-6592.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Pyro-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Pyro-v0\", \"human_url\": \"http://armorgames.com/play/3174\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/pyro-3174.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Foosball2Player-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Foosball2Player-v0\", \"human_url\": \"http://old.2pg.com/game/foosball-2-player/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/F/foosball-2-player.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GravityBall-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GravityBall-v0\", \"human_url\": \"http://www.gamesbutler.com/game/2457/gravity-ball/\", \"regions\": null, \"height\": 500, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/gravityball.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MotoMadness-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.MotoMadness-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/moto-madness\", \"regions\": null, \"height\": 367, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/15170/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CarrotFantasy-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CarrotFantasy-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/carrot-fantasy\", \"regions\": null, \"height\": 690, \"width\": 960, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/38450/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CandySlider-v0\": {\"readme_header\": null, \"categories\": [\"match 3\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CandySlider-v0\", \"human_url\": \"http://www.smileygamer.com/ourgames/candyslider.html\", \"regions\": null, \"height\": 400, \"width\": 540, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.smileygamer.com/ourgames/CandySlider.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GalacticGems2Accelerated-v0\": {\"readme_header\": null, \"categories\": [\"match 3\", \"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GalacticGems2Accelerated-v0\", \"human_url\": \"http://www.kongregate.com/games/MikRad/galactic-gems-2-accelerated\", \"regions\": null, \"height\": 527, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://assets.kongregate.com/gamez/0018/6168/live/Galactic_Gems_2_Accel.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MashaCollectsButterflies-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MashaCollectsButterflies-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/masha-collects-butterflies\", \"regions\": null, \"height\": 520, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/137594/game.swf?1461681034\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Thaw-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Thaw-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Thaw,576742227280287201\", \"regions\": null, \"height\": 700, \"width\": 525, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/t/Thaw/Thaw.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DinoBubble-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DinoBubble-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25639\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eeb4c9ca47.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DoughSnake-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DoughSnake-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/dough-snake\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/39935/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dTruckInTheWoods-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3dTruckInTheWoods-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-truck-in-the-woods/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-truck-in-the-woods.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DrawGems-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DrawGems-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/draw-gems\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/24134/game.swf?1359377583\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchCraft-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MatchCraft-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/match-craft\", \"regions\": null, \"height\": 500, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/133841/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchCrypt-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MatchCrypt-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/match-crypt\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/133603/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.OozingForever-v0\": {\"readme_header\": null, \"categories\": [\"platform\", \"sparsereward\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.OozingForever-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/oozingforever/\", \"regions\": null, \"height\": 400, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/oozingforever/oozingforever.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.GameInit-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GameInit-v0\", \"human_url\": \"http://www.gamesbutler.com/game/24358/game-init/\", \"regions\": null, \"height\": 480, \"width\": 704, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/game_init_060415.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TerrestrialConflict-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TerrestrialConflict-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25651\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eeb8710e37.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Indefinite-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Indefinite-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25363\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae309b07247.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GonAndMon-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"adventure\", \"featured\", \"our\", \"1 player\", \"2 player\", \"2pg\", \"multitask\", \"obstacles\", \"platform\", \"puzzle\", \"thinking\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GonAndMon-v0\", \"human_url\": \"http://old.2pg.com/game/gon-and-mon/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/G/gonandmon.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RedFuryRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.RedFuryRacing-v0\", \"human_url\": \"http://www.cartitans.com/game/red-fury-racing/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/red-fury-racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CanyonValleyRally-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CanyonValleyRally-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/canyon-valley-rally\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/22103/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.V8RacingChampion-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.V8RacingChampion-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/V8-Racing-Champion.html\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/d/file/20160104/52c041834531bec15188ae32fc807486.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperDash-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"kids\", \"our\", \"1 player\", \"2 players\", \"2pg\", \"avoid\", \"bombs\", \"bonus\", \"collecting\", \"flash\", \"fun\", \"highscore\", \"keyboard\", \"kids\", \"pixelated\", \"powerups\", \"record\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.SuperDash-v0\", \"human_url\": \"http://old.2pg.com/game/super-dash/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/superdash2pg_1365939264.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Stickylinky-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Stickylinky-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/StickyLinky,576742227280287416\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/s/Sticky_linky/stickylinky-primary.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacerLvl7-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacerLvl7-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/3927/live/embeddable_93927.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AbductionGrannysVersion-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AbductionGrannysVersion-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25219\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae25e64a173.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DodgeAndCrash-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.DodgeAndCrash-v0\", \"human_url\": \"http://www.cartitans.com/game/dodge-and-crash/\", \"regions\": null, \"height\": 458, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/upload/games/1945/5527750151.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ShamelessClone2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ShamelessClone2-v0\", \"human_url\": \"http://old.2pg.com/game/shameless-clone-2-player/play/\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/sc_1362356708.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BlastTheMooks-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BlastTheMooks-v0\", \"human_url\": \"http://www.gamesbutler.com/game/8072/blast-the-mooks/\", \"regions\": null, \"height\": 550, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/b2fbcb8fd552e685.swf?goto=norm\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ReverseBoots-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ReverseBoots-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Reverse-Boots,576742227280288523\", \"regions\": null, \"height\": 680, \"width\": 510, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/r/Reverse_boots/ReverseBoots_final.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"internet.SlitherIONoSkins-v0\": {\"categories\": [\"mmo\"], \"height\": 300, \"width\": 502, \"server_timestep_limit\": null, \"tags\": {}, \"id\": \"internet.SlitherIONoSkins-v0\", \"rewarder\": true, \"url\": \"http://slither.io/\", \"enable_internet\": true, \"autostart\": true}, \"flashgames.TheCubicMonkeyAdventures2-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TheCubicMonkeyAdventures2-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/the-cubic-monkey-adventures-2\", \"regions\": null, \"height\": 400, \"width\": 650, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/137905/game.swf?1463066352\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Knighttron-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Knighttron-v0\", \"human_url\": \"http://armorgames.com/play/17722\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/knighttron-17722.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ClickerMonsters-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ClickerMonsters-v0\", \"human_url\": \"http://www.gamesbutler.com/game/22147/clicker-monsters/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/5631f1a3aeab59b4.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MonsterChains-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MonsterChains-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25224\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae25fd38c07.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Long_short-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Long_short-v0\", \"human_url\": \"http://www.gamesbutler.com/game/7178/long_short/\", \"regions\": null, \"height\": 570, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/04086cc3dda3ab24.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PufferFish-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PufferFish-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/puffer-fish\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/129225/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FishAndDestroy-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FishAndDestroy-v0\", \"human_url\": \"http://old.2pg.com/game/fish-and-destroy/play/\", \"regions\": null, \"height\": 550, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/fishanddestroy2pg.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperIdleMaster-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperIdleMaster-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000059\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570ce84414182.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleRubble-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BubbleRubble-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/bubble-rubble-the-island\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/131725/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PoliceInterceptor-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PoliceInterceptor-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/police-interceptor\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/35111/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl12-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl12-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Zombonarium-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Zombonarium-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Zombonarium,576742227280294623\", \"regions\": null, \"height\": 800, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://files.cdn.spilcloud.com/flash/zombonarium.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LetsFall-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LetsFall-v0\", \"human_url\": \"http://www.y8.com/games/let_s_fall_\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/88523/original/let_s_fall_.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MinicarHunt-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.MinicarHunt-v0\", \"human_url\": \"http://www.cartitans.com/game/minicar-hunt/\", \"regions\": null, \"height\": 458, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/upload/games/1749/4952196422.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EasterEggSlider-v0\": {\"readme_header\": null, \"categories\": [\"match 3\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EasterEggSlider-v0\", \"human_url\": \"http://www.smileygamer.com/ourgames/eastereggslider.html\", \"regions\": null, \"height\": 540, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.smileygamer.com/ourgames/EasterEggSlider-NoAds.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvasiveRacers-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.EvasiveRacers-v0\", \"human_url\": \"http://www.cartitans.com/game/evasive-racers/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/evasive-racers.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AerobaticMaster2-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AerobaticMaster2-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/aerobatic-master-2\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/22626/game.swf?1363780279\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Quick-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Quick-v0\", \"human_url\": \"http://notdoppler.com/quick.php\", \"regions\": null, \"height\": 516, \"width\": 654, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/quick.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AngryNewsVan-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.AngryNewsVan-v0\", \"human_url\": \"http://www.cartitans.com/game/angry-news-van/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/angry-news-van.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RollerRider-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.RollerRider-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/roller-rider\", \"regions\": null, \"height\": 512, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0021/6804/live/embeddable_216804.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DreamChristmasLink-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DreamChristmasLink-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Dream-Christmas%20Link,576742227280285619\", \"regions\": null, \"height\": 634, \"width\": 870, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/d/dream_christmas_link/dream_christmas_link.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ChickInduce-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ChickInduce-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/chick-induce\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/140741/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TankStorm2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TankStorm2-v0\", \"human_url\": \"http://1000webgames.com/play-8708-Tank-Storm-2.html\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/tankstorm2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PickUpTruckRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PickUpTruckRacing-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/pick-up-truck-racing\", \"regions\": null, \"height\": 500, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/38128/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Kawairun-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"action\", \"cool games\", \"featured\", \"our\", \"1 player\", \"2 players\", \"gameboltz\", \"jumping\", \"kawairun\", \"multiplayer\", \"obstacles\", \"run\", \"runner\", \"running\", \"skills\", \"upgrades\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.Kawairun-v0\", \"human_url\": \"http://old.2pg.com/game/kawairun/play/\", \"regions\": null, \"height\": 400, \"width\": 650, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/Kawairun.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RhythmRockets-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RhythmRockets-v0\", \"human_url\": \"http://armorgames.com/play/6449\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/rhythm-rockets-6449.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Snake-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Snake-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/snake\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/111118/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl6-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl6-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleTub-v0\": {\"readme_header\": null, \"categories\": [\"bubble\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.BubbleTub-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Bubble-Tub,576742227280285413\", \"regions\": null, \"height\": 580, \"width\": 870, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/b/BubbleTub/BubbleTub.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MedievalShark-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MedievalShark-v0\", \"human_url\": \"http://armorgames.com/play/14007\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/medieval-shark-14007.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubblesInSpace-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"our\", \"shooting\", \"1 player\", \"2 players\", \"2pg\", \"aim\", \"bubble\", \"bubbles\", \"color\", \"flash\", \"free\", \"match\", \"matching\", \"shooter\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BubblesInSpace-v0\", \"human_url\": \"http://old.2pg.com/wp-content/games/custom/B/bubbles-in-space.swf\", \"regions\": null, \"height\": null, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"640\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FarmRush-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FarmRush-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000006\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570c13d620f79.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ThePretenderPartThree-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ThePretenderPartThree-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/The-Pretender:-Part-Three,576742227280285438\", \"regions\": null, \"height\": 755, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/t/the_pretender_3/PretenderPartThree_v3.0b.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AircraftRace-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AircraftRace-v0\", \"human_url\": \"http://1000webgames.com/play-10100-Aircraft-Race.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/aircraftrace.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RabbitPlanetEscape-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RabbitPlanetEscape-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25250\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae266ff40eb.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlappyBat-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlappyBat-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/flabby-bat\", \"regions\": null, \"height\": 432, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/121993/game.swf?1399478529\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpellIdle2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SpellIdle2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000002\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570c0e9900cee.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Oddball2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Oddball2-v0\", \"human_url\": \"http://armorgames.com/play/1220\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/oddball-2-1220.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FormulaRacerLvl3-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FormulaRacerLvl3-v0\", \"human_url\": \"http://www.kongregate.com/games/turboNuke/formula-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0010/9268/live/FormulaRacer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AmericanRacing2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AmericanRacing2-v0\", \"human_url\": \"http://turbonuke.com/games.php?game=americanracing2\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://turbonuke.com/flashgames/globalrallyracer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PaulVaulting-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PaulVaulting-v0\", \"human_url\": \"http://www.gamesbutler.com/game/17214/paul-vaulting/\", \"regions\": null, \"height\": 480, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/paul_vaulting2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TowerMoon-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TowerMoon-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/tower-moon\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/21680/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SnowQueen4-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SnowQueen4-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Snow-Queen-4,576742227280290589\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/s/snowqueen4/snowqueen41.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RainbowDrops-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"adventure\", \"girl\", \"our\", \"1 player\", \"2 players\", \"2pg\", \"avoid\", \"distance\", \"flash\", \"highscore\", \"love\", \"multiplayer\", \"rainbow\", \"running\", \"skill\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RainbowDrops-v0\", \"human_url\": \"http://old.2pg.com/game/rainbow-drops/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/rainbow_drops_2pg_1374836963.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RollingHills-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RollingHills-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Rolling-Hills,576742227280285050\", \"regions\": null, \"height\": 640, \"width\": 350, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/r/RollingHills/RollingHills.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Multitask-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Multitask-v0\", \"human_url\": null, \"regions\": null, \"height\": 530, \"width\": 740, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0005/3248/live/MultitaskMOCHIcompleteAZERTY.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TankStorm-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TankStorm-v0\", \"human_url\": \"http://1000webgames.com/play-8127-Tank-Storm.html\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/tank-storm.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BloodbathBay-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BloodbathBay-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/bloodbath-bay\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/19272/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.KartingSuperGo-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.KartingSuperGo-v0\", \"human_url\": \"http://www.kongregate.com/games/fightclub69/karting-super-go\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"https://cdn4.kongcdn.com/game_icons/0047/2708/250x200.jpg?i10c=img.resize(width:171,height:137)\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DnaLabRush-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DnaLabRush-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/dna-lab-rush\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/137217/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RetroRunner-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"adventure\", \"our\", \"1 player\", \"2 players\", \"2pg\", \"avoid\", \"coins\", \"collecting\", \"free\", \"highscore\", \"jump\", \"pixelated\", \"retro\", \"runner\", \"running\", \"score\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.RetroRunner-v0\", \"human_url\": \"http://old.2pg.com/game/retro-runner/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/retro_runner_2pg_1377290931.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CarrotFantasyExtreme2-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CarrotFantasyExtreme2-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/carrot-fantasy-extreme-2\", \"regions\": null, \"height\": 690, \"width\": 960, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/39398/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SavingLittleAlien-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SavingLittleAlien-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25517\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee8bd071bb.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CakeQuest-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CakeQuest-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/cake-quest\", \"regions\": null, \"height\": 410, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/15167/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FreeSouls-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FreeSouls-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000160\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570e19c5735b8.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JumpOverTheRings-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JumpOverTheRings-v0\", \"human_url\": \"http://www.gamesbutler.com/game/25738/jump-over-the-rings/\", \"regions\": null, \"height\": 450, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/a2272590c846cffc.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer2Lvl3-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacer2Lvl3-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0011/8219/live/embeddable_118219.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FasterMiterMaster-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FasterMiterMaster-v0\", \"human_url\": \"http://armorgames.com/play/6375\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/faster-miter-master-6375.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WorldsGuard2-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WorldsGuard2-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/World's-Guard-2,576742227280289032\", \"regions\": null, \"height\": 520, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/w/Worlds_guard2/game_worlds_guard_2_spil.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CruiseAdventure-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CruiseAdventure-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000760\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570f8f0feaee2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Underrun-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Underrun-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/underrun\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/24520/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Raze3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Raze3-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000066\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570ce9a763ba2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Match3ChristmasPack-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Match3ChristmasPack-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/match-3-christmas-pack\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/129734/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl15-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl15-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AchilliaTheGame-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AchilliaTheGame-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25550\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee9776dd00.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TankStorm4-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TankStorm4-v0\", \"human_url\": \"http://1000webgames.com/play-10136-Tank-Storm-4.html\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/tankstorm4.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LonelyEscapeAsylum-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LonelyEscapeAsylum-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25532\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee91568d8e.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ThatRedButton-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ThatRedButton-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000021\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570c1f2a17124.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LawnmowerRacing3d-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LawnmowerRacing3d-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/lawnmower-racing-3d\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/22142/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.OffRoaders3d-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.OffRoaders3d-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/off-roaders-3d\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/21957/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FunnyEaster-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"seasonal\", \"fun\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FunnyEaster-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Funny-Easter,576742227280291407\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/f/funny%20easter/funny_easter_spil.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TrafficCollision-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TrafficCollision-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25604\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eea8dd00c1.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CarrotFantasy2Undersea-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CarrotFantasy2Undersea-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/carrot-fantasy-2-undersea\", \"regions\": null, \"height\": 690, \"width\": 960, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/38968/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BumbleTumble-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\", \"online save\", \"cute\", \"bug\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BumbleTumble-v0\", \"human_url\": \"http://cache.armorgames.com/files/games/bumble-tumble-6452.swf\", \"regions\": null, \"height\": null, \"width\": \"\", \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FreakyRun-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"action\", \"our\", \"1 player\", \"2 player\", \"2pg\", \"collect\", \"comics\", \"freak\", \"multiplayer\", \"our\", \"run\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FreakyRun-v0\", \"human_url\": \"http://old.2pg.com/game/freaky-run/play/\", \"regions\": null, \"height\": 600, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/freaky-run-2pg.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DaleAndPeakot-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DaleAndPeakot-v0\", \"human_url\": \"http://www.miniclip.com/games/dale-and-peakot/en/\", \"regions\": null, \"height\": 540, \"width\": 720, \"extra_files\": {\"relative\": {\"files\": [\"dalePeakot_JB_LevelsAssets.swf\"], \"base\": \"http://www.miniclip.com/games/dale-and-peakot/en\"}}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/dale-and-peakot/en/dalepeakot.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ImitationNationSnakeGame-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ImitationNationSnakeGame-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/imitation-nation---snake-game\", \"regions\": null, \"height\": 385, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/40008/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer2Lvl2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacer2Lvl2-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0011/8219/live/embeddable_118219.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CosmicSwitch-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.CosmicSwitch-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/cosmic-switch\", \"regions\": [{\"coordinates\": [425, 58, 417, 29], \"type\": \"noclick\"}, {\"coordinates\": [426, 57, 417, 29], \"type\": \"noclick\"}], \"height\": 440, \"width\": 526, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/3224/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Go-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Go-v0\", \"human_url\": \"http://armorgames.com/play/310\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/go-310.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SupergirlGo-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SupergirlGo-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/SuperGirl-Go!,576742227280289582\", \"regions\": null, \"height\": 700, \"width\": 525, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/s/super_girl_go.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IcyGifts2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IcyGifts2-v0\", \"human_url\": \"http://www.kongregate.com/games/SilenGames/icy-gifts-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0016/0645/live/embeddable_160645.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ChuteAcademy-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ChuteAcademy-v0\", \"human_url\": \"http://armorgames.com/play/3455\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/chute-academy-3455.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BouncyCannon-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BouncyCannon-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25205\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae25907bad5.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BikeTrial3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BikeTrial3-v0\", \"human_url\": \"http://1000webgames.com/play-8614-Bike-Trial-3.html\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/biketrial3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PuddingPie-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PuddingPie-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/pudding-pie\", \"regions\": null, \"height\": 500, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/131170/game.swf?1430129008\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Kinetikz2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Kinetikz2-v0\", \"human_url\": \"http://armorgames.com/play/1953\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/kinetikz-2-1953.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SurvivalLab-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SurvivalLab-v0\", \"human_url\": null, \"regions\": null, \"height\": 518, \"width\": 450, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/survivallab/survivallab.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.EpicTimePirates-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EpicTimePirates-v0\", \"human_url\": \"http://notdoppler.com/epictimepirates.php\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/epictimepirates.swf?2\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CrazyDarts-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CrazyDarts-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/crazy-darts\", \"regions\": null, \"height\": 600, \"width\": 670, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/20597/game.swf?1381835957\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EmpireBusiness2Beta-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EmpireBusiness2Beta-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000064\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570ce9750a4d0.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TractorTrial2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TractorTrial2-v0\", \"human_url\": \"http://1000webgames.com/play-9965-Tractor-Trial-2.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/tractortrial2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsa-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsa-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperRallyChallenge-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.SuperRallyChallenge-v0\", \"human_url\": \"http://insanehero.com/mygames/SuperRallyChallenge/index.html\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://insanehero.com/mygames/SuperRallyChallenge/superrallychallenge.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RunSoldierRun-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RunSoldierRun-v0\", \"human_url\": \"http://armorgames.com/play/1535\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/run-soldier-run-1535.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Kinetikz-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Kinetikz-v0\", \"human_url\": \"http://armorgames.com/play/1032\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/kinetikz-1032.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SubmarineFighter-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SubmarineFighter-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/submarine-fighter\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/75923/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PocketRocket-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PocketRocket-v0\", \"human_url\": \"http://armorgames.com/play/3368\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/pocket-rocket-3368.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TankStorm3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TankStorm3-v0\", \"human_url\": \"http://1000webgames.com/play-9668-Tank-Storm-3.html\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/tankstorm3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvilSun-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EvilSun-v0\", \"human_url\": \"http://www.gamesbutler.com/game/11623/evil-sun/\", \"regions\": null, \"height\": 450, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/4b04ae0435b9d93b.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BurgerBar-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BurgerBar-v0\", \"human_url\": \"http://armorgames.com/play/17670\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/burger-bar-17670.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dClassicRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3dClassicRacing-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-classic-racing/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-classic-racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WonderRocket-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WonderRocket-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/wonder-rocket\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/37955/game.swf?1366895181\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BottleCaps-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.BottleCaps-v0\", \"human_url\": \"http://www.neongames.com/game/Bottle+Caps\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesonly.net/uploaded/swf/candymatch.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl2-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.QubedMysteriousIsland-v0\": {\"readme_header\": null, \"categories\": [\"platform puzzles\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.QubedMysteriousIsland-v0\", \"human_url\": \"http://www.platformgames.com/game/Qubed%3A+Mysterious+Island\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.platformgames.com/uploaded/swf/qubed.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GalaxyEvo2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GalaxyEvo2-v0\", \"human_url\": \"http://www.y8.com/games/galaxy_evo_2\", \"regions\": null, \"height\": 480, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/119205/original/galaxy_evo.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IndependenceDaySlacking2015-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IndependenceDaySlacking2015-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25407\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae32451d0c8.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Viridia-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Viridia-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/viridia/\", \"regions\": null, \"height\": 465, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/viridia/viridia.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl13-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl13-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.UltimateEscape-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"adventure\", \"our\", \"1 player\", \"2 players\", \"2pg\", \"flash\", \"free\", \"game\", \"highscore\", \"jumping\", \"multiplayer\", \"pixelated\", \"run\", \"runner\", \"running\", \"skill\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.UltimateEscape-v0\", \"human_url\": \"http://old.2pg.com/game/ultimate-escape/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/UltimateEscape_1366737833.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubblePopAdventure-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BubblePopAdventure-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/bubble-pop-adventure\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/133130/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HalloweenAdventureRun-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HalloweenAdventureRun-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/halloween-adventure-run-\", \"regions\": null, \"height\": 500, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/140623/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MapTurtleJigsawPuzzle-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MapTurtleJigsawPuzzle-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/map-turtle-jigsaw-puzzle\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/17038/game.swf?1304178443\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JellyFriend-v0\": {\"readme_header\": null, \"categories\": [\"1 player\", \"flash\", \"jewel\", \"free\", \"match 3\", \"idnet\", \"idnet highscore\", \"idnet save\", \"idnet achievements\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.JellyFriend-v0\", \"human_url\": \"http://www.y8.com/games/jelly_friend\", \"regions\": null, \"height\": 700, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/87720/original/jelly_friend.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SwingTriangle-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SwingTriangle-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25587\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eea546d8a7.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ProjectMonochrome-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ProjectMonochrome-v0\", \"human_url\": \"http://armorgames.com/play/499\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/project-monochrome-499.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LaxAirbusParking-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LaxAirbusParking-v0\", \"human_url\": \"http://www.gamesbutler.com/game/13971/lax-airbus-parking/\", \"regions\": null, \"height\": 500, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/2c9d563ca4039aca.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MotorWheels-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.MotorWheels-v0\", \"human_url\": \"http://www.cartitans.com/game/motor-wheels/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/motor-wheels.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ClimberGuy-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ClimberGuy-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/climber-guy\", \"regions\": null, \"height\": 750, \"width\": 450, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/136513/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NervousLadybug-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NervousLadybug-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/nervous-ladybug\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/23562/game.swf?1353496444\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchStars-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MatchStars-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/match-stars\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/132146/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AmigoPancho-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AmigoPancho-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Amigo-Pancho,576742227280284644\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/a/amigo_pancho/AmigoPancho.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RoadRacing-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RoadRacing-v0\", \"human_url\": \"http://1000webgames.com/play-8185-Road-Racing.html\", \"regions\": null, \"height\": 550, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/roadracing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SnowQueen3-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SnowQueen3-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Snow-Queen-3,576742227280289219\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/s/Snow_Queen_3/Snow_Queen_3_v1.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SapphireClix-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SapphireClix-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/sapphire-clix\", \"regions\": null, \"height\": 510, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/38247/game.swf?1370271893\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Overheat-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Overheat-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/overheat\", \"regions\": null, \"height\": 530, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/22502/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EpicDefender-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EpicDefender-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Epic-Defender,576742227280284318\", \"regions\": null, \"height\": 500, \"width\": 700, \"extra_files\": {\"absolute\": [\"http://api.configar.org/cf/pb/1/settings/0/0/01471020250b96470e93de6345fdfe94\", \"http://www8.agame.com/sdk/spilapi/localization/e/epic_defender_1305188404.swf\"]}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/e/epic_defender/epic_defender.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.QubeyTheCube-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.QubeyTheCube-v0\", \"human_url\": \"http://armorgames.com/play/17778\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/qubey-the-cube-17778.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.VengeanceRider-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.VengeanceRider-v0\", \"human_url\": \"http://www.cartitans.com/game/vengeance-rider/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/vengeance-rider.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IdlePlanet-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IdlePlanet-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000129\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cf6edbdc0e.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BlastTheMooksLevelPack-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BlastTheMooksLevelPack-v0\", \"human_url\": \"http://www.gamesbutler.com/game/9455/blast-the-mooks-level-pack/\", \"regions\": null, \"height\": 550, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/7b05cd16fdfd045e.swf?goto=norm\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Stealthbound-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Stealthbound-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000119\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cf4b326707.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl9-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl9-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Primary-v0\": {\"readme_header\": null, \"categories\": [\"noscore\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Primary-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/primary/\", \"regions\": null, \"height\": 450, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/primary/primary.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.FinalNinjaZero-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FinalNinjaZero-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Final_Ninja_Zero,576742227280294836\", \"regions\": null, \"height\": 800, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://games.cdn.spilcloud.com/f/finalninjazero_final.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FormulaRacerLvl2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FormulaRacerLvl2-v0\", \"human_url\": \"http://www.kongregate.com/games/turboNuke/formula-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0010/9268/live/FormulaRacer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HappyBees-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HappyBees-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Happy-Bees,576742227280289328\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/h/Happy_Bees/Happy_Bees_v1.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AnywayFish-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AnywayFish-v0\", \"human_url\": \"http://armorgames.com/play/12192\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/anyway-fish-12192.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Cruisin-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.Cruisin-v0\", \"human_url\": \"http://www.kongregate.com/games/fightclub69/cruisin\", \"regions\": null, \"height\": 270, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0016/1626/live/cruisin.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Enhanced-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Enhanced-v0\", \"human_url\": \"http://www.kongregate.com/games/mrDN/enhanced\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0018/5217/live/embeddable_185217.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IdleLifting-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IdleLifting-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25320\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae2f0c4714c.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PickAndDig2-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PickAndDig2-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/rocketeer\", \"regions\": null, \"height\": 630, \"width\": 560, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/21832/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dFlashRacer-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3dFlashRacer-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-flash-racer/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-flash-racer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BobbyNutcaseMotoJumping-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BobbyNutcaseMotoJumping-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Bobby-Nutcase-Moto-Jumping,576742227280285280\", \"regions\": null, \"height\": 800, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/b/Bobby_nutcase_motojumping/MotoJumping.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TheCaseOfScaryShadow-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TheCaseOfScaryShadow-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25580\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eea308b85b.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JonnyBackflip-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JonnyBackflip-v0\", \"human_url\": \"http://armorgames.com/play/14723\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/jonny-backflip-14723.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MightyTower-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MightyTower-v0\", \"human_url\": \"http://old.2pg.com/game/mighty-tower-2pg/play/\", \"regions\": null, \"height\": 400, \"width\": 650, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/mighty-tower_1363308497.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchingSweetHearts-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MatchingSweetHearts-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/matching-sweet-harts\", \"regions\": null, \"height\": 550, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/137952/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.99BricksTheLegendOfGarry-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.99BricksTheLegendOfGarry-v0\", \"human_url\": \"http://armorgames.com/play/4375\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/99-bricks-the-legend-4375.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ReachTheGoal-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ReachTheGoal-v0\", \"human_url\": \"http://www.dailygames.com/games/reach-the-goal.html\", \"regions\": null, \"height\": 300, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.dailygames.com/games/reach-the-goal.html\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Connect2-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.Connect2-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/connect-2\", \"regions\": [{\"coordinates\": [15, 568, 80, 37], \"type\": \"noclick\"}, {\"coordinates\": [14, 570, 471, 39], \"type\": \"noclick\"}], \"height\": 420, \"width\": 560, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/3041/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TheTowerman-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TheTowerman-v0\", \"human_url\": \"http://old.2pg.com/game/the-towerman/play/\", \"regions\": null, \"height\": 550, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/Tower.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JetpackJackride-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JetpackJackride-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/jetpack-jackride\", \"regions\": null, \"height\": 480, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/130100/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlyingCookieQuest-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlyingCookieQuest-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/flying-cookie-quest\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0016/0758/live/embeddable_160758.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CaptainSteelbounce-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CaptainSteelbounce-v0\", \"human_url\": \"http://www.kongregate.com/games/BeardshakerGames/captain-steelbounce\", \"regions\": null, \"height\": 528, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0015/2141/live/embeddable_152141.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HyperTravel-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HyperTravel-v0\", \"human_url\": \"http://armorgames.com/play/16096\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/hyper-travel-16096.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl3-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl3-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.QuashBoard-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.QuashBoard-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25666\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eebcfede05.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RoadblockAttack-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RoadblockAttack-v0\", \"human_url\": \"http://www.cartitans.com/game/roadblock-attack/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/roadblock-attack.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Frogged-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Frogged-v0\", \"human_url\": \"http://www.y8.com/games/frogged\", \"regions\": null, \"height\": 480, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/56088/original/frogged.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WolfSpiderJigsawPuzzle-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WolfSpiderJigsawPuzzle-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/wolf-spider-jigsaw-puzzle\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/17023/game.swf?1304178524\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Harvest-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Harvest-v0\", \"human_url\": \"http://notdoppler.com/harvest.php\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/harvest.swf?1\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FirefighterCannon-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FirefighterCannon-v0\", \"human_url\": \"http://1000webgames.com/play-7512-FireFighter-Cannon.html\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/firefighter-cannon.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Stardrops-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Stardrops-v0\", \"human_url\": \"http://www.kongregate.com/games/Seirie/stardrops\", \"regions\": null, \"height\": 600, \"width\": 760, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0015/1676/live/embeddable_151676.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.StitchlandConflict-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.StitchlandConflict-v0\", \"human_url\": \"http://armorgames.com/play/6796\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/stitchland-conflict-6796.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BombIt6-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BombIt6-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Bomb-It-6,576742227280288098\", \"regions\": null, \"height\": 700, \"width\": 510, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/b/bomb_it_6/bomb_it_6.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WinterSlider-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\", \"christmas\", \"match 3\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.WinterSlider-v0\", \"human_url\": \"http://www.kongregate.com/games/SmileyGamer/winter-slider\", \"regions\": null, \"height\": 540, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0016/1697/live/winterslider.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperBoxotron2000-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperBoxotron2000-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25654\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eeb95af002.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Solarsaurs-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Solarsaurs-v0\", \"human_url\": \"http://armorgames.com/play/202\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/solarsaurs-202.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NewSplitterPals-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NewSplitterPals-v0\", \"human_url\": \"http://www.kongregate.com/games/EvgenyKarataev/new-splitter-pals\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/2464/live/embeddable_172464.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RussianTruck-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RussianTruck-v0\", \"human_url\": \"http://www.gamesbutler.com/game/26371/russian-truck/\", \"regions\": null, \"height\": 480, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/2c3975a12dd62e5f.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PanikInChocoland-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PanikInChocoland-v0\", \"human_url\": \"http://www.miniclip.com/games/panik-in-chocoland/en/\", \"regions\": null, \"height\": 453, \"width\": 556, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/panik-in-chocoland/en/Panik.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RunRamRun-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"adventure\", \"kids\", \"our\", \"1 player\", \"2 players\", \"2pg\", \"avoid\", \"collecting\", \"free\", \"obstacles\", \"running\", \"sheep\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.RunRamRun-v0\", \"human_url\": \"http://old.2pg.com/game/run-ram-run/play/\", \"regions\": null, \"height\": 530, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/R/RunRamRun.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl3-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlowerSolitaire-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlowerSolitaire-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Flower-Solitaire,576742227280285161\", \"regions\": null, \"height\": 700, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/f/FlowerSolitaire/FlowerSolitaire-Family.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GamerMemoryTest-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GamerMemoryTest-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000147\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cfb81c5aec.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CarrotFantasyExtreme3-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CarrotFantasyExtreme3-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/carrot-fantasy-extreme\", \"regions\": null, \"height\": 690, \"width\": 960, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/39283/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SiegeHeroPiratePillage-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SiegeHeroPiratePillage-v0\", \"human_url\": \"http://armorgames.com/play/17608\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/siege-hero-pirate-pi-17608.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SmileyPuzzle-v0\": {\"readme_header\": null, \"categories\": [\"match 3\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.SmileyPuzzle-v0\", \"human_url\": \"http://www.smileygamer.com/ourgames/smileypuzzle.html\", \"regions\": null, \"height\": 400, \"width\": 540, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.smileygamer.com/ourgames/SmileyPuzzle.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ClubNitro-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.ClubNitro-v0\", \"human_url\": \"http://www.turbonuke.com/games.php?game=clubnitro\", \"regions\": null, \"height\": 550, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/clubnitro.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SlingBaby-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SlingBaby-v0\", \"human_url\": \"http://armorgames.com/play/12785\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/sling-baby-12785.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DuskRacers-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DuskRacers-v0\", \"human_url\": \"http://www.cartitans.com/game/dusk-racers/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/dusk-racers.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FeedOurDoughnutOverlords-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FeedOurDoughnutOverlords-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Feed-Our-Doughnut-Overlords!,576742227280285048\", \"regions\": null, \"height\": 480, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/f/Feed_our_doughnut_overlords/Fodo.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpinClimbGreen-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SpinClimbGreen-v0\", \"human_url\": \"http://armorgames.com/play/1370\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/spin-climb-green-1370.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TrickyRick-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TrickyRick-v0\", \"human_url\": \"http://www.kongregate.com/games/tAMAS_Games/tricky-rick\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0016/0342/live/embeddable_160342.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SeaPong-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SeaPong-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/sea-pong\", \"regions\": null, \"height\": 500, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/6629/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Neopods-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Neopods-v0\", \"human_url\": \"http://www.gamesbutler.com/game/6211/neopods/\", \"regions\": null, \"height\": 550, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/ef3a22fc8ff9ef4b.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PowerCopter-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PowerCopter-v0\", \"human_url\": \"http://armorgames.com/play/1280\", \"regions\": null, \"height\": 500, \"width\": 650, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/power-copter-1280.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HammerBall-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HammerBall-v0\", \"human_url\": \"http://armorgames.com/play/12877\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/hammer-ball-12877.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TurboRally-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.TurboRally-v0\", \"human_url\": \"http://notdoppler.com/turborally.php\", \"regions\": null, \"height\": 550, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/turborally.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.OkParking-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.OkParking-v0\", \"human_url\": \"http://1000webgames.com/play-9732-OK-Parking.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/okparking.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EasterBubbles-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EasterBubbles-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Easter-Bubbles,576742227280290430\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/e/easterbubble/easterbubble.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Rose-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Rose-v0\", \"human_url\": \"http://armorgames.com/play/1345\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/rose-1345.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MiniSportsChallenge-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MiniSportsChallenge-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/mini-sports-challenge\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/23457/game.swf?1352644956\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JamesTheDeepSeaZebra-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JamesTheDeepSeaZebra-v0\", \"human_url\": \"http://armorgames.com/play/205\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/james-the-deep-sea-z-205.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRaceLvl8-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.NeonRaceLvl8-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/7872/live/embeddable_97872.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Thundercars-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.Thundercars-v0\", \"human_url\": \"http://notdoppler.com/thundercars.php\", \"regions\": null, \"height\": 550, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/thundercars.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TowerEmpire-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TowerEmpire-v0\", \"human_url\": \"http://1000webgames.com/play-8826-Tower-Empire.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/tower-empire.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.InfectonatorSurvivorsAlphaDemo-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.InfectonatorSurvivorsAlphaDemo-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000013\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570c16dd9ea61.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FinalSiege-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FinalSiege-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Final-Siege,576742227280290332\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {\"absolute\": [\"http://api.configar.org/cf/pb/1/settings/0/0/8bc2d9277d443bb23723000e76de5cfe\", \"http://files.cdn.spilcloud.com/flashapi_1_3_1_147/ServicesConnection.swf\", \"http://files.cdn.spilcloud.com/flashapi_1_3_1_147/BrandSystem.swf\", \"http://files.cdn.spilcloud.com/flashapi_1_3_1_147/ServicePack.swf\", \"http://www8.agame.com/sdk/spilapi/localization/BrandLocalization.swf\", \"http://files.cdn.spilcloud.com/flashapi_assets/logos/a10.com.swf\"]}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/f/Final_siege/Final_Siege.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Parkour-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Parkour-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/parkour\", \"regions\": null, \"height\": 600, \"width\": 670, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/24373/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RobotDuelFight-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RobotDuelFight-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25430\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae338cad2c6.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TamusMitta-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TamusMitta-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Tamus-&-Mitta,576742227280285087\", \"regions\": null, \"height\": 670, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/t/Tamus_and_mitta/tamus.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ExtremeSkiing-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ExtremeSkiing-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/extreme-skiing\", \"regions\": null, \"height\": 480, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/23430/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PoliceChaseCrackdown-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.PoliceChaseCrackdown-v0\", \"human_url\": \"http://turbonuke.com/games.php?game=policechasecrackdown\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://turbonuke.com/flashgames/policechasecrackdown.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Avalancher-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Avalancher-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/avalancher\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/136643/game.swf?1457021989\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.InfernalMess-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.InfernalMess-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25435\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae33a67db91.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PumpkinsInZombieTown-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PumpkinsInZombieTown-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/pumpkins-in-zombie-town\", \"regions\": null, \"height\": 520, \"width\": 740, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/137221/game.swf?1459854860\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BikeTrial4-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BikeTrial4-v0\", \"human_url\": \"http://1000webgames.com/play-9583-Bike-Trial-4.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/biketrial4.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EiffelTowerAtNight-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EiffelTowerAtNight-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/eiffel-tower-at-night\", \"regions\": null, \"height\": 650, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/138976/game.swf?1468853758\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MysticalAncientTreasure-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MysticalAncientTreasure-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25549\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee974e6698.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Devilment-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Devilment-v0\", \"human_url\": \"http://www.y8.com/games/devilment\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/84027/original/devilment.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NightRaceRally-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NightRaceRally-v0\", \"human_url\": \"http://www.y8.com/games/night_race_rally\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/119157/original/night_race_rally.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dUrbanMadness-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3dUrbanMadness-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-urban-madness/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-urban-madness.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl15-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl15-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRaceLvl2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.NeonRaceLvl2-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/7872/live/embeddable_97872.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AdventuresOfBloo-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AdventuresOfBloo-v0\", \"human_url\": \"http://www.miniclip.com/games/adventures-of-bloo/en/\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/adventures-of-bloo/en/adventuresbloo.swf\", \"enable_internet\": false, \"serve_from_domain\": \"www.miniclip.com\"}, \"flashgames.XChains-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.XChains-v0\", \"human_url\": \"http://armorgames.com/play/778\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/x-chains-778.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HarvestDay-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HarvestDay-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/harvest-day\", \"regions\": [{\"coordinates\": [21, 59, 430, 29], \"type\": \"noclick\"}], \"height\": 379, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/6632/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DriveToWreck3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DriveToWreck3-v0\", \"human_url\": \"http://1000webgames.com/play-10158-Drive-To-Wreck-3.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/drivetowreck3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlashDrive-v0\": {\"readme_header\": null, \"categories\": [\"racing\", \"sports\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlashDrive-v0\", \"human_url\": \"http://www.kongregate.com/games/MartianGames/flash-drive\", \"regions\": null, \"height\": \"\", \"width\": \"\", \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0014/1396/live/FlashDrive.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperRallyExtreme-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperRallyExtreme-v0\", \"human_url\": \"http://www.kongregate.com/games/fightclub69/super-rally-extreme\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"https://cdn1.kongcdn.com/game_icons/0049/8355/250x200.jpg?i10c=img.resize(width:171,height:137)\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MineDrop-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MineDrop-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Mine-Drop,576742227280284693\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/m/MineDrop.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NanoKingdoms2JokersRevenge-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NanoKingdoms2JokersRevenge-v0\", \"human_url\": \"http://www.kongregate.com/games/Trutruka/nano-kingdoms-2-jokers-revenge\", \"regions\": null, \"height\": 480, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0016/1289/live/embeddable_161289.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PapaLouie3WhenSundaesAttack-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PapaLouie3WhenSundaesAttack-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000046\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570ce62bba443.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpunkyVsAliens-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SpunkyVsAliens-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/spunky-vs-aliens\", \"regions\": null, \"height\": 530, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/22700/game.swf?1435318521\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AsphaltMadness-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AsphaltMadness-v0\", \"human_url\": \"http://1000webgames.com/play-8776-Asphalt-Madness.html\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/asphalt-madness.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl6-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl6-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Sparks-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.Sparks-v0\", \"human_url\": \"http://www.arkadium.com/games/sparks/\", \"regions\": null, \"height\": 444, \"width\": 640, \"extra_files\": {\"relative\": {\"files\": [\"data/sparks_config.xml\", \"data/locale/en-US/strings.xml\", \"data/loggers/logger_config.xml\", \"data/assetpacks/engine.swf\", \"data/loggers/gameplay-logger.swf\", \"data/loggers/comscore-logger.swf\", \"branding.jpg\"], \"base\": \"http://amsarkadium-a.akamaihd.net/assets/global/game/sparks/96daf9b9-e77a-492f-96b0-14a418563083\"}}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://amsarkadium-a.akamaihd.net/assets/global/game/sparks/96daf9b9-e77a-492f-96b0-14a418563083/sparks.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SwampTreck-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SwampTreck-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/swamp-treck\", \"regions\": null, \"height\": 390, \"width\": 520, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/3222/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GroundBattles-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GroundBattles-v0\", \"human_url\": \"http://old.2pg.com/game/ground-battles/play/\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/G/ground-battles.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AwesomeRun2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AwesomeRun2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5002000\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/57a9ddf8d26b6.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Pathillogical-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Pathillogical-v0\", \"human_url\": \"http://www.kongregate.com/games/5minutesoff/pathillogical\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0007/3025/live/embeddable_73025.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AladdinAndTheWonderLamp-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AladdinAndTheWonderLamp-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Aladdin-and-the-wonder-lamp,576742227280289233\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/a/Aladin_and_the_Wonder_Lamp/Aladin_and_the_Wonder_Lamp.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BlackRacerJigsawPuzzle-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BlackRacerJigsawPuzzle-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/black-racer-jigsaw-puzzle\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/16991/game.swf?1304178196\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BunnyAndSquirt-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BunnyAndSquirt-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25249\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae266e06c11.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleHitChristmas-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.BubbleHitChristmas-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Bubble-Hit:-Christmas,576742227280283935\", \"regions\": [{\"coordinates\": [496, 161, 275, 286], \"type\": \"noclick\"}], \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/b/bubble_hit_christmas/Bubble_Hit_Christmas.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BombIt4-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BombIt4-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Bomb-It-4,576742227280285511\", \"regions\": null, \"height\": 700, \"width\": 510, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/b/BombIt4/bomb_it_4.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RedCode3-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RedCode3-v0\", \"human_url\": \"http://www.miniclip.com/games/red-code-3/en/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/red-code-3/en/redCode3SingleFile.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BeachCrazy-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BeachCrazy-v0\", \"human_url\": \"http://armorgames.com/play/15569\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/beach-crazy-15569.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GrandPrixGo-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.GrandPrixGo-v0\", \"human_url\": \"http://www.kongregate.com/games/turboNuke/grand-prix-go\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0011/5460/live/GrandPrixGo.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Crumbs2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Crumbs2-v0\", \"human_url\": \"http://www.gamesbutler.com/game/4687/crumbs-2/\", \"regions\": null, \"height\": 360, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/581f0c4b4ff804a9.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CarrotFantasy2Desert-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CarrotFantasy2Desert-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/carrot-fantasy-2-desert\", \"regions\": null, \"height\": 690, \"width\": 960, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/38907/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SwagMan-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SwagMan-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/swag-man\", \"regions\": null, \"height\": 600, \"width\": 760, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/129912/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.KeeperOfTheGrove3-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.KeeperOfTheGrove3-v0\", \"human_url\": \"http://www.y8.com/games/keeper_of_the_grove_3\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/91305/original/keeper_of_the_grove_3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacing-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SkiSim-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SkiSim-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/ski-sim\", \"regions\": null, \"height\": 600, \"width\": 670, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/20589/game.swf?1377854676\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TouchTheSky-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TouchTheSky-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/touch-the-sky\", \"regions\": null, \"height\": 600, \"width\": 670, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/23253/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchToEnjoy-v0\": {\"readme_header\": null, \"categories\": [\"puzzle\", \"match 3\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MatchToEnjoy-v0\", \"human_url\": \"http://www.kongregate.com/games/charstudio/match-to-enjoy\", \"regions\": null, \"height\": 527, \"width\": 620, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0012/6924/live/game_match_to_enjoy.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchAndCrash-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MatchAndCrash-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/match-and-crash\", \"regions\": null, \"height\": 500, \"width\": 300, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/127650/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WildWestConflict-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WildWestConflict-v0\", \"human_url\": \"http://1000webgames.com/play-9395-Wild-West-Conflict.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/wildwestconflict.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ChromaticTowerDefense-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ChromaticTowerDefense-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/chromatic-tower-defense\", \"regions\": null, \"height\": 550, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/23181/game.swf?1353509333\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleGlee-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.BubbleGlee-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Bubble-Glee,576742227280289253\", \"regions\": [{\"coordinates\": [239, 41, 491, 38], \"type\": \"noclick\"}, {\"coordinates\": [458, 38, 490, 41], \"type\": \"noclick\"}], \"height\": 510, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/b/Bubble_Glee/Bubble_Glee.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SupercarDomination-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.SupercarDomination-v0\", \"human_url\": \"http://www.cartitans.com/game/supercar-domination/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/supercar-domination.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HighwayRevenge-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HighwayRevenge-v0\", \"human_url\": \"http://www.cartitans.com/game/highway-revenge/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/highway-revenge.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl14-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl14-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MushboomsLevelPack-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MushboomsLevelPack-v0\", \"human_url\": \"http://www.gamesbutler.com/game/7684/mushbooms-level-pack/\", \"regions\": null, \"height\": 550, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/12929afb1a5c149f.swf?goto=norm\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CosmoGravity2-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CosmoGravity2-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Cosmo-Gravity-2,576742227280291914\", \"regions\": null, \"height\": 800, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/a10/cosmogravity/CosmoGravity3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WormHappy-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WormHappy-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/worm-happy\", \"regions\": null, \"height\": 440, \"width\": 440, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/41269/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleSlasher-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BubbleSlasher-v0\", \"human_url\": \"http://old.2pg.com/game/bubble-slasher/play/\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesforyourwebsite.org/games/Bubble-Slasher-2pg.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Mushbooms-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Mushbooms-v0\", \"human_url\": \"http://www.gamesbutler.com/game/6823/mushbooms/\", \"regions\": null, \"height\": 550, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/mushbooms_locked_final.swf?goto=norm\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HexBattles-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HexBattles-v0\", \"human_url\": \"http://www.gamesbutler.com/game/4689/hex-battles/\", \"regions\": null, \"height\": 420, \"width\": 630, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/117514eebc04e644.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PenguinHeroes-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PenguinHeroes-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Penguin-Heroes,576742227280285464\", \"regions\": null, \"height\": 700, \"width\": 525, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/p/Penguin_heroes/Penguin_heroes.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleAdventures-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BubbleAdventures-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25254\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/game-1462796976.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CandyMatchCrush-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CandyMatchCrush-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/candy-match-crush\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/122671/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Coloruid-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Coloruid-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000010\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570c1619e0936.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TinyRacers-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.TinyRacers-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/tiny-racers\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/24398/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Krome-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Krome-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25461\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae352110953.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PolygonalFury-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PolygonalFury-v0\", \"human_url\": \"http://notdoppler.com/polygonalfury.php\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/polygonalfury.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PixelPurge-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PixelPurge-v0\", \"human_url\": \"http://armorgames.com/play/6804\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/pixel-purge-6804.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Michimind-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Michimind-v0\", \"human_url\": \"http://www.gamesbutler.com/game/3387/michimind/\", \"regions\": null, \"height\": 500, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/michimind.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MeerkatMission-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MeerkatMission-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Meerkat-Mission,576742227280285168\", \"regions\": null, \"height\": 510, \"width\": 700, \"extra_files\": {\"absolute\": [\"http://api.configar.org/cf/pb/1/settings/0/0/4a082ddc81a83df7a18309b48ed79a9a\", \"http://www8.agame.com/sdk/spilapi/localization/m/meerkat_mission_1306233434.swf\"]}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/m/meerkat_mission/meerkat_mission.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TaxiInc-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TaxiInc-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25631\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eeb26a74d0.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HelicopsTerritories-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HelicopsTerritories-v0\", \"human_url\": \"http://armorgames.com/play/10251\", \"regions\": null, \"height\": 480, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/helicops-territories-10251.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.OldTv-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.OldTv-v0\", \"human_url\": \"http://www.gamesbutler.com/game/25283/old-tv/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/125701ab5119e33e.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Conjure-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Conjure-v0\", \"human_url\": \"http://armorgames.com/play/11813\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/conjure-11813.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WaveLucha-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"adventure\", \"our\", \"1 player\", \"2 players\", \"2pg\", \"chase\", \"chasing\", \"escape\", \"highscore\", \"pixelated\", \"runner\", \"running\", \"survive\", \"water\", \"wave\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.WaveLucha-v0\", \"human_url\": \"http://old.2pg.com/game/wave-lucha/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/wavelucha2pg_1370988428.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl9-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl9-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SiegerRebuiltToDestroy-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SiegerRebuiltToDestroy-v0\", \"human_url\": \"http://armorgames.com/play/16137\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/sieger-rebuilt-to-de-16137.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl15-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl15-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl7-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl7-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.StarCars-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.StarCars-v0\", \"human_url\": \"http://www.y8.com/games/star_cars\", \"regions\": null, \"height\": 450, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/102588/original/star_cars.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeliVsTower-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HeliVsTower-v0\", \"human_url\": \"http://armorgames.com/play/15296\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/heli-vs-tower-15296.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ZombiesAndDonuts-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ZombiesAndDonuts-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/zombies-and-donuts\", \"regions\": null, \"height\": 500, \"width\": 670, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/21830/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer2Lvl10-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacer2Lvl10-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0011/8219/live/embeddable_118219.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvolutionRacingLvl11-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.EvolutionRacingLvl11-v0\", \"human_url\": \"http://www.y8.com/games/evolution_racing\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/109879/original/evolution_racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LearnToFlyIdle-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LearnToFlyIdle-v0\", \"human_url\": \"http://www.kongregate.com/games/light_bringer777/learn-to-fly-idle\", \"regions\": null, \"height\": 540, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0020/3284/live/embeddable_203284.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WastelandSiege-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WastelandSiege-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000407\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570eccfb653d8.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacer-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/3927/live/embeddable_93927.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GrandPrixGo2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.GrandPrixGo2-v0\", \"human_url\": \"http://notdoppler.com/grandprixgo2.php\", \"regions\": null, \"height\": 550, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/grandprixgo2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NinjaPainter-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NinjaPainter-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Ninja-Painter,576742227280284705\", \"regions\": null, \"height\": 700, \"width\": 520, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/n/NinjaPainter/ninja_painter_agame_com.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.VolleyBomb-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.VolleyBomb-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25244\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae265e64dbd.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FireworksGame-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FireworksGame-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25246\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae2664b32b6.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Stars-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Stars-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/stars\", \"regions\": null, \"height\": 550, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/40105/game.swf?1398679265\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TowerEmpire2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TowerEmpire2-v0\", \"human_url\": \"http://1000webgames.com/play-9283-Tower-Empire-2.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/towerempire2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperCarRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperCarRacing-v0\", \"human_url\": \"http://www.kongregate.com/games/fightclub69/super-car-racing\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"https://cdn1.kongcdn.com/game_icons/0056/9777/icon1_466x373.jpg?i10c=img.resize(width:171,height:137)\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PixelFighta-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PixelFighta-v0\", \"human_url\": \"http://armorgames.com/play/1267\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/pixel-fighta-1267.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoverOrangeJourneyGangsters-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CoverOrangeJourneyGangsters-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25255\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae26882fb9d.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterCarsBridgesTrack-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CoasterCarsBridgesTrack-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/Coaster-Cars-Bridges-track.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/flash4/Coaster-Cars-Bridges-track.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Peakart-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Peakart-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/PeaKart.html\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/flash5/PeaKart.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MiceVsHammers-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MiceVsHammers-v0\", \"human_url\": \"http://old.2pg.com/game/mice-vs-hammers/play/\", \"regions\": null, \"height\": 480, \"width\": 760, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/M/mice_vs_hammers.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Filler-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Filler-v0\", \"human_url\": \"http://www.kongregate.com/games/SimianLogic/filler\", \"regions\": null, \"height\": 527, \"width\": 620, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0000/5982/live/filler.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleHitHalloween-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.BubbleHitHalloween-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Bubble-Hit:-Halloween,576742227280283659\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/b/bubble_hit_halloween/bubble_hit_halloween.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MonsterTroubles-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MonsterTroubles-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/monster-troubles\", \"regions\": null, \"height\": 500, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/38973/game.swf?1380622674\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlyingKiwi-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlyingKiwi-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/flying-kiwi\", \"regions\": null, \"height\": 550, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/24332/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MonkeyGoHappyNinjaHunt2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MonkeyGoHappyNinjaHunt2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25619\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575eeaeb7f9a9.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SnakeClassic-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SnakeClassic-v0\", \"human_url\": \"http://www.gamesbutler.com/game/2257/snake-classic/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/snakeclassic.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PurifyTheLegendOfZ-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PurifyTheLegendOfZ-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25371\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae30ca2af2f.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GalleonFight-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GalleonFight-v0\", \"human_url\": \"http://1000webgames.com/play-7852-Galleon-Fight.html\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/galleon-fight100x100.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Numz-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Numz-v0\", \"human_url\": \"http://notdoppler.com/numz.php\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/numz.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BraveAstronaut-v0\": {\"readme_header\": null, \"categories\": [\"flash\", \"space\", \"purchase equipment upgrades\", \"killing\", \"collecting\", \"monsters\", \"planet\", \"free\", \"idnet\", \"idnet highscore\", \"idnet save\", \"idnet achievements\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BraveAstronaut-v0\", \"human_url\": \"http://www.y8.com/games/brave_astronaut\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/104502/original/brave_astronaut.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CupidBubbles-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CupidBubbles-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Cupid-Bubbles,576742227280290597\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/c/cupidbubbles/cupidbubbles.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.UdderChaos-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.UdderChaos-v0\", \"human_url\": \"http://www.gamesbutler.com/game/3559/udder-chaos/\", \"regions\": null, \"height\": 680, \"width\": 540, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/udderchaos.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DriveToWreck-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DriveToWreck-v0\", \"human_url\": \"http://1000webgames.com/play-8537-Drive-To-Wreck.html\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/drive-to-wreck.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dLaSupercars-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3dLaSupercars-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-la-supercars/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-la-supercars.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HelmetBombers3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HelmetBombers3-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Helmet-Bombers-3,576742227280285497\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/h/Helmet_bombers3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Streetrace2Nitro-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.Streetrace2Nitro-v0\", \"human_url\": \"http://insanehero.com/mygames/StreetRace2/index.html\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://insanehero.com/mygames/StreetRace2/streetrace2nitro.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Sheepy-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Sheepy-v0\", \"human_url\": \"http://armorgames.com/play/865\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/sheepy-865.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RoboPop-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RoboPop-v0\", \"human_url\": \"http://www.miniclip.com/games/robo-pop/en/\", \"regions\": null, \"height\": 500, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/robo-pop/en/robopop.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SneakyScubaEscape-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SneakyScubaEscape-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25411\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae32a2be02d.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FormulaRacerLvl8-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FormulaRacerLvl8-v0\", \"human_url\": \"http://www.kongregate.com/games/turboNuke/formula-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://chat.kongregate.com/gamez/0010/9268/live/FormulaRacer.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchAroundTheWorld-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.MatchAroundTheWorld-v0\", \"human_url\": \"http://www.neongames.com/game/Match+around+the+World\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesonly.net/uploaded/swf/matcharoundtheworld.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WhistleAndMice-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WhistleAndMice-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/whistle-and-mice\", \"regions\": null, \"height\": 400, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/23590/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Drifters-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Drifters-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/drifters\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/38136/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DanceBattle-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DanceBattle-v0\", \"human_url\": \"http://armorgames.com/play/6648\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/dance-battle-6648.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Flagman-v0\": {\"readme_header\": null, \"categories\": [\"noscore\", \"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Flagman-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/flagman/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/flagman/flagman.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.GalacticCats-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GalacticCats-v0\", \"human_url\": \"http://old.2pg.com/game/galactic-cats/play/\", \"regions\": null, \"height\": 480, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/GalacticCats_1369856512.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SurvivorMissionD-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SurvivorMissionD-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25259\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae26baca855.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl14-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl14-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DisasterWillStrikeDefender-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DisasterWillStrikeDefender-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25377\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae3100edfb4.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TechnoMania-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TechnoMania-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Techno-Mania,576742227280285331\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/t/techno_mania/Techno_mania.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TheGreatSiege-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TheGreatSiege-v0\", \"human_url\": \"http://www.kongregate.com/games/ttback/the-great-siege\", \"regions\": null, \"height\": 450, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0004/1580/live/embeddable_41580.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JamesThePirateZebra-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JamesThePirateZebra-v0\", \"human_url\": \"http://armorgames.com/play/1606\", \"regions\": null, \"height\": \"\", \"width\": \"\", \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/james-the-pirate-zeb-1606.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TokyoGuineaPop-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TokyoGuineaPop-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/tokyo-guinea-pop\", \"regions\": null, \"height\": 525, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0014/7832/live/embeddable_147832.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperXtreme5MinuteShootEmUp-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperXtreme5MinuteShootEmUp-v0\", \"human_url\": \"http://armorgames.com/play/4274\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/super-xtreme-5-minut-4274.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SafariTime-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SafariTime-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Safari-Time,576742227280284998\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/s/Safari_time/Safari_Time.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Hash-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Hash-v0\", \"human_url\": \"http://armorgames.com/play/4518\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/hash-4518.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ToonEscapeMaze-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ToonEscapeMaze-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25496\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee84236575.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl11-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl11-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MindImpulse-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MindImpulse-v0\", \"human_url\": \"http://armorgames.com/play/1711\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/mind-impulse-1711.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CartoonCandy-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CartoonCandy-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/cartoon-candy\", \"regions\": null, \"height\": 540, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/130173/game.swf?1422975985\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FootballHeads201314Ligue1-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FootballHeads201314Ligue1-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000096\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cef2ccf8fe.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ManicRallyGo-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ManicRallyGo-v0\", \"human_url\": \"http://armorgames.com/play/6002\", \"regions\": null, \"height\": 480, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/manic-rally-go-6002.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TempleRunKnight-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TempleRunKnight-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/temple-run-knight\", \"regions\": null, \"height\": 525, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/140691/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TheBigEscape-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TheBigEscape-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25459\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae350825d15.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FindTheCandy3Kids-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FindTheCandy3Kids-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25391\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae317ac06a3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dTestDrive-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3dTestDrive-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-test-drive/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-test-drive.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.StickBlender-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.StickBlender-v0\", \"human_url\": \"http://www.kongregate.com/games/EffingGames/stick-blender\", \"regions\": null, \"height\": 400, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0012/8323/live/embeddable_128323.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CavemanEscape-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CavemanEscape-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/caveman-escape\", \"regions\": null, \"height\": 600, \"width\": 450, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/130136/game.swf?1422963134\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TaxiRacers-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TaxiRacers-v0\", \"human_url\": \"http://www.y8.com/games/taxi_racers\", \"regions\": null, \"height\": 349, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/92271/original/taxi_racers.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.UnfreezeMe3-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.UnfreezeMe3-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Unfreeze-Me-3,576742227280290645\", \"regions\": null, \"height\": 640, \"width\": 440, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/u/Unfreeze_me3/UnfreezeMe3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IncrementalAcceleration-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IncrementalAcceleration-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25301\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae2e2957165.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacerLvl5-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacerLvl5-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/3927/live/embeddable_93927.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushFutureLvl10-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.HeatRushFutureLvl10-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-future\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0019/7465/live/embeddable_197465.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.KartOn-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.KartOn-v0\", \"human_url\": \"http://armorgames.com/play/5938\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/kart-on-5938.swf\", \"enable_internet\": false, \"serve_from_domain\": \"armorgames.com\"}, \"flashgames.Rb2-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Rb2-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/rb2\", \"regions\": null, \"height\": 600, \"width\": 400, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/130629/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer2Lvl6-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacer2Lvl6-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0011/8219/live/embeddable_118219.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FishEatFish-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FishEatFish-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/fish-eat-fish\", \"regions\": null, \"height\": 400, \"width\": 570, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/3019/game.swf?1438339548\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DartsSim-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DartsSim-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/darts-sim\", \"regions\": null, \"height\": 550, \"width\": 670, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/20523/game.swf?1272450300\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRaceLvl3-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.NeonRaceLvl3-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/7872/live/embeddable_97872.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleRubbleTheIsland-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BubbleRubbleTheIsland-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25439\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae33f8d98e4.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeavenAndHell-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HeavenAndHell-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Heaven-and-Hell,576742227280284165\", \"regions\": null, \"height\": 700, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/h/heaven_and_hell/Heaven_and_hell_agame.com.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LlamasInDistress-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LlamasInDistress-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25256\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae268f48568.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Rocketeer-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Rocketeer-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/rocketeer\", \"regions\": null, \"height\": 630, \"width\": 560, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/21832/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JelliesFun-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JelliesFun-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25172\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae25009b979.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dBuggyRacing-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.3dBuggyRacing-v0\", \"human_url\": \"http://www.willinggames.com/racing-games/3D-Buggy-Racing.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.willinggames.com/flash3/3D-Buggy-Racing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PyramidApocalypse-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PyramidApocalypse-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25493\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee75a26c43.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WizkidEscape-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WizkidEscape-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/wizkid-escape\", \"regions\": null, \"height\": 480, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/127272/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SwimmingRace-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SwimmingRace-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/swimming-race\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/22892/game.swf?1344258791\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MushboomsLevelPack2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MushboomsLevelPack2-v0\", \"human_url\": \"http://www.gamesbutler.com/game/9564/mushbooms-level-pack-2/\", \"regions\": null, \"height\": 550, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/43861ff73fc7b692.swf?goto=norm\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Spectrum-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Spectrum-v0\", \"human_url\": \"http://armorgames.com/play/487\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/spectrum-487.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GravityThruster-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GravityThruster-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/gravity-thruster\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/35269/game.swf?1366122188\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MagicSafari-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MagicSafari-v0\", \"human_url\": \"http://notdoppler.com/magicsafari.php\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/magicsafari.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ClimbingSanta-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ClimbingSanta-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/climbing-santa\", \"regions\": null, \"height\": 500, \"width\": 650, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/23729/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ReleaseTheMooks2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ReleaseTheMooks2-v0\", \"human_url\": \"http://www.gamesbutler.com/game/5905/release-the-mooks-2/\", \"regions\": null, \"height\": 500, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/1092a7ad22e7af81.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TheThreeTowers-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TheThreeTowers-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/the-three-towers\", \"regions\": null, \"height\": 530, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/39201/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RushOfTanks-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RushOfTanks-v0\", \"human_url\": \"http://www.gamesbutler.com/game/26414/rush-of-tanks/\", \"regions\": null, \"height\": 600, \"width\": 450, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/RushOfTanks_unlock.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HandsOff-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HandsOff-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Hands-Off,576742227280289760\", \"regions\": null, \"height\": 525, \"width\": 700, \"extra_files\": {\"absolute\": [\"http://api.configar.org/cf/pb/1/settings/0/0/7f8d20a2f3b0563f3c041ca93b5cc45d\"]}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/h/hands_off.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRaceLvl6-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.NeonRaceLvl6-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/7872/live/embeddable_97872.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WilliamTell-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WilliamTell-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/William-Tell,576742227280285291\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/w/william_tell/williamtell_spil.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Stratega-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Stratega-v0\", \"human_url\": \"http://armorgames.com/play/15993\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/stratega-15993.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BlackInk-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BlackInk-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25420\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae32f790e21.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3FootNinjaIi-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3FootNinjaIi-v0\", \"human_url\": \"http://www.miniclip.com/games/3-foot-ninja-ii/en/\", \"regions\": null, \"height\": 420, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/3-foot-ninja-ii/en/3-foot-ninja-ii.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CitySiege3FubarLevelPack-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CitySiege3FubarLevelPack-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000057\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570ce82ee5190.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TurtleBreak-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TurtleBreak-v0\", \"human_url\": \"http://www.y8.com/games/turtle_break\", \"regions\": null, \"height\": 500, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/19685/original/turtle_break.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl10-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl10-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Velocity-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Velocity-v0\", \"human_url\": \"http://armorgames.com/play/343\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/velocity-343.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.JakeTheSnake-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.JakeTheSnake-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/jake-the-snake\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/24031/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SnakeFightArena-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SnakeFightArena-v0\", \"human_url\": \"http://old.2pg.com/game/snake-fight-arena/play/\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/Snakefight2pg_1363807257.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EctoHarvest-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.EctoHarvest-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Ecto-Harvest,576742227280290232\", \"regions\": [{\"coordinates\": [509, 210, 630, 54], \"type\": \"noclick\"}], \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/e/Ecto_harvest/EctoHarvest-spil-v1.02.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.NeonRace-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/7872/live/embeddable_97872.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HunterForDismantlers-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HunterForDismantlers-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25209\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae25a39e611.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Basement-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Basement-v0\", \"human_url\": \"http://1000webgames.com/play-7411-Basement.html\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://1000webgames.com/arcade/basement.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SushiCatTheHoneymoon-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SushiCatTheHoneymoon-v0\", \"human_url\": \"http://armorgames.com/play/6301\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/sushi-cat-the-honeym-6301.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EscapeTheRedGiant-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EscapeTheRedGiant-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/escapetheredgiant/\", \"regions\": null, \"height\": 500, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/escapetheredgiant/escapetheredgiant.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.EpicDerbyRace-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EpicDerbyRace-v0\", \"human_url\": \"http://www.cartitans.com/game/epic-derby-race/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/epic-derby-race.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Sheepster-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Sheepster-v0\", \"human_url\": \"http://www.gamesbutler.com/game/2444/sheepster/\", \"regions\": null, \"height\": 500, \"width\": 650, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/Sheepster_final.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DaymareInvaders-v0\": {\"readme_header\": null, \"categories\": [\"1 player\", \"flash\", \"shooting\", \"arkanoid\", \"space invaders\", \"free\", \"default\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DaymareInvaders-v0\", \"human_url\": \"http://www.y8.com/games/daymare_invaders\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-storage/contents/39092/original/daymare_invaders.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SandcastleShowdown-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SandcastleShowdown-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/sandcastle-showdown\", \"regions\": null, \"height\": 650, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/24208/game.swf?1360062134\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperShinyheadHarderThanFlappyBird-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperShinyheadHarderThanFlappyBird-v0\", \"human_url\": \"http://old.2pg.com/game/super-shinyhead/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/S/super-shiny-head-2pg.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"internet.SlitherIOErmiyaEskandaryBot-v0\": {\"categories\": [\"mmo\"], \"height\": 300, \"width\": 502, \"server_timestep_limit\": null, \"tags\": {}, \"id\": \"internet.SlitherIOErmiyaEskandaryBot-v0\", \"rewarder\": true, \"url\": \"http://slither.io/\", \"enable_internet\": true, \"autostart\": true}, \"flashgames.DiscoverEurope-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DiscoverEurope-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Discover-Europe,576742227280285197\", \"regions\": null, \"height\": 700, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/d/DiscoverEurope/DiscoverEurope-Family.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PixelQuest-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PixelQuest-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/pixel-quest\", \"regions\": null, \"height\": 530, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/21869/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Gemclix-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.Gemclix-v0\", \"human_url\": \"http://www.match3.com/match-3-games/gemclix.html\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://flash.match3.com/game_files/gemclixmatch3_mochirev4.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SwapTheDots-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"fun\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.SwapTheDots-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Swap-The-Dots,576742227280291218\", \"regions\": [{\"coordinates\": [618, 40, 84, 38], \"type\": \"noclick\"}], \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/s/swap_the_dots/swapthedots.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Titanic-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Titanic-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Titanic,576742227280285079\", \"regions\": null, \"height\": 440, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/t/Titanic/titanic_agame.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Qoosh-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Qoosh-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Qoosh,576742227280287823\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/q/Qoosh/Qoosh.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PixelBasher-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PixelBasher-v0\", \"human_url\": \"http://armorgames.com/play/5832\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/pixel-basher-5832.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TinyCastle-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TinyCastle-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/tinycastle/\", \"regions\": null, \"height\": 500, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/tinycastle/tinycastle.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.FlappyCopter-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlappyCopter-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/flappy-copter\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/39602/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.LessQuick-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.LessQuick-v0\", \"human_url\": \"http://notdoppler.com/lessquick.php\", \"regions\": null, \"height\": 516, \"width\": 654, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/lessquick.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HungryPiranha-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.HungryPiranha-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/hungry-piranha\", \"regions\": null, \"height\": 450, \"width\": 550, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/12832/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.DeepFreeze-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.DeepFreeze-v0\", \"human_url\": \"http://www.miniclip.com/games/deep-freeze/en/\", \"regions\": null, \"height\": 300, \"width\": 400, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/deep-freeze/en/deepfreeze.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ZombiesVsBrains-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ZombiesVsBrains-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5002396\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/57bef5c024f0e.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.UnderwaterSecrets-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.UnderwaterSecrets-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Underwater-Secrets,576742227280292352\", \"regions\": [{\"coordinates\": [616, 40, 84, 36], \"type\": \"noclick\"}], \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/u/underwater_secrets/underwater_secrets_spil.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.StickyNinjaMissions-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.StickyNinjaMissions-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/sticky-ninja-missions\", \"regions\": null, \"height\": 512, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0021/0593/live/embeddable_210593.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SpacePunkRacerLvl2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.SpacePunkRacerLvl2-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/space-punk-racer\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0012/4902/live/embeddable_124902.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.EvilMinion-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.EvilMinion-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/evil-minion\", \"regions\": null, \"height\": 400, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/15172/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BoltThrough-v0\": {\"readme_header\": null, \"categories\": [\"2 player\", \"car\", \"our\", \"1 player\", \"2 players\", \"2playergames\", \"addicting\", \"distance\", \"featured\", \"flash game\", \"free\", \"fun\", \"highscore\", \"keyboard\", \"kids\", \"runner\", \"running\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.BoltThrough-v0\", \"human_url\": \"http://old.2pg.com/game/bolt-through/play/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/boltthrough2pg.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PuzzleMonsters-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PuzzleMonsters-v0\", \"human_url\": \"http://www.kongregate.com/games/Edvent/puzzle-monsters\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/1446/live/embeddable_171446.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RunFaustoRun-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RunFaustoRun-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/run-fausto-run\", \"regions\": null, \"height\": 550, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/105078/game.swf?\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3FootNinja-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3FootNinja-v0\", \"human_url\": \"http://www.miniclip.com/games/3-foot-ninja/en/\", \"regions\": null, \"height\": 400, \"width\": 560, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/3-foot-ninja/en/3-foot-ninja.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.HeatRushUsaLvl12-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.HeatRushUsaLvl12-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/heat-rush-usa\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0017/9179/live/embeddable_179179.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RunRunRan-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RunRunRan-v0\", \"human_url\": \"http://www.kongregate.com/games/artlogicgames/run-run-ran\", \"regions\": null, \"height\": 600, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0016/8905/live/embeddable_168905.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Trizzle-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.Trizzle-v0\", \"human_url\": \"http://www.arkadium.com/games/trizzle/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {\"relative\": {\"files\": [\"config.xml\", \"data/trizzle_config.xml\", \"data/loggers/logger_config.xml\", \"data/loggers/gameplay-logger.swf\", \"branding.jpg\", \"data/assetpacks/engine.swf\", \"data/locale/en-US/strings.xml\", \"data/sounds/VO/Trizzle_titlecheer.mp3\", \"data/sounds/VO/doll_cheer_3.mp3\", \"data/sounds/VO/doll_cheer_4.mp3\", \"data/sounds/VO/doll_voice_1.mp3\", \"data/sounds/VO/doll_voice_10.mp3\", \"data/sounds/VO/doll_voice_2.mp3\", \"data/sounds/VO/doll_voice_3.mp3\", \"data/sounds/VO/doll_voice_4.mp3\", \"data/sounds/VO/doll_voice_5.mp3\", \"data/sounds/VO/doll_voice_6.mp3\", \"data/sounds/VO/doll_voice_7.mp3\", \"data/sounds/VO/doll_voice_8.mp3\", \"data/sounds/VO/doll_voice_9.mp3\", \"data/sounds/doll_big_complete.mp3\", \"data/sounds/doll_spin_out.mp3\", \"data/sounds/doll_tile_power_up.mp3\", \"data/sounds/help_panel_close.mp3\", \"data/sounds/help_panel_open.mp3\", \"data/sounds/level_up.mp3\", \"data/sounds/level_up_with_cutecheer.mp3\", \"data/sounds/moves_dec.mp3\", \"data/sounds/moves_inc.mp3\", \"data/sounds/nine_moves_left.mp3\", \"data/sounds/no_more_moves_panel_close.mp3\", \"data/sounds/no_more_moves_panel_open.mp3\", \"data/sounds/option_panel_close.mp3\", \"data/sounds/option_panel_open.mp3\", \"data/sounds/out_of_moves_placard.mp3\", \"data/sounds/quit_panel_close.mp3\", \"data/sounds/quit_panel_open.mp3\", \"data/sounds/stars_animation.mp3\", \"data/sounds/talkbubble_popup.mp3\", \"data/sounds/VO/doll_cheer_1.mp3\", \"data/sounds/VO/doll_cheer_2.mp3\", \"data/sounds/button_press.mp3\", \"data/sounds/button_rollover.mp3\", \"data/sounds/doll_close.mp3\", \"data/sounds/doll_drop.mp3\", \"data/sounds/doll_level_up_1.mp3\", \"data/sounds/doll_level_up_2.mp3\", \"data/sounds/doll_open.mp3\", \"data/sounds/doll_overmatch.mp3\", \"data/sounds/doll_pick.mp3\", \"data/sounds/ingame_music.mp3\", \"data/sounds/play_button_click.mp3\", \"data/sounds/titlescreen_music.mp3\"], \"base\": \"http://amsarkadium-a.akamaihd.net/assets/global/game/trizzle/9335dc40-4402-4b83-86c1-46b41c49ce64\"}}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://amsarkadium-a.akamaihd.net/assets/global/game/trizzle/9335dc40-4402-4b83-86c1-46b41c49ce64/trizzle.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Xmatch2016-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Xmatch2016-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/xmatch-2016\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/135524/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperRally3d-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SuperRally3d-v0\", \"human_url\": \"http://notdoppler.com/superrally3d.php\", \"regions\": null, \"height\": 374, \"width\": 750, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/superrally3d.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleShooterChallenge-v0\": {\"readme_header\": null, \"categories\": [\"arcade\", \"1 player\", \"flash\", \"shooting\", \"bubbles\", \"matching\", \"free\", \"match 3\", \"idnet\", \"bubble shooter\", \"idnet highscore\", \"idnet achievements\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.BubbleShooterChallenge-v0\", \"human_url\": \"http://www.y8.com/games/bubble_shooter_challenge\", \"regions\": [{\"coordinates\": [670, 146, 222, 396], \"type\": \"noclick\"}, {\"coordinates\": [400, 418, 606, 78], \"type\": \"noclick\"}], \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/107990/original/bubble_shooter_challenge.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PowerSwing-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PowerSwing-v0\", \"human_url\": \"http://www.gamesbutler.com/game/2268/power-swing/\", \"regions\": null, \"height\": 444, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/powerswing.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SnowQueen-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SnowQueen-v0\", \"human_url\": \"http://www.neongames.com/game/Snow+Queen\", \"regions\": null, \"height\": 600, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesonly.net/uploaded/swf/snowqueen.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ShimmyChute-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ShimmyChute-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/shimmy-chute\", \"regions\": null, \"height\": 800, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/129434/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Crazycle-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Crazycle-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25402\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae31d7bb38c.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CaptainNutty-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.CaptainNutty-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/captain-nutty\", \"regions\": null, \"height\": 530, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/39009/game.swf?1415283677\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ViewtifulFightClub2-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ViewtifulFightClub2-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25552\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/575ee9840404a.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TheOneForkRestaurantDx-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TheOneForkRestaurantDx-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25429\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae337ac0981.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TableTennisChallenge-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TableTennisChallenge-v0\", \"human_url\": \"http://www.y8.com/games/table_tennis_challenge\", \"regions\": null, \"height\": 585, \"width\": 780, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://img-ak.y8.com/cloud/y8-game/contents/117550/original/table_tennis_challenge.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MinedigJourneyToHollowEarth-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MinedigJourneyToHollowEarth-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/minedig-journey-to-hollow-earth\", \"regions\": null, \"height\": 550, \"width\": 350, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/137667/game.swf?1461944537\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MultiballMadness-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MultiballMadness-v0\", \"human_url\": \"http://armorgames.com/play/702\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/multiball-madness-702.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TumbleTiles-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.TumbleTiles-v0\", \"human_url\": \"http://www.arkadium.com/games/tumble-tiles/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {\"relative\": {\"files\": [\"assets/sounds/HitDestructibleTile.mp3\", \"assets/sounds/TilePreDamage.mp3\", \"assets/sounds/TileUniced.mp3\", \"assets/sounds/TileBounce_3.mp3\", \"assets/sounds/levelCompleteAppear.mp3\", \"assets/sounds/GoalBannerDisappear.mp3\", \"assets/sounds/PowerupAdjacentOrBombComboDouble.mp3\", \"assets/config/levels.xml\", \"assets/sounds/bombStartFly.mp3\", \"assets/sounds/TileBounce_0.mp3\", \"assets/data/locale/it-IT/strings.xml\", \"assets/sounds/blackHoleCatch.mp3\", \"assets/sounds/GainStar1.mp3\", \"assets/sounds/TileClick.mp3\", \"assets/sounds/PowerupWindup.mp3\", \"assets/sounds/PowerupAdjacent.mp3\", \"assetsPlatformSpecific/config/assets.xml\", \"assets/sounds/subgoalCompleted.mp3\", \"assets/sounds/tileRotationCompleted.mp3\", \"assets/sounds/PowerupMeterFilled.mp3\", \"assets/data/locale/de-DE/strings.xml\", \"assets/sounds/BaddieGrunt1.mp3\", \"assets/sounds/TileBounce_2.mp3\", \"assets/sounds/GoalBannerAppear.mp3\", \"assets/config/assets.xml\", \"assets/sounds/magicGem.mp3\", \"assets/sounds/PowerupPartyBombExplosion1.mp3\", \"assets/sounds/TileBounce_1.mp3\", \"assets/sounds/TilePop2.mp3\", \"assets/sounds/PowerupColorClear.mp3\", \"assets/sounds/GainStar2.mp3\", \"assets/sounds/TileIced.mp3\", \"assets/sounds/PowerupAdjacentOrBombComboSingle.mp3\", \"assets/sounds/backgroundMusic.mp3\", \"assets/config/sounds.xml\", \"assets/sounds/TileBounce_0.mp3\", \"assets/data/locale/en-US/strings.xml\", \"assets/sounds/PowerupColRow.mp3\", \"assets/sounds/Success.mp3\", \"assets/sounds/HitGlassSpace.mp3\", \"assets/sounds/ButtonClick.mp3\", \"assets/sounds/PowerupBombExplosion.mp3\", \"assets/sounds/TilePop1.mp3\", \"assets/sounds/PowerupBombTrigger.mp3\", \"assets/sounds/TileUncaged.mp3\", \"assets/data/locale/fr-FR/strings.xml\", \"assets/sounds/TilePop3.mp3\", \"assets/data/locale/es-ES/strings.xml\", \"assets/sounds/GainStar3.mp3\", \"assetsPlatformSpecific/textures/1x/background.jpg\", \"assetsPlatformSpecific/textures/1x/fonts/berlin-sans-demi-small.xml\", \"assetsPlatformSpecific/textures/1x/fonts/berlin-sans-demi-white.xml\", \"assetsPlatformSpecific/textures/1x/fonts/berlin-sans-demi-yellow.xml\", \"assetsPlatformSpecific/textures/1x/fonts/berlin-sans-demi.xml\", \"assetsPlatformSpecific/textures/1x/fonts/level-numbers-white.xml\", \"assetsPlatformSpecific/textures/1x/fonts/level-numbers-yellow.xml\", \"assetsPlatformSpecific/textures/1x/fontsatlas.png\", \"assetsPlatformSpecific/textures/1x/fontsatlas.xml\", \"assetsPlatformSpecific/textures/1x/gameplayatlas.png\", \"assetsPlatformSpecific/textures/1x/gameplayatlas.xml\", \"assetsPlatformSpecific/textures/1x/gui/ConnectionProposition.xml\", \"assetsPlatformSpecific/textures/1x/gui/buyCoinsControl.xml\", \"assetsPlatformSpecific/textures/1x/gui/goal.xml\", \"assetsPlatformSpecific/textures/1x/gui/intro_screen.xml\", \"assetsPlatformSpecific/textures/1x/gui/level_completed.xml\", \"assetsPlatformSpecific/textures/1x/gui/level_failed.xml\", \"assetsPlatformSpecific/textures/1x/gui/pause_popup.xml\", \"assetsPlatformSpecific/textures/1x/introscreenatlas.png\", \"assetsPlatformSpecific/textures/1x/introscreenatlas.xml\", \"assetsPlatformSpecific/textures/1x/introscreenbackgroundatlas.jpg\", \"assetsPlatformSpecific/textures/1x/introscreenbackgroundatlas.xml\", \"assetsPlatformSpecific/textures/1x/levelcompleteatlas.png\", \"assetsPlatformSpecific/textures/1x/levelcompleteatlas.xml\", \"assetsPlatformSpecific/textures/1x/levelselectatlas.png\", \"assetsPlatformSpecific/textures/1x/levelselectatlas.xml\", \"assetsPlatformSpecific/textures/1x/particles/black-hole-prediction.xml\", \"assetsPlatformSpecific/textures/1x/particles/chain-break.xml\", \"assetsPlatformSpecific/textures/1x/particles/gem-break.xml\", \"assetsPlatformSpecific/textures/1x/particles/glass-break.xml\", \"assetsPlatformSpecific/textures/1x/particles/intro-screen-idle.xml\", \"assetsPlatformSpecific/textures/1x/particles/liana-break.xml\", \"assetsPlatformSpecific/textures/1x/particles/mask-break.xml\", \"assetsPlatformSpecific/textures/1x/particles/powerup-trail.xml\", \"assetsPlatformSpecific/textures/1x/particles/stars.xml\", \"assetsPlatformSpecific/textures/1x/particles/stars_big.xml\", \"assetsPlatformSpecific/textures/1x/particles/stone-break.xml\", \"assetsPlatformSpecific/textures/1x/particles/tile-break-blue.xml\", \"assetsPlatformSpecific/textures/1x/particles/tile-break-green.xml\", \"assetsPlatformSpecific/textures/1x/particles/tile-break-purple.xml\", \"assetsPlatformSpecific/textures/1x/particles/tile-break-red.xml\", \"assetsPlatformSpecific/textures/1x/particles/tile-break-yellow.xml\", \"assetsPlatformSpecific/textures/1x/powerup-bar-blue.png\", \"assetsPlatformSpecific/textures/1x/powerup-bar-green.png\", \"assetsPlatformSpecific/textures/1x/powerup-bar-mask.png\", \"assetsPlatformSpecific/textures/1x/powerup-bar-purple.png\", \"assetsPlatformSpecific/textures/1x/powerup-bar-red.png\", \"assetsPlatformSpecific/textures/1x/powerup-bar-yellow.png\", \"assetsPlatformSpecific/textures/1x/powerup-sparkle-guide.png\"], \"base\": \"http://amsarkadium-a.akamaihd.net/assets/arena-4/game/tumble-tiles/05b8d9cf-8607-4876-a95f-8d48eeee68bf\"}}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://amsarkadium-a.akamaihd.net/assets/arena-4/game/tumble-tiles/05b8d9cf-8607-4876-a95f-8d48eeee68bf/tumble-tiles.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SuperRallyChallenge2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.SuperRallyChallenge2-v0\", \"human_url\": \"http://insanehero.com/mygames/SuperRallyChallenge2/index.html\", \"regions\": null, \"height\": 360, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://insanehero.com/mygames/SuperRallyChallenge2/superrallychallenge2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Offroaders2-v0\": {\"readme_header\": null, \"categories\": [\"sports\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Offroaders2-v0\", \"human_url\": \"http://notdoppler.com/offroaders2.php\", \"regions\": null, \"height\": 550, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/offroaders2.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Commando2-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Commando2-v0\", \"human_url\": \"http://www.miniclip.com/games/commando-2/en/\", \"regions\": null, \"height\": 400, \"width\": 590, \"extra_files\": {\"absolute\": [\"http://www.miniclip.com/swfcontent/components/gatekeeper_as2.swf\", \"http://www.miniclip.com/swfcontent/components/game_offsite_as2.swf\"]}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.miniclip.com/games/commando-2/en/commando2.swf\", \"enable_internet\": false, \"serve_from_domain\": \"www.miniclip.com\"}, \"flashgames.Xnake-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Xnake-v0\", \"human_url\": \"http://armorgames.com/play/780\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/xnake-780.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BusinessmanSimulator-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BusinessmanSimulator-v0\", \"human_url\": \"http://www.gamesbutler.com/game/25668/businessman-simulator/\", \"regions\": null, \"height\": 540, \"width\": 960, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/04bd1eaf1fd74969.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.KnightsOfRock-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.KnightsOfRock-v0\", \"human_url\": \"http://armorgames.com/play/45\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/knights-of-rock-45.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ZodiacMatch-v0\": {\"readme_header\": null, \"categories\": [\"match-3\", \"puzzle\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ZodiacMatch-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Zodiac-Match,576742227280286626\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/z/Zodiac_match/ZodiacMatch.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dSuperRide-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": true, \"id\": \"flashgames.3dSuperRide-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-super-ride/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-super-ride.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlyPlane-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlyPlane-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/fly-plane\", \"regions\": null, \"height\": 300, \"width\": 500, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/222/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.WindowShooter-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.WindowShooter-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000171\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570e1c145137f.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MatchMonsters-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MatchMonsters-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/match-monsters\", \"regions\": null, \"height\": 500, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/22318/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl2-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.3dRookieCop-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.3dRookieCop-v0\", \"human_url\": \"http://www.cartitans.com/game/3d-rookie-cop/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/3d-rookie-cop.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ZombieMatch3-v0\": {\"readme_header\": null, \"categories\": [\"match 3\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.ZombieMatch3-v0\", \"human_url\": \"http://www.smileygamer.com/ourgames/zombiematch3.html\", \"regions\": [{\"coordinates\": [16, 136, 477, 73], \"type\": \"noclick\"}], \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.smileygamer.com/ourgames/zombiematch3.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRaceLvl5-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.NeonRaceLvl5-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0009/7872/live/embeddable_97872.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AdrenalineChaser-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AdrenalineChaser-v0\", \"human_url\": \"http://www.cartitans.com/game/adrenaline-chaser/\", \"regions\": null, \"height\": 400, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"birdseye\"}, \"title\": null, \"swf_url\": \"http://www.cartitans.com/download/adrenaline-chaser.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Jumpz-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Jumpz-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Jumpz,576742227280285289\", \"regions\": null, \"height\": 640, \"width\": 480, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/j/Jumpz/Jumpz.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl12-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl12-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.GoGreenGo-v0\": {\"readme_header\": null, \"categories\": [\"platform\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.GoGreenGo-v0\", \"human_url\": \"http://www.freegamesforyourwebsite.com/game/go-green-go\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cdn.freeonlinegames.com/games/4111/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer2Lvl7-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacer2Lvl7-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0011/8219/live/embeddable_118219.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.StormRage-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.StormRage-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/storm-rage\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/15028/game.swf?1437476679\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.PouThanksgivingDaySlacking-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.PouThanksgivingDaySlacking-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25204\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae257b08b3e.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BearInSuperActionAdventure-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.BearInSuperActionAdventure-v0\", \"human_url\": \"http://armorgames.com/play/17755\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/bear-in-super-action-17755.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IceBlock-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IceBlock-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Ice-Block,576742227280289227\", \"regions\": null, \"height\": 510, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/i/Ice-Block/Ice_Block_v1.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Match2Collapse-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Match2Collapse-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/match-2-collapse\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/131631/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.VolcanoPanicInIsland-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.VolcanoPanicInIsland-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25445\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/56ae34446277e.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.BubbleHit-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.BubbleHit-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Bubble-Hit,576742227280283380\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/games/flash/b/bubble_hit/bubble_hit.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.RobotWantsFishy-v0\": {\"readme_header\": null, \"categories\": [\"sparsereward\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.RobotWantsFishy-v0\", \"human_url\": \"http://www.andkon.com/arcade/adventureaction/robotwantsfishy/\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.andkon.com/arcade/adventureaction/robotwantsfishy/robotwantsfishy.swf\", \"enable_internet\": false, \"serve_from_domain\": \"andkon.com\"}, \"flashgames.ToyWarAngryRobotDog-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ToyWarAngryRobotDog-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000192\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570e73468701f.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NoughtsAndCrosses-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.NoughtsAndCrosses-v0\", \"human_url\": \"http://old.2pg.com/game/noughts-and-crosses/play/\", \"regions\": null, \"height\": 525, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://old.2pg.com/wp-content/games/custom/N/noughtsandcrosses1.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.TrickOrToad-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.TrickOrToad-v0\", \"human_url\": \"http://armorgames.com/play/1382\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/trick-or-toad-1382.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.YummyyummyMonsterShooter-v0\": {\"readme_header\": null, \"categories\": [\"jewel\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.YummyyummyMonsterShooter-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Yummy-Yummy-Monster-Shooter,576742227280286880\", \"regions\": null, \"height\": 500, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/y/Yummy_yummy_monster/yummy_yummy_monster_shooter.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SnackOnLittleCreatures-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SnackOnLittleCreatures-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000180\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570e1c5c9550a.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.IntoSpace-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.IntoSpace-v0\", \"human_url\": \"http://notdoppler.com/intospace.php\", \"regions\": null, \"height\": 500, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://i.notdoppler.com/files/intospace.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.Chefday-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.Chefday-v0\", \"human_url\": \"http://www.games68.com/games.php?id=5000134\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/570cf7b8e7c94.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.FlyingTest-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.FlyingTest-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/flying-test\", \"regions\": null, \"height\": 600, \"width\": 800, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/134912/game.swf?1448885357\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.MusicZap-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.MusicZap-v0\", \"human_url\": \"http://armorgames.com/play/1364\", \"regions\": null, \"height\": 450, \"width\": 600, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://cache.armorgames.com/files/games/music-zap-1364.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SnowPrincessMakeup-v0\": {\"readme_header\": null, \"categories\": [\"Tower Defense\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SnowPrincessMakeup-v0\", \"human_url\": \"http://publishers.spilgames.com/en/game/Snow-Princess-Make-Up,576742227280284508\", \"regions\": null, \"height\": 513, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www8.agame.com/mirror/flash/s/SnowPrincessMakeUp/snow_princess_make_up.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.CoasterRacer2-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": true, \"id\": \"flashgames.CoasterRacer2-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/coaster-racer-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0011/8219/live/embeddable_118219.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.NeonRace2Lvl5-v0\": {\"readme_header\": null, \"categories\": [\"racing\"], \"rewarder\": true, \"autostart\": false, \"id\": \"flashgames.NeonRace2Lvl5-v0\", \"human_url\": \"http://www.kongregate.com/games/LongAnimals/neon-race-2\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {\"perspective\": \"driver\"}, \"title\": null, \"swf_url\": \"http://external.kongregate-games.com/gamez/0013/7834/live/embeddable_137834.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.ReleaseTheMooks-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.ReleaseTheMooks-v0\", \"human_url\": \"http://www.gamesbutler.com/game/3635/release-the-mooks/\", \"regions\": null, \"height\": 500, \"width\": 700, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/relesethemooks.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.OswaldTheAngryDwarf-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.OswaldTheAngryDwarf-v0\", \"human_url\": \"http://www.games68.com/games.php?id=25210\", \"regions\": null, \"height\": 480, \"width\": 640, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.games68.com/games/game-1462009415.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.SantaClimbHere-v0\": {\"readme_header\": null, \"categories\": [\"Assorted\"], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.SantaClimbHere-v0\", \"human_url\": \"http://www.gamesbutler.com/game/27121/santa-climb-here/\", \"regions\": null, \"height\": 525, \"width\": 400, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.gamesbutler.com/files/660b25a543ac979e.swf\", \"enable_internet\": false, \"serve_from_domain\": null}, \"flashgames.AntsGlider-v0\": {\"readme_header\": null, \"categories\": [], \"rewarder\": false, \"autostart\": false, \"id\": \"flashgames.AntsGlider-v0\", \"human_url\": \"http://www.gamesforwebsites.com/game/ants-glider\", \"regions\": null, \"height\": 480, \"width\": 720, \"extra_files\": {}, \"server_timestep_limit\": null, \"tags\": {}, \"title\": null, \"swf_url\": \"http://www.freeonlinegames.com/games/39883/game.swf\", \"enable_internet\": false, \"serve_from_domain\": null}}\n"
  },
  {
    "path": "universe/runtimes/registration.py",
    "content": "import collections\nimport json\n\nimport six\nfrom gym import error\n\n\nclass UnregisteredRuntime(error.Unregistered):\n    \"\"\"Raised when the user requests a runtime from the registry that does\n    not actually exist.\n    \"\"\"\n    pass\n\nclass DockerRuntime(object):\n    \"\"\"Lightweight struct for our DockerImage configuration\"\"\"\n    def __init__(self, id=id, image=None, command=None, host_config=None, default_params=None, server_registry_file=None):\n        \"\"\"\n        Args:\n            id: The short identifier for this runtime\n            image: The full docker image name including a tag\n            command: A list of commands to be passed to docker\n            host_config: A dict that will be fed to docker.Client().create_host_config\n            default_params: The default parameter values for this environment\n            server_registry: A file containing a JSON dump of the server registry. The format will be runtime-specific.\n        \"\"\"\n        self.id = id\n        self.image = image\n        self.command = command or []\n        self.host_config = host_config or {}\n        self.default_params = default_params or {}\n\n        self._server_registry = None\n        self._server_registry_file = server_registry_file\n\n    @property\n    def server_registry(self):\n        if self._server_registry is None:\n            with open(self._server_registry_file) as f:\n                self._server_registry = json.load(f)\n        return self._server_registry\n\n    @property\n    def _cli_flags(self):\n        # Not everything maps in a straightforward way, e.g. cap_add => '--cap-add' but ipc_mode => '--ipc\n        api_to_cli = {\n            'ipc_mode': 'ipc'\n        }\n\n        cli_flags = []\n        for api_key, api_value in self.host_config.items():\n            if isinstance(api_value, (six.string_types, bool)):\n                cli_values = [api_value]\n            else:\n                cli_values = api_value\n\n            for cli_value in cli_values:\n                if api_key in api_to_cli:\n                    api_key = api_to_cli[api_key]\n                cli_flag = '--{}'.format(api_key.replace('_', '-'))\n                if isinstance(cli_value, bool):\n                    # boolean flag, like --privileged\n                    cli_flags += [cli_flag]\n                else:\n                    cli_flags += [cli_flag, cli_value]\n\n        return cli_flags\n\n    def cli_command(self, vnc_port, rewarder_port, extra_flags=[]):\n        return ['docker', 'run',\n           '-p', '{}:5900'.format(vnc_port),\n           '-p', '{}:15900'.format(rewarder_port)] + \\\n           extra_flags + \\\n           self._cli_flags + \\\n           [self.image] + self.command\n\n\nclass WindowsRuntime(object):\n    # TODO: Spawn windows runtimes (right now managed manually)\n    def __init__(self, id=id, default_params=None):\n        \"\"\"\n        Args:\n            id: The short identifier for this runtime\n        \"\"\"\n        self.id = id\n        self.default_params = default_params\n\n\nclass Registry(object):\n    def __init__(self):\n        self.runtimes = collections.OrderedDict()\n\n    def register_runtime(self, id, kind, **kwargs):\n        if kind == \"docker\":\n            self.runtimes[id] = DockerRuntime(id, **kwargs)\n        elif kind == \"windows\":\n            self.runtimes[id] = WindowsRuntime(id, **kwargs)\n        else:\n            raise error.Error(\"No runtime of kind {} . \\n Valid options are ['docker']\".format(kind))\n\n    def runtime_spec(self, id):\n        \"\"\"\n        id is a string describing the runtime, e.g 'flashgames\n\n        Returns a configured DockerRuntime object\n        \"\"\"\n        try:\n            return self.runtimes[id]\n        except KeyError:\n            raise UnregisteredRuntime('No registered runtime with name: {}'.format(id))\n\n\nregistry = Registry()\nregister_runtime = registry.register_runtime\nruntime_spec = registry.runtime_spec\n"
  },
  {
    "path": "universe/runtimes.yml",
    "content": "flashgames:\n  tag: 0.20.28\ngym-core:\n  tag: 0.20.6\nworld-of-bits:\n  tag: 0.20.0\n"
  },
  {
    "path": "universe/scoreboard/__init__.py",
    "content": "from gym.benchmarks import scoring\nfrom gym.benchmarks import register_benchmark\n\nregister_benchmark(\n    id='Atari7VNC-v0',\n    scorer=scoring.TotalReward(),\n    name='AtariVNC',\n    description='7 Atari games, with pixel observations (using universe)',\n    tasks=[\n        {\n            \"env_id\": \"VNCBeamRider-v3\",\n            \"trials\": 1,\n            \"max_timesteps\": 10000000\n        },\n        {\n            \"env_id\": \"VNCBreakout-v3\",\n            \"trials\": 1,\n            \"max_timesteps\": 10000000\n        },\n        {\n            \"env_id\": \"VNCEnduro-v3\",\n            \"trials\": 1,\n            \"max_timesteps\": 10000000\n        },\n        {\n            \"env_id\": \"gym-core.Pong-v3\",\n            \"trials\": 1,\n            \"max_timesteps\": 10000000\n        },\n        {\n            \"env_id\": \"VNCQbert-v3\",\n            \"trials\": 1,\n            \"max_timesteps\": 10000000\n        },\n        {\n            \"env_id\": \"VNCSeaquest-v3\",\n            \"trials\": 1,\n            \"max_timesteps\": 10000000\n        },\n        {\n            \"env_id\": \"VNCSpaceInvaders-v3\",\n            \"trials\": 1,\n            \"max_timesteps\": 10000000\n        }\n    ])\n\nregister_benchmark(\n    id='FlashRacing-v0',\n    scorer=scoring.RewardPerTime(),\n    name='FlashRacing',\n    description='7 flash racing games, goal is best score per time',\n    tasks=[\n        {'env_id': 'flashgames.NeonRace-v0',\n         'trials': 1,\n         'max_timesteps': 5000000,\n         'reward_floor':   175.0,\n         'reward_ceiling': 1700.0,\n        },\n        {'env_id': 'flashgames.CoasterRacer-v0',\n         'trials': 1,\n         'max_timesteps': 5000000,\n         'reward_floor':   17.0,\n         'reward_ceiling': 400.0,\n        },\n        {'env_id': 'flashgames.HeatRushUsa-v0',\n         'trials': 1,\n         'max_timesteps': 5000000,\n         'reward_floor':   150.0,\n         'reward_ceiling': 700.0,\n        },\n        {'env_id': 'flashgames.FormulaRacer-v0',\n         'trials': 1,\n         'max_timesteps': 5000000,\n         'reward_floor':  0.27,\n         'reward_ceiling': 1.0,\n        },\n        {'env_id': 'flashgames.DuskDrive-v0',\n         'trials': 1,\n         'max_timesteps': 5000000,\n         'reward_floor':   5000.0,\n         'reward_ceiling': 15000.0,\n        },\n        {'env_id': 'flashgames.SpacePunkRacer-v0',\n         'trials': 1,\n         'max_timesteps': 5000000,\n         'reward_floor':   0.67,\n         'reward_ceiling': 2.25,\n        },\n        {'env_id': 'flashgames.NeonRace2-v0',\n         'trials': 1,\n         'max_timesteps': 5000000,\n         'reward_floor':   0.0,\n         'reward_ceiling': 1200.0,\n        }\n    ])\n"
  },
  {
    "path": "universe/spaces/__init__.py",
    "content": "from universe.spaces.hardcoded import Hardcoded\nfrom universe.spaces.vnc_action_space import VNCActionSpace\nfrom universe.spaces.vnc_event import VNCEvent, KeyEvent, PointerEvent\nfrom universe.spaces.vnc_observation_space import VNCObservationSpace\n\nfrom universe.spaces.diagnostics import PeekReward\n"
  },
  {
    "path": "universe/spaces/diagnostics.py",
    "content": "class DiagnosticEvent(object):\n    pass\n\nPeekReward = DiagnosticEvent()\n"
  },
  {
    "path": "universe/spaces/hardcoded.py",
    "content": "from gym.spaces import prng\n\nclass Hardcoded(object):\n    def __init__(self, actions):\n        self.actions = actions\n\n    def contains(self, action):\n        return action in self.actions\n\n    def sample(self):\n        i = prng.np_random.randint(len(self.actions))\n        return self.actions[i]\n\n    def __getitem__(self, i):\n        return self.actions[i]\n"
  },
  {
    "path": "universe/spaces/joystick_action_space.py",
    "content": "import gym\nfrom gym.spaces import Box\nfrom universe.spaces import joystick_event\nfrom gym.spaces import prng\nfrom collections import OrderedDict\n\n\nclass JoystickActionSpace(gym.Space):\n    \"\"\"\n    Programmable joystick - currently Windows-only => mapped to vJoy\n    \"\"\"\n    def __init__(self, axis_x=False, axis_y=False, axis_z=False, axis_rx=False, axis_ry=False, axis_rz=False,\n                 slider_0=False, slider_1=False):\n        self.event_space_map = OrderedDict()\n\n        if axis_x:\n            self.axis_x = box_axis()\n            self.event_space_map[joystick_event.JoystickAxisXEvent] = self.axis_x\n        if axis_y:\n            self.axis_y = box_axis()\n            self.event_space_map[joystick_event.JoystickAxisYEvent] = self.axis_y\n        if axis_z:\n            self.axis_z = box_axis()\n            self.event_space_map[joystick_event.JoystickAxisZEvent] = self.axis_z\n        if axis_rx:\n            self.axis_rx = box_axis()\n            self.event_space_map[joystick_event.JoystickAxisRxEvent] = self.axis_rx\n        if axis_ry:\n            self.axis_ry = box_axis()\n            self.event_space_map[joystick_event.JoystickAxisRyEvent] = self.axis_ry\n        if axis_rz:\n            self.axis_rz = box_axis()\n            self.event_space_map[joystick_event.JoystickAxisRzEvent] = self.axis_rz\n        if slider_0:\n            self.slider_0 = box_axis()\n            self.event_space_map[joystick_event.JoystickSlider0Event] = self.slider_0\n        if slider_1:\n            self.slider_1 = box_axis()\n            self.event_space_map[joystick_event.JoystickSlider1Event] = self.slider_1\n        # TODO: Add buttons (similar to a vnc_event.KeyEvent - but 1..32)\n        # TODO: Add POV hats\n\n    def contains(self, action):\n        if not isinstance(action, list):\n            return False\n        for a in action:\n            if isinstance(a, joystick_event.JoystickAxisEvent):\n                axis = self.event_space_map[a]\n                if not axis.contains(a):\n                    return False\n        return True\n\n    def sample(self):\n        event_type_index = prng.np_random.randint(len(self.event_space_map))\n        event_type = list(self.event_space_map.keys())[event_type_index]\n        if event_type.__bases__[0] == joystick_event.JoystickAxisEvent:\n            event = [event_type(self.event_space_map[event_type].sample()[0])]\n        else:\n            raise JoystickActionSpaceException('Unexpected event type')\n        return event\n\n\nclass JoystickActionSpaceException(Exception):\n    pass\n\n\ndef box_axis():\n    return Box(-1.0, 1.0, shape=(1,))\n"
  },
  {
    "path": "universe/spaces/joystick_event.py",
    "content": "class JoystickEvent(object):\n    pass\n\n\nclass JoystickAxisEvent(JoystickEvent):\n    def __init__(self, amount):\n        self.amount = float(amount)\n\n    def __repr__(self):\n        return str(type(self)) + '<amount={}>'.format(self.amount)\n\n    def __str__(self):\n        return repr(self)\n\n    def __hash__(self):\n        return self.amount.__hash__()\n\n    def __eq__(self, other):\n        return type(other) == type(self) and \\\n               other.amount == self.amount\n\n    def compile(self):\n        return type(self).__name__, self.amount\n\n\nclass JoystickAxisXEvent(JoystickAxisEvent):\n    pass\n\n\nclass JoystickAxisYEvent(JoystickAxisEvent):\n    pass\n\n\nclass JoystickAxisZEvent(JoystickAxisEvent):\n    pass\n\n\nclass JoystickAxisRxEvent(JoystickAxisEvent):\n    pass\n\n\nclass JoystickAxisRyEvent(JoystickAxisEvent):\n    pass\n\n\nclass JoystickAxisRzEvent(JoystickAxisEvent):\n    pass\n\n\nclass JoystickSlider0Event(JoystickAxisEvent):\n    pass\n\n\nclass JoystickSlider1Event(JoystickAxisEvent):\n    pass\n"
  },
  {
    "path": "universe/spaces/vnc_action_space.py",
    "content": "import gym\nimport string\n\nfrom gym.spaces import prng\n\nfrom universe.vncdriver import constants\nfrom universe.spaces import vnc_event\n\nclass VNCActionSpace(gym.Space):\n    \"\"\"The space of VNC actions.\n\n    You can submit a list of KeyEvents or PointerEvents. KeyEvents\n    correspond to pressing or releasing a key. PointerEvents correspond\n    to moving to a specific pixel, and setting the mouse buttons to some state\n    (buttonmask is a bitmap corresponding to which buttons are down).\n\n    Note that key releases work differently from click releases: keys\n    are stateful and must be explicitly released, while the state of\n    the mouse buttons is provided at each timestep, so you have to\n    explicitly keep the mouse down.\n\n    Attributes:\n        keys (list<KeyEvent>): The allowed key presses\n        buttonmasks (list<int>): The allowed buttonmasks (i.e. mouse presses)\n        screen_shape (int, int): The X and Y dimensions of the screen\n    \"\"\"\n\n    def __init__(self, keys=None, buttonmasks=None, screen_shape=(1024, 728)):\n        self.keys = []\n        if keys is None:\n            keys = [c for c in string.printable] + list(constants.KEYMAP.keys())\n        for key in (keys or []):\n            down = vnc_event.KeyEvent.by_name(key, down=True)\n            up = vnc_event.KeyEvent.by_name(key, down=False)\n            self.keys.append(down)\n            self.keys.append(up)\n        self._key_set = set(self.keys)\n\n        self.screen_shape = screen_shape\n        if self.screen_shape is not None:\n            self.buttonmasks = []\n            if buttonmasks is None:\n                buttonmasks = range(256)\n            for buttonmask in buttonmasks:\n                self.buttonmasks.append(buttonmask)\n            self._buttonmask_set = set(self.buttonmasks)\n\n    def contains(self, action):\n        if not isinstance(action, list):\n            return False\n\n        for a in action:\n            if isinstance(a, vnc_event.KeyEvent):\n                if a not in self._key_set:\n                    return False\n            elif isinstance(a, vnc_event.PointerEvent):\n                if self.screen_shape is None:\n                    return False\n\n                if a.x < 0 or a.x > self.screen_shape[0]:\n                    return False\n                elif a.y < 0 or a.y > self.screen_shape[1]:\n                    return False\n                elif a.buttonmask not in self._buttonmask_set:\n                    return False\n\n        return True\n\n    def sample(self):\n        # Both key and pointer allowed\n        if self.screen_shape is not None:\n            event_type = prng.np_random.randint(2)\n        else:\n            event_type = 0\n\n        if event_type == 0:\n            # Let's press a key\n            key = prng.np_random.choice(self.keys)\n            event = [key]\n        else:\n            x = prng.np_random.randint(self.screen_shape[0])\n            y = prng.np_random.randint(self.screen_shape[1])\n            buttonmask = prng.np_random.choice(self.buttonmasks)\n\n            event = [vnc_event.PointerEvent(x, y, buttonmask)]\n        return event\n"
  },
  {
    "path": "universe/spaces/vnc_event.py",
    "content": "import string\nfrom universe import error\nfrom universe.vncdriver import constants\n\nclass VNCEvent(object):\n    pass\n\ndef keycode(key):\n    if key in constants.KEYMAP:\n        return constants.KEYMAP.get(key)\n    elif len(key) == 1:\n        return ord(key)\n    else:\n        raise error.Error('Not sure how to translate to keycode: {!r}'.format(key))\n\nclass KeyEvent(VNCEvent):\n    _keysym_to_name = {}\n    for key, value in constants.KEYMAP.items():\n        _keysym_to_name[value] = key\n    for c in string.printable:\n        _keysym_to_name[ord(c)] = c\n\n    @classmethod\n    def build(cls, keys, down=None):\n        \"\"\"Build a key combination, such as:\n\n        ctrl-t\n        \"\"\"\n        codes = []\n        for key in keys.split('-'):\n            key = keycode(key)\n            codes.append(key)\n\n        events = []\n        if down is None or down:\n            for code in codes:\n                events.append(cls(code, down=True))\n\n        if down is None or not down:\n            for code in reversed(codes):\n                events.append(cls(code, down=False))\n        return events\n\n    @classmethod\n    def by_name(cls, key, down=None):\n        return cls(keycode(key), down=down)\n\n    def __init__(self, key, down=True):\n        # TODO: validate key\n        self.key = key\n        self.down = bool(down)\n\n    def compile(self):\n        return 'KeyEvent', self.key, self.down\n\n    def __repr__(self):\n        if self.down:\n            direction = 'down'\n        else:\n            direction = 'up'\n        name = self._keysym_to_name.get(self.key)\n        if not name:\n            name = '0x{:x}'.format(self.key)\n        else:\n            name = '{} (0x{:x})'.format(name, self.key)\n        return 'KeyEvent<key={} direction={}>'.format(name, direction)\n\n    def __str__(self):\n        return repr(self)\n\n    def __hash__(self):\n        return (self.key, self.down).__hash__()\n\n    def __eq__(self, other):\n        return type(other) == type(self) and \\\n            other.key == self.key and \\\n            other.down == self.down\n\n    @property\n    def key_name(self):\n        \"\"\"Human readable name\"\"\"\n        return self._keysym_to_name.get(self.key)\n\nclass PointerEvent(VNCEvent):\n    def __init__(self, x, y, buttonmask=0):\n        self.x = x\n        self.y = y\n        self.buttonmask = buttonmask\n\n    def compile(self):\n        return 'PointerEvent', self.x, self.y, self.buttonmask\n\n    def __repr__(self):\n        return 'PointerEvent<x={} y={} buttonmask={}>'.format(self.x, self.y, self.buttonmask)\n\n    def __str__(self):\n        return repr(self)\n"
  },
  {
    "path": "universe/spaces/vnc_observation_space.py",
    "content": "import gym\n\nclass VNCObservationSpace(gym.Space):\n    # For now, we leave the VNC ObservationSpace wide open, since\n    # there isn't much use-case for this object.\n    def contains(self, x):\n        return True\n"
  },
  {
    "path": "universe/twisty.py",
    "content": "import threading\nfrom twisted.python.runtime import platform\n\n# On OSX, we should use kqueue rather than the default select\n# backend. (Proximal issue is that select only can handle a limited\n# number of file descriptors.)\n#\n# Based off twisted.internet.default\ndef _get_reactor(platform):\n    try:\n        if platform.isLinux():\n            try:\n                from twisted.internet import epollreactor\n                cls = epollreactor.EPollReactor\n            except ImportError:\n                from twisted.internet import pollreactor\n                cls = pollreactor.PollReactor\n        elif platform.isMacOSX():\n            from twisted.internet import kqreactor\n            cls = kqreactor.KQueueReactor\n        elif platform.getType() == 'posix' and not platform.isMacOSX():\n            from twisted.internet import pollreactor\n            cls = pollreactor.PollReactor\n        else:\n            from twisted.internet import selectreactor\n            cls = selectreactor.SelectReactor\n    except ImportError:\n        from twisted.internet import selectreactor\n        cls = selectreactor.SelectReactor\n    return cls()\n\nclass TwistedThread(threading.Thread):\n    started = False\n    daemon = True\n\n    @classmethod\n    def start_once(cls):\n        if cls.started:\n            return\n        cls.started = True\n\n        instance = cls(name='Twisted')\n        instance.start()\n\n    def run(self):\n        reactor.run(installSignalHandlers=False)\n\nreactor = _get_reactor(platform)\nstart_once = TwistedThread.start_once\n"
  },
  {
    "path": "universe/utils/__init__.py",
    "content": "import logging\nimport six\nimport sys\nif six.PY2:\n    import Queue as queue\nelse:\n    import queue\nimport threading\nimport signal\nfrom twisted.internet import defer\n\nfrom universe.twisty import reactor\n\nlogger = logging.getLogger(__name__)\n\nclass ErrorBuffer(object):\n    def __init__(self):\n        self.queue = queue.Queue()\n\n    def __enter__(self):\n        pass\n\n    def __exit__(self, type, value, traceback):\n        if value is not None:\n            self.record(value)\n\n    def __call__(self, error, wrap=True):\n        self.record(error, wrap=True)\n\n    def record(self, error, wrap=True):\n        logger.debug('Error in thread %s: %s', threading.current_thread().name, error)\n        if wrap:\n            error = format_error(error)\n\n        try:\n            self.queue.put_nowait(error)\n        except queue.Full:\n            pass\n\n    def check(self, timeout=None):\n        if timeout is None:\n            timeout = 0\n\n        try:\n            error = self.queue.get(timeout=timeout)\n        except queue.Empty:\n            return\n        else:\n            raise error\n\n    def blocking_check(self, timeout=None):\n        # TODO: get rid of this method\n        if timeout is None:\n            while True:\n                self.check(timeout=3600)\n        else:\n            self.check(timeout)\n\n\nfrom twisted.python import failure\nimport traceback\nimport threading\nfrom universe import error\ndef format_error(e):\n    # errback automatically wraps everything in a Twisted Failure\n    if isinstance(e, failure.Failure):\n        e = e.value\n\n    if isinstance(e, str):\n        err_string = e\n    elif six.PY2:\n        err_string = traceback.format_exc(e).rstrip()\n    else:\n        err_string = ''.join(traceback.format_exception(type(e), e, e.__traceback__)).rstrip()\n\n    if err_string == 'None':\n        # Reasonable heuristic for exceptions that were created by hand\n        last = traceback.format_stack()[-2]\n        err_string = '{}\\n  {}'.format(e, last)\n    # Quick and dirty hack for now.\n    err_string = err_string.replace('Connection to the other side was lost in a non-clean fashion', 'Connection to the other side was lost in a non-clean fashion (HINT: this generally actually means we got a connection refused error. Check that the remote is actually running.)')\n    return error.Error(err_string)\n\ndef queue_get(local_queue):\n    while True:\n        try:\n            result = local_queue.get(timeout=1000)\n        except queue.Empty:\n            pass\n        else:\n            return result\n\ndef blockingCallFromThread(f, *a, **kw):\n    local_queue = queue.Queue()\n    def _callFromThread():\n        result = defer.maybeDeferred(f, *a, **kw)\n        result.addBoth(local_queue.put)\n    reactor.callFromThread(_callFromThread)\n    result = queue_get(local_queue)\n    if isinstance(result, failure.Failure):\n        if result.frames:\n            e = error.Error(str(result))\n        else:\n            e = result.value\n        raise e\n    return result\n\nfrom gym import spaces\ndef repeat_space(space, n):\n    return spaces.Tuple([space] * n)\n\nimport base64\nimport uuid\ndef random_alphanumeric(length=14):\n    buf = []\n    while len(buf) < length:\n        entropy = base64.encodestring(uuid.uuid4().bytes).decode('ascii')\n        bytes = [c for c in entropy if c.isalnum()]\n        buf += bytes\n    return ''.join(buf)[:length]\n\n\ndef best_effort(function, *args, **kwargs):\n    try:\n        return function(*args, **kwargs)\n    except:\n        if six.PY2:\n            logging.error('Error in %s:', function.__name__)\n            traceback.print_exc()\n        else:\n            logging.error('Error in %s:', function.__name__)\n            logger.error(traceback.format_exc())\n        return None\n\nimport base64\ndef basic_auth_encode(username, password=''):\n    fmt = '{}:{}'.format(username, password)\n    return 'Basic ' + base64.encodestring(fmt.encode('utf-8')).rstrip().decode('utf-8')\n\ndef basic_auth_decode(header):\n    if header.startswith('Basic '):\n        header = header[len('Basic '):]\n        decoded = base64.decodestring(header.encode('utf-8')).decode('utf-8')\n        username, password = decoded.split(':')\n        return username, password\n    else:\n        return None\n\nimport os\ndef default_password():\n    if os.path.exists('/usr/local/openai/privileged_state/password'):\n        with open('/usr/local/openai/privileged_state/password') as f:\n            return f.read().strip()\n    return 'openai'\n\nimport logging\nimport time\nlogger = logging.getLogger(__name__)\nclass PeriodicLog(object):\n    def log(self, obj, name, msg, *args, **kwargs):\n        try:\n            info = obj._periodic_log_info\n        except AttributeError:\n            info = obj._periodic_log_info = {}\n\n        # Would be better to use a frequency=... arg after kwargs, but\n        # that isn't py2 compatible.\n        frequency = kwargs.pop('frequency', 1)\n        delay = kwargs.pop('delay', 0)\n        last_log = info.setdefault(name, time.time()-frequency+delay)\n        if time.time() - last_log < frequency:\n            return\n        info[name] = time.time()\n        logger.info('[{}] {}'.format(name, msg), *args)\n\n    def log_debug(self, obj, name, msg, *args, **kwargs):\n        try:\n            info = obj._periodic_log_debug\n        except AttributeError:\n            info = obj._periodic_log_debug = {}\n\n        frequency = kwargs.pop('frequency', 1)\n        delay = kwargs.pop('delay', 0)\n        last_log = info.setdefault(name, time.time()-frequency+delay)\n        if time.time() - last_log < frequency:\n            return\n        info[name] = time.time()\n        logger.debug('[{}] {}'.format(name, msg), *args)\n\n_periodic = PeriodicLog()\nperiodic_log = _periodic.log\nperiodic_log_debug = _periodic.log_debug\n\nimport threading\ndef thread_name():\n    return threading.current_thread().name\n\ndef exit_on_signal():\n    \"\"\"\n    Install a signal handler for HUP, INT, and TERM to call exit, allowing clean shutdown.\n    When running a universe environment, it's important to shut down the container when the\n    agent dies so you should either call this or otherwise arrange to exit on signals.\n    \"\"\"\n    def shutdown(signal, frame):\n        logger.warn('Received signal %s: exiting', signal)\n        sys.exit(128+signal)\n    signal.signal(signal.SIGHUP, shutdown)\n    signal.signal(signal.SIGINT, shutdown)\n    signal.signal(signal.SIGTERM, shutdown)\n"
  },
  {
    "path": "universe/utils/display.py",
    "content": "# -*- coding: utf-8 -*-\nimport logging\n\nimport six\nimport numpy as np\n\nlogger = logging.getLogger(__name__)\n\n# We log these with logger, which in py2 chokes on unicode\ndef fmt_plusminus(mean, dev):\n    if six.PY3:\n        return mean + '±' + dev\n    else:\n        # Logging unicode in py2 is asking for trouble\n        return mean + '+-' + dev\n\ndef compute_timestamps_pair_max(time_m_2, flat=True):\n    if flat:\n        # Ignore empty inputs, which happens when environments are resetting.\n        time_m_2 = [[x for x in time_m_2 if len(x)]]\n\n    if len(time_m_2) == 0:\n        return None, None\n\n    # We concatenate the (min, max) lags from a variety of runs. Those\n    # runs may have different lengths.\n    time_m_2 = [np.array(m) for m in time_m_2]\n\n    timestamp_m = []\n    data_m = []\n    for m in time_m_2:\n        if len(m) > 0:\n            timestamp, data = compute_timestamps_sigma(m[:, 1])\n            timestamp_m.append(timestamp)\n            data_m.append(data)\n        else:\n            timestamp_m.append(None)\n            data_m.append({})\n    return timestamp_m, data_m\n\ndef display_timestamps_pair_compact(time_m_2):\n    \"\"\"Takes a list of the following form: [(a1, b1), (a2, b2), ...] and\n    returns a string a_mean-b_mean, flooring out at 0.\n    \"\"\"\n    if len(time_m_2) == 0:\n        return '(empty)'\n\n    time_m_2 = np.array(time_m_2)\n\n    low = time_m_2[:, 0].mean()\n    high = time_m_2[:, 1].mean()\n\n    low = max(low, 0)\n\n    # Not sure if this'll always be true, and not worth crashing over\n    if high < 0:\n        logger.warn('Harmless warning: upper-bound on clock skew is negative: (%s, %s). Please let Greg know about this.', low, high)\n\n    return '{}-{}'.format(display_timestamp(low), display_timestamp(high))\n\ndef display_timestamps_pair(time_m_2):\n    \"\"\"Takes a list of the following form: [(a1, b1), (a2, b2), ...] and\n    returns a string (a_mean+/-a_error, b_mean+/-b_error).\n    \"\"\"\n    if len(time_m_2) == 0:\n        return '(empty)'\n\n    time_m_2 = np.array(time_m_2)\n    return '({}, {})'.format(\n        display_timestamps(time_m_2[:, 0]),\n        display_timestamps(time_m_2[:, 1]),\n    )\n\ndef compute_timestamps_sigma_n(time_m):\n    timestamp_m = []\n    data_m = []\n\n    for t in time_m:\n        timestamp, data = compute_timestamps(t)\n        timestamp_m.append(timestamp)\n        data_m.append(data)\n\n    return timestamp_m, data_m\n\ndef compute_timestamps_sigma(time_m):\n    if len(time_m) == 0:\n        return None, {}\n\n    mean = np.mean(time_m)\n    std = standard_error(time_m)\n    scale, units = pick_time_units(mean)\n    return fmt_plusminus('{:.2f}{}'.format(mean * scale, units), '{:.2f}{}'.format(std * scale, units)), {'mean': mean}\n\ndef display_timestamps(time_m):\n    res, _ = compute_timestamps(time_m)\n    if res is None:\n        return '(empty)'\n    else:\n        return res\n\ndef compute_timestamps(time_m):\n    if len(time_m) == 0:\n        return None, {}\n\n    mean = np.mean(time_m)\n    std = standard_error(time_m)\n    return fmt_plusminus(display_timestamp(mean), display_timestamp(std)), {'mean': mean}\n\ndef display_timestamps_n(time_m):\n    # concatenate all the n's timesteps together, then display_timestamps on it\n    return display_timestamps(np.concatenate(time_m))\n\ndef standard_error(ary, axis=0):\n    if len(ary) > 1:\n        return np.std(ary, axis=axis) / np.sqrt(len(ary) - 1)\n    else:\n        return np.std(ary, axis=axis)\n\ndef display_timestamp(time):\n    assert not isinstance(time, np.ndarray), 'Invalid scalar: {}'.format(time)\n    scale, units = pick_time_units(time)\n    return '{:.2f}{}'.format(time * scale, units)\n\ndef pick_time_units(time):\n    assert not isinstance(time, np.ndarray), 'Invalid scalar: {}'.format(time)\n    if abs(time) < 1:\n        return 1000, 'ms'\n    else:\n        return 1, 's'\n"
  },
  {
    "path": "universe/vectorized/__init__.py",
    "content": "from universe.vectorized.core import Env, Wrapper, ObservationWrapper, ActionWrapper, RewardWrapper\nfrom universe.vectorized.multiprocessing_env import MultiprocessingEnv\nfrom universe.vectorized.vectorize_filter import Filter, VectorizeFilter\n"
  },
  {
    "path": "universe/vectorized/core.py",
    "content": "import gym\nfrom gym import spaces\nfrom universe import error\n\nclass Env(gym.Env):\n    \"\"\"Base class capable of handling vectorized environments.\n    \"\"\"\n    metadata = {\n        # This key indicates whether an env is vectorized (or, in the case of\n        # Wrappers where autovectorize=True, whether they should automatically\n        # be wrapped by a Vectorize wrapper.)\n        'runtime.vectorized': True,\n    }\n\n    # Number of remotes. User should set this.\n    n = None\n\n\nclass Wrapper(Env, gym.Wrapper):\n    \"\"\"Use this instead of gym.Wrapper iff you're wrapping a vectorized env,\n    (or a vanilla env you wish to be vectorized).\n    \"\"\"\n    # If True and this is instantiated with a non-vectorized environment,\n    # automatically wrap it with the Vectorize wrapper.\n    autovectorize = True\n\n    def __init__(self, env):\n        super(Wrapper, self).__init__(env)\n        if not env.metadata.get('runtime.vectorized'):\n            if self.autovectorize:\n                # Circular dependency :(\n                from universe import wrappers\n                env = wrappers.Vectorize(env)\n            else:\n                raise error.Error('This wrapper can only wrap vectorized envs (i.e. where env.metadata[\"runtime.vectorized\"] = True), not {}. Set \"self.autovectorize = True\" to automatically add a Vectorize wrapper.'.format(env))\n\n        self.env = env\n\n    @property\n    def n(self):\n        return self.env.n\n\n    def configure(self, **kwargs):\n        self.env.configure(**kwargs)\n\nclass ObservationWrapper(Wrapper, gym.ObservationWrapper):\n    pass\n\nclass RewardWrapper(Wrapper, gym.RewardWrapper):\n    pass\n\nclass ActionWrapper(Wrapper, gym.ActionWrapper):\n    pass\n"
  },
  {
    "path": "universe/vectorized/multiprocessing_env.py",
    "content": "import logging\nimport multiprocessing\nimport numpy as np\nimport traceback\n\nimport gym\nfrom gym import spaces\nfrom universe.vectorized import core\n\nlogger = logging.getLogger(__name__)\nlogger.setLevel(logging.INFO)\n\nclass Error(Exception):\n    pass\n\ndef display_name(exception):\n    prefix = ''\n    # AttributeError has no __module__; RuntimeError has module of\n    # exceptions\n    if hasattr(exception, '__module__') and exception.__module__ != 'exceptions':\n        prefix = exception.__module__ + '.'\n    return prefix + type(exception).__name__\n\ndef render_dict(error):\n    return {\n        'type': display_name(error),\n        'message': error.message,\n        'traceback': traceback.format_exc(error)\n    }\n\nclass Worker(object):\n    def __init__(self, env_m, worker_idx):\n        # These are instantiated in the *parent* process\n        # currently. Probably will want to change this. The parent\n        # does need to obtain the relevant Spaces at some stage, but\n        # that's doable.\n        self.worker_idx = worker_idx\n        self.env_m = env_m\n        self.m = len(env_m)\n        self.parent_conn, self.child_conn = multiprocessing.Pipe()\n        self.joiner = multiprocessing.Process(target=self.run)\n        self._clear_state()\n\n        self.start()\n\n        # Parent only!\n        self.child_conn.close()\n\n    def _clear_state(self):\n        self.mask = [True] * self.m\n\n    # Control methods\n\n    def start(self):\n        self.joiner.start()\n\n    def _parent_recv(self):\n        rendered, res = self.parent_conn.recv()\n        if rendered is not None:\n            raise Error('[Worker {}] Error: {} ({})\\n\\n{}'.format(self.worker_idx, rendered['message'], rendered['type'], rendered['traceback']))\n        return res\n\n    def _child_send(self, msg):\n        self.child_conn.send((None, msg))\n\n    def _parent_send(self, msg):\n        try:\n            self.parent_conn.send(msg)\n        except IOError: # the worker is now dead\n            try:\n                res = self._parent_recv()\n            except EOFError:\n                raise Error('[Worker {}] Child died unexpectedly'.format(self.worker_idx))\n            else:\n                raise Error('[Worker {}] Child returned unexpected result: {}'.format(self.worker_idx, res))\n\n    def close_start(self):\n        self._parent_send(('close', None))\n\n    def close_finish(self):\n        self.joiner.join()\n\n    def reset_start(self):\n        self._parent_send(('reset', None))\n\n    def reset_finish(self):\n        return self._parent_recv()\n\n    def step_start(self, action_m):\n        \"\"\"action_m: the batch of actions for this worker\"\"\"\n        self._parent_send(('step', action_m))\n\n    def step_finish(self):\n        return self._parent_recv()\n\n    def mask_start(self, i):\n        self._parent_send(('mask', i))\n\n    def seed_start(self, seed_m):\n        self._parent_send(('seed', seed_m))\n\n    def render_start(self, mode, close):\n        self._parent_send(('render', (mode, close)))\n\n    def render_finish(self):\n        return self._parent_recv()\n\n    def run(self):\n        try:\n            self.do_run()\n        except Exception as e:\n            rendered = render_dict(e)\n            self.child_conn.send((rendered, None))\n            return\n\n    def do_run(self):\n        # Child only!\n        self.parent_conn.close()\n\n        while True:\n            method, body = self.child_conn.recv()\n            logger.debug('[%d] Received: method=%s body=%s', self.worker_idx, method, body)\n            if method == 'close':\n                logger.info('Closing envs')\n                # TODO: close envs?\n                return\n            elif method == 'reset':\n                self._clear_state()\n                observation_m = [env.reset() for env in self.env_m]\n                self._child_send(observation_m)\n            elif method == 'step':\n                action_m = body\n                observation_m, reward_m, done_m, info = self.step_m(action_m)\n                self._child_send((observation_m, reward_m, done_m, info))\n            elif method == 'mask':\n                i = body\n                assert 0 <= i < self.m, 'Bad value for mask: {} (should be >= 0 and < {})'.format(i, self.m)\n\n                self.mask[i] = False\n                logger.debug('[%d] Applying mask: i=%d', self.worker_idx, i)\n            elif method == 'seed':\n                seeds = body\n                [env.seed(seed) for env, seed in zip(self.env_m, seeds)]\n            elif method == 'render':\n                mode, close = body\n                if mode == 'human':\n                    self.env_m[0].render(mode=mode, close=close)\n                    result = [None]\n                else:\n                    result = [env.render(mode=mode, close=close) for env in self.env_m]\n                self._child_send(result)\n            else:\n                raise Error('Bad method: {}'.format(method))\n\n    def step_m(self, action_m):\n        observation_m = []\n        reward_m = []\n        done_m = []\n        info = {'m': []}\n\n        for env, enabled, action in zip(self.env_m, self.mask, action_m):\n            if enabled:\n                observation, reward, done, info_i = env.step(action)\n                if done:\n                    observation = env.reset()\n            else:\n                observation = None\n                reward = 0\n                done = False\n                info_i = {}\n            observation_m.append(observation)\n            reward_m.append(reward)\n            done_m.append(done)\n            info['m'].append(info_i)\n        return observation_m, reward_m, done_m, info\n\n\ndef step_n(worker_n, action_n):\n    accumulated = 0\n    for worker in worker_n:\n        action_m = action_n[accumulated:accumulated+worker.m]\n        worker.step_start(action_m)\n        accumulated += worker.m\n\n    observation_n = []\n    reward_n = []\n    done_n = []\n    info = {'n': []}\n\n    for worker in worker_n:\n        observation_m, reward_m, done_m, info_i = worker.step_finish()\n        observation_n += observation_m\n        reward_n += reward_m\n        done_n += done_m\n        info['n'] += info_i['m']\n    return observation_n, reward_n, done_n, info\n\n\ndef reset_n(worker_n):\n    for worker in worker_n:\n        worker.reset_start()\n\n    observation_n = []\n    for worker in worker_n:\n        observation_n += worker.reset_finish()\n\n    return observation_n\n\n\ndef seed_n(worker_n, seed_n):\n    accumulated = 0\n    for worker in worker_n:\n        action_m = seed_n[accumulated:accumulated+worker.m]\n        worker.seed_start(seed_n)\n        accumulated += worker.m\n\n\ndef mask(worker_n, i):\n    accumulated = 0\n    for k, worker in enumerate(worker_n):\n        if accumulated + worker.m <= i:\n            accumulated += worker.m\n        else:\n            worker.mask_start(i - accumulated)\n            return\n\ndef render_n(worker_n, mode, close):\n    if mode == 'human':\n        # Only render 1 worker\n        worker_n = worker_n[0:]\n\n    for worker in worker_n:\n        worker.render_start(mode, close)\n    res = []\n    for worker in worker_n:\n        res += worker.render_finish()\n    if mode != 'human':\n        return res\n    else:\n        return None\n\ndef close_n(worker_n):\n    if worker_n is None:\n        return\n\n    # TODO: better error handling: workers should die when we go away\n    # anyway. Also technically should wait for these processes if\n    # we're not crashing.\n    for worker in worker_n:\n        try:\n            worker.close_start()\n        except Error:\n            pass\n\n    # for worker in worker_n:\n    #     try:\n    #         worker.close_finish()\n    #     except Error:\n    #         pass\n\nclass MultiprocessingEnv(core.Env):\n    metadata = {\n        'runtime.vectorized': True,\n        'configure.required': True,\n    }\n\n    def __init__(self, env_id):\n        self.worker_n = None\n\n        # Pull the relevant info from a transient env instance\n        self.spec = gym.spec(env_id)\n        env = self.spec.make()\n\n        current_metadata = self.metadata\n        self.metadata = env.metadata.copy()\n        self.metadata.update(current_metadata)\n\n        self.action_space = env.action_space\n        self.observation_space = env.observation_space\n        self.reward_range = env.reward_range\n\n    def configure(self, n=1, pool_size=None, episode_limit=None):\n        self.n = n\n        self.envs = [self.spec.make() for _ in range(self.n)]\n\n        if pool_size is None:\n            pool_size = min(len(self.envs), multiprocessing.cpu_count() - 1)\n            pool_size = max(1, pool_size)\n\n        self.worker_n = []\n        m = int((self.n + pool_size - 1) / pool_size)\n        for i in range(0, self.n, m):\n            envs = self.envs[i:i+m]\n            self.worker_n.append(Worker(envs, i))\n\n        if episode_limit is not None:\n            self._episode_id.episode_limit = episode_limit\n\n    def _seed(self, seed):\n        seed_n(self.worker_n, seed)\n        return [[seed_i] for seed_i in seed]\n\n    def _reset(self):\n        return reset_n(self.worker_n)\n\n    def _step(self, action_n):\n        return step_n(self.worker_n, action_n)\n\n    def _render(self, mode='human', close=False):\n        return render_n(self.worker_n, mode=mode, close=close)\n\n    def mask(self, i):\n        mask(self.worker_n, i)\n\n    def _close(self):\n        close_n(self.worker_n)\n\nif __name__ == '__main__':\n    env_n = make('Pong-v3')\n    env_n.configure()\n    env_n.reset()\n    print(env_n.step([0] * 10))\n"
  },
  {
    "path": "universe/vectorized/tests/test_monitoring.py",
    "content": "import glob\nimport os\n\nimport gym.monitoring\nfrom gym.monitoring.tests import helpers\nfrom universe import wrappers\n\ndef test_multiprocessing_env_monitoring():\n    with helpers.tempdir() as temp:\n        env = wrappers.WrappedMultiprocessingEnv('Pong-v3')\n        env.configure(n=2)\n        env = wrappers.Monitor(env, temp)\n        env.reset()\n        for i in range(2):\n            env.step([0, 0])\n        env.close()\n        manifests = glob.glob(os.path.join(temp, '*.video.*'))\n        assert len(manifests) == 2, 'There are {} manifests: {}'.format(len(manifests), manifests)\n\n        results = gym.monitoring.load_results(temp)\n        assert results['env_info']['env_id'] == 'Pong-v3'\n\ndef test_vnc_monitoring():\n    with helpers.tempdir() as temp:\n        env = gym.make('gym-core.Pong-v3')\n        env.configure(remotes=2)\n        env = wrappers.GymCoreAction(env)\n        env = wrappers.Monitor(env, temp)\n\n        env.reset()\n        for i in range(2):\n            env.step([0, 0])\n        env.close()\n\n        results = gym.monitoring.load_results(temp)\n        assert results['env_info']['env_id'] == 'gym-core.Pong-v3'\n\nif __name__ == '__main__':\n    test_multiprocessing_env_monitoring()\n    test_vnc_monitoring()\n"
  },
  {
    "path": "universe/vectorized/vectorize_filter.py",
    "content": "from universe.vectorized import core\n\nclass Filter(object):\n    def _after_reset(self, observation):\n        return observation\n\n    def _after_step(self, observation, reward, done, info):\n        return observation, reward, done, info\n\nclass VectorizeFilter(core.Wrapper):\n    \"\"\"Vectorizes a Filter written for the non-vectorized case.\"\"\"\n\n    autovectorize = False\n    metadata = {\n        'configure.required': True\n    }\n\n    def __init__(self, env, filter_factory, *args, **kwargs):\n        super(VectorizeFilter, self).__init__(env)\n        self.filter_factory = filter_factory\n        self.filter_n = None\n        self._args = args\n        self._kwargs = kwargs\n\n    def _reset(self):\n        if self.filter_n is None:\n            self.filter_n = [self.filter_factory(*self._args, **self._kwargs) for _ in range(self.n)]\n        observation_n = self.env.reset()\n        observation_n = [filter._after_reset(observation) for filter, observation in zip(self.filter_n, observation_n)]\n        return observation_n\n\n    def _step(self, action_n):\n        o_n, r_n, d_n, i = self.env.step(action_n)\n\n        observation_n = []\n        reward_n = []\n        done_n = []\n        info = i.copy()\n        info['n'] = []\n        for filter, observation, reward, done, info_i in zip(self.filter_n, o_n, r_n, d_n, i['n']):\n            observation, reward, done, info_i = filter._after_step(observation, reward, done, info_i)\n            observation_n.append(observation)\n            reward_n.append(reward)\n            done_n.append(done)\n            info['n'].append(info_i)\n        return observation_n, reward_n, done_n, info\n\n    def __str__(self):\n        return '<{}[{}]{}>'.format(type(self).__name__, self.filter_factory, self.env)\n"
  },
  {
    "path": "universe/vncdriver/README.md",
    "content": "# Python VNC driver implementation\n\nThis Python VNC driver is using an older API, and needs a small amount\nof work to once again become a good backend. We haven't bothered with\nthis since the Go driver is much faster. We would take a pull request\nto fix it though!\n"
  },
  {
    "path": "universe/vncdriver/__init__.py",
    "content": "import logging\n\nfrom universe.vncdriver.vnc_session import VNCSession\nfrom universe.vncdriver.vnc_client import client_factory\nfrom universe.vncdriver.screen import NumpyScreen, PygletScreen\n\nlogger = logging.getLogger(__name__)\nlogger.setLevel(logging.INFO)\n"
  },
  {
    "path": "universe/vncdriver/auth.py",
    "content": "import six\nimport uuid\n\nfrom universe import utils\nfrom universe.vncdriver.vendor import pydes\n\nclass RFBDes(pydes.des):\n    def setKey(self, key):\n        key = key.encode('ascii')\n\n        newkey = []\n        for ki in range(len(key)):\n            if six.PY2:\n                bsrc = ord(key[ki])\n            else:\n                bsrc = key[ki]\n\n            # Reverse the bits\n            btgt = 0\n            for i in range(8):\n                if bsrc & (1 << i):\n                    btgt = btgt | (1 << 7-i)\n\n            if six.PY2:\n                newkey.append(chr(btgt))\n            else:\n                newkey.append(btgt)\n\n        super(RFBDes, self).setKey(newkey)\n\ndef challenge():\n    length = 16\n    buf = b''\n    while len(buf) < length:\n        entropy = uuid.uuid4().bytes\n        buf += entropy\n    return buf[:length]\n\ndef challenge_response(challenge, password=None):\n    if password is None:\n        password = utils.default_password()\n    password += ((8 - len(password)) % 8) * '\\0'  # pad to multiple of 8 bytes\n    des = RFBDes(password)\n    return des.encrypt(challenge)\n"
  },
  {
    "path": "universe/vncdriver/constants.py",
    "content": "# Encodings\nRAW_ENCODING =                  0\nCOPY_RECTANGLE_ENCODING =       1\nRRE_ENCODING =                  2\nCORRE_ENCODING =                4\nHEXTILE_ENCODING =              5\nZLIB_ENCODING =                 6\nTIGHT_ENCODING =                7\nZLIBHEX_ENCODING =              8\nZRLE_ENCODING =                 16\n#0xffffff00 to 0xffffffff tight options\nPSEUDO_CURSOR_ENCODING =        -239\n\n# Keycodes\nKEY_BackSpace = 0xff08\nKEY_Tab =       0xff09\nKEY_Return =    0xff0d\nKEY_Escape =    0xff1b\nKEY_Insert =    0xff63\nKEY_Delete =    0xffff\nKEY_Home =      0xff50\nKEY_End =       0xff57\nKEY_PageUp =    0xff55\nKEY_PageDown =  0xff56\nKEY_Left =      0xff51\nKEY_Up =        0xff52\nKEY_Right =     0xff53\nKEY_Down =      0xff54\nKEY_F1 =        0xffbe\nKEY_F2 =        0xffbf\nKEY_F3 =        0xffc0\nKEY_F4 =        0xffc1\nKEY_F5 =        0xffc2\nKEY_F6 =        0xffc3\nKEY_F7 =        0xffc4\nKEY_F8 =        0xffc5\nKEY_F9 =        0xffc6\nKEY_F10 =       0xffc7\nKEY_F11 =       0xffc8\nKEY_F12 =       0xffc9\nKEY_F13 =       0xFFCA\nKEY_F14 =       0xFFCB\nKEY_F15 =       0xFFCC\nKEY_F16 =       0xFFCD\nKEY_F17 =       0xFFCE\nKEY_F18 =       0xFFCF\nKEY_F19 =       0xFFD0\nKEY_F20 =       0xFFD1\nKEY_ShiftLeft = 0xffe1\nKEY_ShiftRight = 0xffe2\nKEY_ControlLeft = 0xffe3\nKEY_ControlRight = 0xffe4\nKEY_MetaLeft =  0xffe7\nKEY_MetaRight = 0xffe8\nKEY_AltLeft =   0xffe9\nKEY_AltRight =  0xffea\n\nKEY_Scroll_Lock = 0xFF14\nKEY_Sys_Req =   0xFF15\nKEY_Num_Lock =  0xFF7F\nKEY_Caps_Lock = 0xFFE5\nKEY_Pause =     0xFF13\nKEY_Super_L =   0xFFEB\nKEY_Super_R =   0xFFEC\nKEY_Hyper_L =   0xFFED\nKEY_Hyper_R =   0xFFEE\n\nKEY_KP_0 =      0xFFB0\nKEY_KP_1 =      0xFFB1\nKEY_KP_2 =      0xFFB2\nKEY_KP_3 =      0xFFB3\nKEY_KP_4 =      0xFFB4\nKEY_KP_5 =      0xFFB5\nKEY_KP_6 =      0xFFB6\nKEY_KP_7 =      0xFFB7\nKEY_KP_8 =      0xFFB8\nKEY_KP_9 =      0xFFB9\nKEY_KP_Enter =  0xFF8D\n\nKEY_ForwardSlash = 0x002F\nKEY_BackSlash = 0x005C\nKEY_SpaceBar=   0x0020\n\n# TODO: build this programmatically?\nKEYMAP = {\n    'bsp': KEY_BackSpace,\n    'tab': KEY_Tab,\n    'return': KEY_Return,\n    'enter': KEY_Return,\n    'esc': KEY_Escape,\n    'ins': KEY_Insert,\n    'delete': KEY_Delete,\n    'del': KEY_Delete,\n    'home': KEY_Home,\n    'end': KEY_End,\n    'pgup': KEY_PageUp,\n    'pgdn': KEY_PageDown,\n    'ArrowLeft': KEY_Left,\n    'left': KEY_Left,\n    'ArrowUp': KEY_Up,\n    'up': KEY_Up,\n    'ArrowRight': KEY_Right,\n    'right': KEY_Right,\n    'ArrowDown': KEY_Down,\n    'down': KEY_Down,\n\n    'slash': KEY_BackSlash,\n    'bslash': KEY_BackSlash,\n    'fslash': KEY_ForwardSlash,\n    'spacebar': KEY_SpaceBar,\n    'space': KEY_SpaceBar,\n    'sb': KEY_SpaceBar,\n\n    'f1': KEY_F1,\n    'f2': KEY_F2,\n    'f3': KEY_F3,\n    'f4': KEY_F4,\n    'f5': KEY_F5,\n    'f6': KEY_F6,\n    'f7': KEY_F7,\n    'f8': KEY_F8,\n    'f9': KEY_F9,\n    'f10': KEY_F10,\n    'f11': KEY_F11,\n    'f12': KEY_F12,\n    'f13': KEY_F13,\n    'f14': KEY_F14,\n    'f15': KEY_F15,\n    'f16': KEY_F16,\n    'f17': KEY_F17,\n    'f18': KEY_F18,\n    'f19': KEY_F19,\n    'f20': KEY_F20,\n\n    'lshift': KEY_ShiftLeft,\n    'shift': KEY_ShiftLeft,\n    'rshift': KEY_ShiftRight,\n    'lctrl': KEY_ControlLeft,\n    'ctrl': KEY_ControlLeft,\n    'rctrl': KEY_ControlRight,\n    'lmeta': KEY_MetaLeft,\n    'meta': KEY_MetaLeft,\n    'rmeta': KEY_MetaRight,\n    'lalt': KEY_AltLeft,\n    'alt': KEY_AltLeft,\n    'ralt': KEY_AltRight,\n    'scrlk': KEY_Scroll_Lock,\n    'sysrq': KEY_Sys_Req,\n    'numlk': KEY_Num_Lock,\n    'caplk': KEY_Caps_Lock,\n    'pause': KEY_Pause,\n    'lsuper': KEY_Super_L,\n    'super': KEY_Super_L,\n    'rsuper': KEY_Super_R,\n    'lhyper': KEY_Hyper_L,\n    'hyper': KEY_Hyper_L,\n    'rhyper': KEY_Hyper_R,\n\n    'kp0': KEY_KP_0,\n    'kp1': KEY_KP_1,\n    'kp2': KEY_KP_2,\n    'kp3': KEY_KP_3,\n    'kp4': KEY_KP_4,\n    'kp5': KEY_KP_5,\n    'kp6': KEY_KP_6,\n    'kp7': KEY_KP_7,\n    'kp8': KEY_KP_8,\n    'kp9': KEY_KP_9,\n    'kpenter': KEY_KP_Enter,\n}\n"
  },
  {
    "path": "universe/vncdriver/dual_proxy_server.py",
    "content": "# a proxy server that handles both reward channel and vnc.\nfrom twisted.python import log\nfrom autobahn.twisted import websocket\nimport logging\nimport os\nimport time\nimport pexpect\nimport sys\nimport threading\n\nfrom universe.vncdriver.vnc_proxy_server import VNCProxyServer\nfrom universe.rewarder.reward_proxy_server import RewardProxyServer\nfrom universe import utils\n\nlogger = logging.getLogger(__name__)\n\n\nclass DualProxyServer(VNCProxyServer):\n    def __init__(self, action_queue=None, error_buffer=None, enable_logging=True):\n        self._log_info('DualProxyServer inited')\n        self.reward_proxy = None\n\n        super(DualProxyServer, self).__init__(action_queue, error_buffer, enable_logging)\n\n    def _log_info(self, msg, *args, **kwargs):\n        logger.info('[dual_proxy] ' + msg, *args, **kwargs)\n\n    def recv_ClientInit(self, block):\n        # start reward proxy.\n        self._log_info('Starting reward proxy server')\n        self.reward_proxy = pexpect.spawnu(self.factory.reward_proxy_bin,\n                                           logfile=sys.stdout,\n                                           timeout=None)\n\n        # wait on reward proxy to be up.\n        self._log_info('Waiting for reward proxy server')\n        self.reward_proxy.expect('\\[RewardProxyServer\\]')\n        self.reward_proxy_thread = threading.Thread(target=lambda: self.reward_proxy.expect(pexpect.EOF))\n        self.reward_proxy_thread.start()\n\n        self._log_info('Reward proxy server is up %s', self.reward_proxy.before)\n\n        super(DualProxyServer, self).recv_ClientInit(block)\n\n        self.logfile_dir = self.log_manager.logfile_dir\n\n    def close(self):\n        # end connections.\n        super(DualProxyServer, self).close()\n\n        # wait for rewarder to close.\n        if self.reward_proxy:\n            self.reward_proxy.terminate()\n\n        # upload to s3.\n        # probably hacky right now.\n        logger.info('log manager = %s', self.log_manager)\n        if self.log_manager:\n            os.system('/app/universe/bin/upload_directory.sh demonstrator_%(recorder_id)s %(directory)s %(bucket)s' %\n                    dict(recorder_id=self.factory.recorder_id, directory=self.logfile_dir,\n                        bucket=self.factory.bucket)\n                    )\n\n"
  },
  {
    "path": "universe/vncdriver/error.py",
    "content": "class Error(Exception):\n    pass\n"
  },
  {
    "path": "universe/vncdriver/fbs_reader.py",
    "content": "import json\nimport os\nimport struct\n\nfrom universe import error\n\nclass InvalidFBSFileError(error.Error):\n    pass\n\nclass FBSReader(object):\n    def __init__(self, path):\n        self.file = open(path, 'rb')\n        version = self.file.read(12)\n        if version != b'FBS 001.002\\n':\n            raise InvalidFBSFileError('Unrecognized FBS version: {}'.format(version))\n\n        header = self.file.readline()\n        pos = self.file.tell()\n        self.file.seek(pos, os.SEEK_SET)\n\n        header = json.loads(header.decode('utf-8'))\n        self.start = header['start']\n\n    def __iter__(self):\n        return self\n\n    def read_safe(self, size=None):\n        \"\"\"\n        We currently close our fbs files by killing them, so sometimes they end\n        up with bad data at the end. Close our reader if we expect `size` bytes\n        and get fewer.\n\n        This is a hack and should be removed when we cleanly close our\n        connections in fbs_writer.\n\n        https://github.com/openai/universe-envs/issues/41\n        \"\"\"\n        bytes = self.file.read(size)\n        if len(bytes) != size:\n            # We unexpectedly got to the end of the file\n            self.close()\n            raise StopIteration\n        return bytes\n\n    def next(self):\n        return self.__next__()\n\n    def __next__(self):\n        length_str = self.read_safe(4)\n        if length_str == '':\n            # Indicates a file with no trailer\n            self.close()\n            raise StopIteration\n        (length,) = struct.unpack('!I', length_str)\n\n        if length == 0:\n            # Reached the end\n            self.close()\n            raise StopIteration()\n\n        data = self.read_safe(length)\n        timestamp_str = self.read_safe(4)\n        (timestamp,) = struct.unpack('!I', timestamp_str)\n\n        return data, self.start + timestamp/1000.\n\n    def close(self):\n        self.file.close()\n"
  },
  {
    "path": "universe/vncdriver/fbs_writer.py",
    "content": "import json\nimport struct\nimport time\n\nfrom gym.utils import atomic_write, closer\n\nfbs_closer = closer.Closer()\n\nclass FBSWriter(object):\n    def __init__(self, path):\n        self._closed = False\n\n        self.start = None\n        self.stop = None\n\n        self._id = fbs_closer.register(self)\n\n        self.file = open(path, 'wb')\n        # custom format: exactly the same as FBS 001.000 except:\n        #\n        # FBS 001.002\n        # {line-of-json}\n        # [length-byte, data, timestamp]...\n        # \\0\\0\\0\\0 {line-of-json}\n        self.file.write(b'FBS 001.002\\n')\n\n    def write(self, data):\n        # Format:\n        #\n        # length\n        # data\n        # timestamp (4 bytes)\n\n        if not data:\n            return\n\n        if self.start is not None:\n            delta = int(1000 * (time.time() - self.start))\n        else:\n            delta = 0\n            self.start = time.time()\n\n            # Write metadata header\n            self.file.write(json.dumps({'start': self.start}).encode('utf-8'))\n            self.file.write(b'\\n')\n\n        length = struct.pack('!I', len(data))\n        self.file.write(length)\n        self.file.write(data)\n\n        delta = struct.pack('!I', delta)\n        self.file.write(delta)\n\n    def _write_metadata(self):\n        # Write metadata trailer\n        null = struct.pack('!I', 0)\n        self.file.write(null)\n        self.file.write(json.dumps({'stop': self.stop}).encode('utf-8'))\n        self.file.write(b'\\n')\n\n    def close(self):\n        if self._closed:\n            return\n        self._closed = True\n\n        fbs_closer.unregister(self._id)\n        self.stop = time.time()\n        self._write_metadata()\n        self.file.close()\n\n    def __del__(self):\n        self.close()\n"
  },
  {
    "path": "universe/vncdriver/libvnc_session.py",
    "content": "import logging\nimport os\n\nfrom twisted.internet import defer, endpoints\n\nfrom universe import error, utils\nfrom universe.twisty import reactor\nfrom universe.vncdriver import screen, vnc_client\n\nPYGAME_INSTALLED = None\ndef load_pygame():\n    global PYGAME_INSTALLED, pygame\n    if PYGAME_INSTALLED is not None:\n        return\n\n    try:\n        import pygame\n        PYGAME_INSTALLED = True\n    except ImportError:\n        PYGAME_INSTALLED = False\n\nlogger = logging.getLogger(__name__)\n\n\nclass LibVNCSession(object):\n    def __init__(self, remotes, error_buffer, encoding=None, compress_level=None, fine_quality_level=None, subsample_level=None):\n        \"\"\"compress_level: 0-9 [9 is highest compression]\n        fine_quality_level: 0-100 [100 is best quality]\n        subsample_level: 0-3 [0 is best quality]\n\n        Lots of references for this, but\n        https://github.com/TurboVNC/turbovnc/blob/master/doc/performance.txt\n        is decent.\n        \"\"\"\n\n        load_pygame()\n        import libvncdriver\n\n        if encoding is None:\n            encoding = os.environ.get('LIBVNC_ENCODING', 'tight')\n        if compress_level is None:\n            compress_level = int(os.environ.get('LIBVNC_COMPRESS_LEVEL', '0'))\n        if fine_quality_level is None:\n            fine_quality_level = int(os.environ.get('LIBVNC_FINE_QUALITY_LEVEL', '100'))\n        if subsample_level is None:\n            subsample_level = int(os.environ.get('LIBVNC_SUBSAMPLE_LEVEL', '0'))\n\n        if not hasattr(libvncdriver, 'VNCSession'):\n            raise error.Error('''\n *=================================================*\n|| libvncdriver is not installed                   ||\n|| Try installing with \"pip install libvncdriver\"  ||\n|| or use the go or python driver by setting       ||\n|| UNIVERSE_VNCDRIVER=go                                ||\n|| UNIVERSE_VNCDRIVER=py                                ||\n *=================================================*''')\n        logger.info(\"Using libvncdriver's %s encoding\" % encoding)\n        self.driver = libvncdriver.VNCSession(\n            remotes=remotes,\n            error_buffer=error_buffer,\n            encoding=encoding,\n            compress_level=compress_level,\n            fine_quality_level=fine_quality_level,\n            subsample_level=subsample_level,\n        )\n        self.screen = None\n        self.render_called_once = False\n        if PYGAME_INSTALLED:\n            pygame.init()\n\n    def flip(self):\n        return self._guard(self.driver.flip)\n\n    def step(self, action):\n        return self.driver.step(action)\n\n    def render(self):\n        self._guard(self._render)\n\n    def _guard(self, fn):\n        try:\n            return fn()\n        except (KeyboardInterrupt, SystemExit):\n            self.close()\n\n    def _render(self):\n        self.before_render()\n        if not PYGAME_INSTALLED:\n            return\n        # For some reason pygame wants X and Y swapped\n        aray, n = self.driver.flip()\n        if self.screen is None:\n            self.screen = pygame.display.set_mode(aray[0].shape[:2][::-1])\n        surf = pygame.surfarray.make_surface(aray[0].swapaxes(0, 1))\n        rect = surf.get_rect()\n        self.screen.blit(surf, rect)\n        pygame.display.flip()\n\n        for event in pygame.event.get():\n            if event.type == pygame.QUIT:\n                self.close()\n\n    def before_render(self):\n        if not self.render_called_once:\n            self.render_called_once = True\n            if not PYGAME_INSTALLED:\n                logger.warn('''\n *================================================================*\n||                                                                ||\n|| Rendering disabled when using libvnc without pygame installed. ||\n|| Consider viewing over VNC or running \"pip install pygame\".     ||\n||                                                                ||\n *================================================================*''')\n\n\n    def close(self):\n        if PYGAME_INSTALLED:\n            pygame.quit()\n        self.driver.close()\n"
  },
  {
    "path": "universe/vncdriver/screen/__init__.py",
    "content": "from universe.vncdriver.screen.base import Screen\nfrom universe.vncdriver.screen.numpy_screen import NumpyScreen\nfrom universe.vncdriver.screen.pyglet_screen import PygletScreen\nfrom universe.vncdriver.screen.screen_buffer import ScreenBuffer\n"
  },
  {
    "path": "universe/vncdriver/screen/base.py",
    "content": "import logging\nimport time\n\nlogger = logging.getLogger(__name__)\n\nclass Screen(object):\n    pass\n"
  },
  {
    "path": "universe/vncdriver/screen/numpy_screen.py",
    "content": "import logging\nimport numpy as np\nfrom universe import pyprofile\nimport threading\nimport time\n\nfrom universe import error\nfrom universe.twisty import reactor\nfrom universe.vncdriver import server_messages\nfrom universe.spaces import vnc_event\n\nlogger = logging.getLogger(__name__)\n\nclass NumpyScreen(object):\n    def __init__(self, width, height):\n        self.lock = threading.RLock()\n\n        shape = (height, width, 3)\n        self._screens = (np.zeros(shape, dtype=np.uint8), np.zeros(shape, dtype=np.uint8))\n\n        self.color_cycle = [0, 1, 2]\n        self._width = None\n        self._height = None\n\n        self._defer = []\n\n        self.paint_cursor = False\n        self._cursor = {\n            id(self._screens[0]): {\n                'behind': None,\n                'details': None,\n                'painted': False,\n            },\n            id(self._screens[1]): {\n                'behind': None,\n                'details': None,\n                'painted': False,\n            },\n        }\n\n        self._back_updated = True\n        self._back_cursor_updated = True\n\n        self.cursor_shape = None\n        self.cursor_position = None\n\n        self._has_initial_framebuffer_update = False\n\n    def set_paint_cursor(self, paint_cursor):\n        self.paint_cursor = paint_cursor\n\n    def peek(self):\n        front_screen, _ = self._screens\n        return front_screen\n\n    def flip(self):\n        pyprofile.push('vncdriver.numpy_screen.flip_bitmap')\n        with self.lock:\n            if self._back_updated:\n                updates = self._defer\n\n                # Flip screens\n                front_screen, back_screen = self._screens\n                self._screens = back_screen, front_screen\n\n                # Mark ourselves as pending application of updates\n                self._back_updated = False\n\n                # This can be called asynchronously if desired, but it means\n                # less reliably smooth playback.\n                #\n                # reactor.callFromThread(self.update_back)\n                self.update_back()\n            else:\n                updates = []\n            result = self.peek(), {'vnc_session.framebuffer_updates': updates}\n        pyprofile.pop()\n        return result\n\n    def apply_action(self, action):\n        if isinstance(action, vnc_event.PointerEvent):\n            with self.lock:\n                self.cursor_position = (action.x, action.y)\n\n                # If not self._back_updated, we're not actually up to\n                # date, so any pixels we cached would be wrong. When\n                # back updates, it'll automatically render the cursor.\n                if self._back_updated and self.paint_cursor:\n                    self._unpaint_cursor()\n                    self._paint_cursor()\n\n    def apply(self, framebuffer_update):\n        with self.lock:\n            self._has_initial_framebuffer_update = True\n\n            # Pop any pending updates\n            self._update_back()\n            self._apply(framebuffer_update)\n            self._defer.append(framebuffer_update)\n\n\n    def _apply(self, framebuffer_update):\n        if self.paint_cursor:\n            self._unpaint_cursor()\n        for rect in framebuffer_update.rectangles:\n            if isinstance(rect.encoding,\n                          (server_messages.RAWEncoding, server_messages.ZRLEEncoding, server_messages.ZlibEncoding)):\n                self._update_rectangle(rect.x, rect.y, rect.width, rect.height, rect.encoding.data)\n            elif isinstance(rect.encoding, server_messages.PseudoCursorEncoding):\n                self._update_cursor_shape(rect.x, rect.y, rect.width, rect.height, rect.encoding.image, rect.encoding.mask)\n            else:\n                raise error.Error('Unrecognized encoding: {}'.format(rect.encoding))\n        if self.paint_cursor:\n            self._paint_cursor()\n\n    def update_back(self):\n        with self.lock:\n            self._update_back()\n\n    def _update_back(self):\n        if self._back_updated:\n            return\n        self._back_updated = True\n\n        for framebuffer_update in self._defer:\n            self._apply(framebuffer_update)\n\n        if len(self._defer) == 0 and self.paint_cursor:\n            self._unpaint_cursor()\n            self._paint_cursor()\n\n        self._defer = []\n\n    def _update_rectangle(self, x, y, width, height, data):\n        _, back_screen = self._screens\n        back_screen[y:y+height, x:x+width, self.color_cycle] = data\n\n    def _update_cursor_shape(self, hotx, hoty, width, height, image, mask):\n        # hotx, hoty are the hotspot within the cursor\n        self.cursor_shape = (hotx, hoty, width, height, image, mask)\n\n    def _paint_cursor(self):\n\n        # use our knowledge of the x, y cursor position plus the\n        # cursor shape to paint the cursor\n        if self.cursor_position is None:\n            return\n        elif not self._has_initial_framebuffer_update:\n            return\n        elif self.cursor_shape is None:\n            return\n\n        self._back_cursor_updated = True\n\n        _, back_screen = self._screens\n        cursor = self._cursor[id(back_screen)]\n\n        assert not cursor['painted']\n        cursor['painted'] = True\n\n        hotx, hoty, width, height, image, mask = self.cursor_shape\n        x, y = self.cursor_position\n\n        # Save old data\n        cursor['details'] = (x, y, width, height)\n        cursor['behind'] = back_screen[y:y+height, x:x+width, :].copy()\n\n        # Paint the cursor\n        total_h, total_w, _ = back_screen.shape\n\n        cutoff_h = min(total_h - y, height)\n        cutoff_w = min(total_w - x, width)\n        image = image[:cutoff_h, :cutoff_w]\n        mask = mask[:cutoff_h, :cutoff_w, np.newaxis]\n\n        back_screen[y:y+height, x:x+width, self.color_cycle] = (1 - mask)*back_screen[y:y+height, x:x+width, self.color_cycle] + mask*image\n\n    def _unpaint_cursor(self):\n\n        _, back_screen = self._screens\n        cursor = self._cursor[id(back_screen)]\n\n        if cursor['behind'] is not None:\n            assert cursor['painted']\n            x, y, width, height = cursor['details']\n            back_screen[y:y+height, x:x+width, :] = cursor['behind']\n        cursor['painted'] = False\n\n\n    # def _copy_rectangle(self, screen, src_x, src_y, x, y, width, height):\n    #     update = np.frombuffer(data, dtype=np.uint8)\n    #     update = update.reshape([height, width, 4])\n    #     update = update[:, :, self._color_cycle]  # Ignore X channel\n\n\n    #     screen[y:y+height, x:x+width] = screen[src_y:src_y+height, src_x:src_x+width]\n\n    # def _fill_rectangle(self, screen, x, y, width, height, color):\n    #     update = np.frombuffer(color, dtype=np.uint8)\n    #     update = update[self._color_cycle]\n    #     screen[y:y+height, x:x+width] = update\n\n    # def begin(self, number_of_rectangles):\n    #     self.lock.acquire()\n    #     # This may already have been called via\n    #     # reactor.callFromThread. It's safe to be called multiple times.\n    #     self._update_back()\n\n    # def commit(self):\n    #     self.lock.release()\n\n    # def back_bitmap(self):\n    #     _, back_screen = self._screens\n    #     return back_screen\n\n    # def screen_synced(self):\n    #     # TODO: lock?\n    #     return self._screens is not None\n"
  },
  {
    "path": "universe/vncdriver/screen/pyglet_screen.py",
    "content": "import logging\nimport numpy as np\nimport os\nfrom universe import pyprofile\nimport sys\n\nfrom universe import error\nfrom universe.vncdriver import server_messages\n\nlogger = logging.getLogger(__name__)\n\nclass PygletScreen(object):\n    def __init__(self, bitmap=None):\n        self._window = None\n        self._is_updated = False\n        self._height, self._width, _ = bitmap.shape\n        self._initialize()\n        self.update_rectangle(0, 0, self._width, self._height, bitmap)\n\n    def flip(self):\n        if not self._is_updated:\n            return\n        self._is_updated = False\n\n        self._window.clear()\n        self._window.switch_to()\n        self._window.dispatch_events()\n        self.texture.blit(0, 0)\n        self._window.flip()\n\n    def _initialize(self):\n        if not os.environ.get('DISPLAY') and sys.platform.startswith('linux'):\n            raise error.Error(\"Cannot render with mode='human' with no DISPLAY variable set.\")\n\n        import pyglet\n        self._window = pyglet.window.Window(width=self._width, height=self._height, visible=True)\n        self._window.dispatch_events()\n        self.texture = pyglet.image.Texture.create(width=self._width, height=self._height)\n\n    def update_rectangle(self, x, y, width, height, data):\n        bytes = data.tobytes()\n        pyprofile.incr('vncdriver.pyglet_screen.blit')\n        pyprofile.incr('vncdriver.pyglet_screen.blit.bytes', len(bytes), unit=pyprofile.BYTES)\n        import pyglet\n        image = pyglet.image.ImageData(width, height, 'RGB', bytes, pitch=width * -3)\n        self.texture.blit_into(image, x, self._height-height-y, 0)\n        self._is_updated = True\n\n    def apply(self, framebuffer_update):\n        pyprofile.push('vncdriver.pyglet_screen.apply')\n        for rect in framebuffer_update.rectangles:\n            if isinstance(rect.encoding,\n                          (server_messages.RAWEncoding, server_messages.ZRLEEncoding, server_messages.ZlibEncoding)):\n                self.update_rectangle(rect.x, rect.y, rect.width, rect.height, rect.encoding.data)\n            else:\n                raise error.Error('Unrecognized encoding: {}'.format(rect.encoding))\n        pyprofile.pop()\n\n\n\n    # # TODO: we don't seem to be able to have multiple independent\n    # # windows at once\n    # def update_rectangle(self, x, y, width, height, data):\n    #     self._update_rgbarray(x, y, width, height, update)\n\n\n    # def copy_rectangle(self, src_x, src_y, x, y, width, height):\n    #     assert self._window\n    #     rectangle = self.texture.get_region(src_x, self._height-height-src_y, width, height)\n    #     self.texture.blit_into(rectangle.get_image_data(), x, self._height-height-y, 0)\n\n    # def fill_rectangle(self, x, y, width, height, color):\n    #     import pyglet\n    #     # While this technically works, it's super slow\n    #     update = np.frombuffer(color, dtype=np.uint8)\n    #     r, g, b = update[self._color_cycle]\n    #     image_pattern = pyglet.image.SolidColorImagePattern(color=(r, g, b, 0))\n    #     image = image_pattern.create_image(width, height)\n    #     self.texture.blit_into(image, x, self._height-height-y, 0)\n\n    # def commit(self):\n    #     self._window.clear()\n    #     self._window.switch_to()\n    #     self.texture.blit(0, 0)\n\n    #     self._is_updated = True\n"
  },
  {
    "path": "universe/vncdriver/screen/screen_buffer.py",
    "content": "import logging\nimport time\nimport threading\n\nfrom universe.vncdriver.screen import numpy_screen\n\nlogger = logging.getLogger(__name__)\n\nclass ScreenBuffer(object):\n    def __init__(self):\n        self.lock = threading.Lock()\n        self.uncommitted = []\n        self.updates = []\n\n    def apply_format(self, attrs):\n        self._push({\n            'type': 'apply_format',\n            'attrs': attrs,\n        })\n\n    def update_rectangle(self, x, y, width, height, data):\n        self._push({\n            'type': 'update_rectangle',\n            'x': x,\n            'y': y,\n            'width': width,\n            'height': height,\n            'data': data,\n        })\n\n    def copy_rectangle(self, src_x, src_y, x, y, width, height):\n        self._push({\n            'type': 'copy_rectangle',\n            'src_x': src_x,\n            'src_y': src_y,\n            'x': x,\n            'y': y,\n            'width': width,\n            'height': height,\n        })\n\n    def fill_rectangle(self, x, y, width, height, color):\n        self._push({\n            'type': 'fill_rectangle',\n            'x': x,\n            'y': y,\n            'width': width,\n            'height': height,\n            'color': color,\n        })\n\n    def framebuffer_update_finish(self):\n        with self.lock:\n            self.updates += self.uncommitted\n            self.uncommitted = []\n\n    def _push(self, update):\n        \"\"\"Always call from single thread.\"\"\"\n        self.uncommitted.append(update)\n\n    def pop(self):\n        with self.lock:\n            if self.updates:\n                updates = self.updates\n                self.updates = []\n                return updates\n            else:\n                return None\n\n    def peek(self):\n        with self.lock:\n            if self.updates:\n                return self.updates\n            else:\n                return None\n"
  },
  {
    "path": "universe/vncdriver/server_messages.py",
    "content": "try:\n    # In Py2, use the more efficient cStringIO implementation if it's\n    # available\n    from cStringIO import StringIO as BytesIO\nexcept ImportError:\n    # Fall back to using normal BytesIO, six handles python 2 vs 3 compat\n    from six import BytesIO\n\nimport logging\nimport numpy as np\nfrom universe import pyprofile\nimport struct\n\nlogger = logging.getLogger(__name__)\n\nclass FramebufferUpdate(object):\n    def __init__(self, rectangles):\n        self.rectangles = rectangles\n\nclass Rectangle(object):\n    def __init__(self, x, y, width, height, encoding):\n        self.x = x\n        self.y = y\n        self.width = width\n        self.height = height\n        self.encoding = encoding\n\nclass PseudoCursorEncoding(object):\n    def __init__(self, image, mask):\n        self.image = image\n        self.mask = mask\n\n    @classmethod\n    def parse_rectangle(cls, client, x, y, width, height, data):\n        split = width * height * client.framebuffer.bypp\n        image = np.frombuffer(data[:split], np.uint8).reshape((height, width, 4))[:, :, [0, 1, 2]]\n\n        # Turn raw bytes into uint8 array\n        mask = np.frombuffer(data[split:], np.uint8)\n        # Turn uint8 array into bit array, and go over the scanlines\n        mask = np.unpackbits(mask).reshape((height, -1 if mask.size else 0))[:, :width]\n\n        encoding = cls(image, mask)\n        return Rectangle(x, y, width, height, encoding)\n\nclass RAWEncoding(object):\n    def __init__(self, data):\n        self.data = data\n\n    @classmethod\n    def parse_rectangle(cls, client, x, y, width, height, data):\n        assert client.framebuffer.bpp == 32\n        data = np.frombuffer(data, np.uint8).reshape((height, width, 4))[:, :, [0, 1, 2]]\n        encoding = cls(data)\n        return Rectangle(x, y, width, height, encoding)\n\nclass ZlibEncoding(object):\n    def __init__(self, data):\n        self.data = data\n\n    @classmethod\n    def parse_rectangle(cls, client, x, y, width, height, data):\n        decompressed = client.zlib_decompressor.decompress(data)\n        logger.debug('[zlib] Decompressed from %s bytes -> %s bytes', len(data), len(decompressed))\n        pyprofile.incr('vncdriver.recv_rectangle.zlib_encoding.decompressed_bytes', len(decompressed), unit=pyprofile.BYTES)\n        data = np.frombuffer(decompressed, np.uint8).reshape((height, width, 4))[:, :, [0, 1, 2]]\n        encoding = cls(data)\n        return Rectangle(x, y, width, height, encoding)\n\nclass ZRLEEncoding(object):\n    def __init__(self, data):\n        self.data = data\n\n    @classmethod\n    def parse_rectangle(cls, client, x, y, width, height, data):\n        decompressed = client.zlib_decompressor.decompress(data)\n        logger.debug('[zrle] Decompressed from %s bytes -> %s bytes', len(data), len(decompressed))\n        pyprofile.incr('vncdriver.recv_rectangle.zrle_encoding.decompressed_bytes', len(decompressed), unit=pyprofile.BYTES)\n\n        if client.framebuffer.bpp > 24:\n            bytes_per_pixel = 3\n        else:\n            bytes_per_pixel = client.framebuffer.bypp\n\n        buf = BytesIO(decompressed)\n        data = cls._read(x, y, width, height, buf, bytes_per_pixel)\n        encoding = cls(data)\n        return Rectangle(x, y, width, height, encoding)\n\n    @classmethod\n    def _read(cls, x, y, width, height, buf, bytes_per_pixel):\n        data = np.zeros([height, width, 3], dtype=np.uint8) + 255\n\n        for tile_y in range(0, height, 64):\n            tile_height = min(64, height-tile_y)\n\n            for tile_x in range(0, width, 64):\n                tile_width = min(64, width-tile_x)\n\n                tile = data[tile_y:tile_y+tile_height, tile_x:tile_x+tile_width]\n                cls._read_tile(tile, buf, tile_width, tile_height, bytes_per_pixel)\n        return data\n\n    @classmethod\n    def _read_tile(cls, tile, buf, tile_width, tile_height, bytes_per_pixel):\n        assert bytes_per_pixel == 3\n\n        # Each tile begins with a subencoding type byte.  The top bit of this\n        # byte is set if the tile has been run-length encoded, clear otherwise.\n        # The bottom 7 bits indicate the size of the palette used: zero means\n        # no palette, 1 means that the tile is of a single color, and 2 to 127\n        # indicate a palette of that size.  The special subencoding values 129\n        # and 127 indicate that the palette is to be reused from the last tile\n        # that had a palette, with and without RLE, respectively.\n        (subencoding,) = struct.unpack('!B', buf.read(1))\n\n        run_length_encoded = bool(subencoding & 128)\n        palette_size = subencoding & 127\n\n        bytes = palette_size * bytes_per_pixel\n        palette_data = buf.read(bytes)\n        assert len(palette_data) == bytes, \"Palette data came up short: {} bytes rather than {}\".format(len(palette_data), bytes)\n\n        logger.debug('Handling zrle tile: run_length_encoded=%s palette_size=%s', run_length_encoded, palette_size)\n\n        if palette_size == 0 and not run_length_encoded:\n            # 0: Raw pixel data. width*height pixel values follow (where width and\n            # height are the width and height of the tile):\n            #\n            #  +-----------------------------+--------------+-------------+\n            #  | No. of bytes                | Type [Value] | Description |\n            #  +-----------------------------+--------------+-------------+\n            #  | width*height*BytesPerCPixel | CPIXEL array | pixels      |\n            #  +-----------------------------+--------------+-------------+\n            data = buf.read(bytes_per_pixel * tile_width * tile_height)\n            data = np.frombuffer(data, dtype=np.uint8).reshape((tile_height, tile_width, 3))\n            tile[:, :, :] = data\n            return\n        elif palette_size == 1 and not run_length_encoded:\n            # 1: A solid tile consisting of a single color.  The pixel value\n            # follows:\n            #\n            # +----------------+--------------+-------------+\n            # | No. of bytes   | Type [Value] | Description |\n            # +----------------+--------------+-------------+\n            # | bytesPerCPixel | CPIXEL       | pixelValue  |\n            # +----------------+--------------+-------------+\n            color = np.frombuffer(palette_data, dtype=np.uint8).reshape((3, ))\n            tile[:, :, :] = color\n            return\n        elif not run_length_encoded:\n            # 2 to 16:  Packed palette types.  The paletteSize is the value of the\n            # subencoding, which is followed by the palette, consisting of\n            # paletteSize pixel values.  The packed pixels follow, with each\n            # pixel represented as a bit field yielding a zero-based index into\n            # the palette.  For paletteSize 2, a 1-bit field is used; for\n            # paletteSize 3 or 4, a 2-bit field is used; and for paletteSize\n            # from 5 to 16, a 4-bit field is used.  The bit fields are packed\n            # into bytes, with the most significant bits representing the\n            # leftmost pixel (i.e., big endian).  For tiles not a multiple of 8,\n            # 4, or 2 pixels wide (as appropriate), padding bits are used to\n            # align each row to an exact number of bytes.\n\n            #   +----------------------------+--------------+--------------+\n            #   | No. of bytes               | Type [Value] | Description  |\n            #   +----------------------------+--------------+--------------+\n            #   | paletteSize*bytesPerCPixel | CPIXEL array | palette      |\n            #   | m                          | U8 array     | packedPixels |\n            #   +----------------------------+--------------+--------------+\n\n            #  where m is the number of bytes representing the packed pixels.\n            #  For paletteSize of 2, this is div(width+7,8)*height; for\n            #  paletteSize of 3 or 4, this is div(width+3,4)*height; or for\n            #  paletteSize of 5 to 16, this is div(width+1,2)*height.\n            palette = np.frombuffer(palette_data, dtype=np.uint8).reshape((-1, 3))\n\n            if palette_size > 16:\n                # No palette reuse in zrle\n                assert palette_size < 127\n                bits_per_packed_pixel = 8\n            elif palette_size > 4:\n                bits_per_packed_pixel = 4\n            elif palette_size > 2:\n                bits_per_packed_pixel = 2\n            else:\n                bits_per_packed_pixel = 1\n\n            for j in range(tile_height):\n                # Discard any leftover bits for each new line\n                b = 0\n                nbits = 0\n\n                for i in range(tile_width):\n                    if nbits == 0:\n                        (b,) = struct.unpack('!B', buf.read(1))\n                        nbits = 8\n                    nbits -= bits_per_packed_pixel\n                    idx = (b >> nbits) & ((1 << bits_per_packed_pixel) - 1) & 127\n                    tile[j, i, :] = palette[idx]\n            return\n        elif run_length_encoded and palette_size == 0:\n            # 128:  Plain RLE.  The data consists of a number of runs, repeated\n            # until the tile is done.  Runs may continue from the end of one row\n            # to the beginning of the next.  Each run is represented by a single\n            # pixel value followed by the length of the run.  The length is\n            # represented as one or more bytes.  The length is calculated as one\n            # more than the sum of all the bytes representing the length.  Any\n            # byte value other than 255 indicates the final byte.  So for\n            # example, length 1 is represented as [0], 255 as [254], 256 as\n            # [255,0], 257 as [255,1], 510 as [255,254], 511 as [255,255,0], and\n            # so on.\n            #\n            # +-------------------------+--------------+-----------------------+\n            # | No. of bytes            | Type [Value] | Description           |\n            # +-------------------------+--------------+-----------------------+\n            # | bytesPerCPixel          | CPIXEL       | pixelValue            |\n            # | div(runLength - 1, 255) | U8 array     | 255                   |\n            # | 1                       | U8           | (runLength-1) mod 255 |\n            # +-------------------------+--------------+-----------------------+\n            i = 0\n            pixels = tile_width * tile_height\n            data = np.zeros((pixels, 3))\n            while i < pixels:\n                pix = buf.read(bytes_per_pixel)\n                pix = np.frombuffer(pix, dtype=np.uint8).reshape((3, ))\n\n                count = 1\n                b = None\n\n                while b == 255 or b is None:\n                    (b,) = struct.unpack('!B', buf.read(1))\n                    count += b\n\n                data[i:i+count, :] = pix\n                i += count\n            assert i == pixels\n        elif run_length_encoded and palette_size > 1:\n            # 130 to 255:  Palette RLE.  Followed by the palette, consisting of\n            # paletteSize = (subencoding - 128) pixel values:\n            #\n            #   +----------------------------+--------------+-------------+\n            #   | No. of bytes               | Type [Value] | Description |\n            #   +----------------------------+--------------+-------------+\n            #   | paletteSize*bytesPerCPixel | CPIXEL array | palette     |\n            #   +----------------------------+--------------+-------------+\n            #\n            # Following the palette is, as with plain RLE, a number of runs,\n            # repeated until the tile is done.  A run of length one is\n            # represented simply by a palette index:\n            #\n            #         +--------------+--------------+--------------+\n            #         | No. of bytes | Type [Value] | Description  |\n            #         +--------------+--------------+--------------+\n            #         | 1            | U8           | paletteIndex |\n            #         +--------------+--------------+--------------+\n            #\n            # A run of length more than one is represented by a palette index\n            # with the top bit set, followed by the length of the run as for\n            # plain RLE.\n            #\n            # +-------------------------+--------------+-----------------------+\n            # | No. of bytes            | Type [Value] | Description           |\n            # +-------------------------+--------------+-----------------------+\n            # | 1                       | U8           | paletteIndex + 128    |\n            # | div(runLength - 1, 255) | U8 array     | 255                   |\n            # | 1                       | U8           | (runLength-1) mod 255 |\n            # +-------------------------+--------------+-----------------------+\n            palette = np.frombuffer(palette_data, dtype=np.uint8).reshape((-1, 3))\n\n            i = 0\n            pixels = tile_width * tile_height\n            data = np.zeros((pixels, 3))\n            while i < pixels:\n                (idx,) = struct.unpack('!B', buf.read(1))\n\n                count = 1\n\n                if idx & 128:\n                    b = None\n                    while b == 255 or b is None:\n                        (b,) = struct.unpack('!B', buf.read(1))\n                        count += b\n\n                idx &= 127\n                pix = palette[idx]\n\n                data[i:i+count, :] = pix\n                i += count\n            assert i == pixels\n        else:\n            assert False, \"Unhandled case: run_length_encoded={} palette_size={}\".format(run_length_encoded, palette_size)\n\n        tile[:] = data.reshape((tile_height, tile_width, 3))\n"
  },
  {
    "path": "universe/vncdriver/vendor/__init__.py",
    "content": ""
  },
  {
    "path": "universe/vncdriver/vendor/pydes.py",
    "content": "#############################################################################\n# \t\t\t\tDocumentation\t\t\t\t    #\n#############################################################################\n\n# Author:   Todd Whiteman\n# Date:     16th March, 2009\n# Verion:   2.0.0\n# License:  Public Domain - free to do as you wish\n# Homepage: http://twhiteman.netfirms.com/des.html\n#\n# This is a pure python implementation of the DES encryption algorithm.\n# It's pure python to avoid portability issues, since most DES\n# implementations are programmed in C (for performance reasons).\n#\n# Triple DES class is also implemented, utilising the DES base. Triple DES\n# is either DES-EDE3 with a 24 byte key, or DES-EDE2 with a 16 byte key.\n#\n# See the README.txt that should come with this python module for the\n# implementation methods used.\n#\n# Thanks to:\n#  * David Broadwell for ideas, comments and suggestions.\n#  * Mario Wolff for pointing out and debugging some triple des CBC errors.\n#  * Santiago Palladino for providing the PKCS5 padding technique.\n#  * Shaya for correcting the PAD_PKCS5 triple des CBC errors.\n#\n\"\"\"A pure python implementation of the DES and TRIPLE DES encryption algorithms.\n\nClass initialization\n--------------------\npyDes.des(key, [mode], [IV], [pad], [padmode])\npyDes.triple_des(key, [mode], [IV], [pad], [padmode])\n\nkey     -> Bytes containing the encryption key. 8 bytes for DES, 16 or 24 bytes\n\t   for Triple DES\nmode    -> Optional argument for encryption type, can be either\n\t   pyDes.ECB (Electronic Code Book) or pyDes.CBC (Cypher Block Chaining)\nIV      -> Optional Initial Value bytes, must be supplied if using CBC mode.\n\t   Length must be 8 bytes.\npad     -> Optional argument, set the pad character (PAD_NORMAL) to use during\n\t   all encrypt/decrpt operations done with this instance.\npadmode -> Optional argument, set the padding mode (PAD_NORMAL or PAD_PKCS5)\n\t   to use during all encrypt/decrpt operations done with this instance.\n\nI recommend to use PAD_PKCS5 padding, as then you never need to worry about any\npadding issues, as the padding can be removed unambiguously upon decrypting\ndata that was encrypted using PAD_PKCS5 padmode.\n\nCommon methods\n--------------\nencrypt(data, [pad], [padmode])\ndecrypt(data, [pad], [padmode])\n\ndata    -> Bytes to be encrypted/decrypted\npad     -> Optional argument. Only when using padmode of PAD_NORMAL. For\n\t   encryption, adds this characters to the end of the data block when\n\t   data is not a multiple of 8 bytes. For decryption, will remove the\n\t   trailing characters that match this pad character from the last 8\n\t   bytes of the unencrypted data block.\npadmode -> Optional argument, set the padding mode, must be one of PAD_NORMAL\n\t   or PAD_PKCS5). Defaults to PAD_NORMAL.\n\n\nExample\n-------\nfrom pyDes import *\n\ndata = \"Please encrypt my data\"\nk = des(\"DESCRYPT\", CBC, \"\\0\\0\\0\\0\\0\\0\\0\\0\", pad=None, padmode=PAD_PKCS5)\n# For Python3, you'll need to use bytes, i.e.:\n#   data = b\"Please encrypt my data\"\n#   k = des(b\"DESCRYPT\", CBC, b\"\\0\\0\\0\\0\\0\\0\\0\\0\", pad=None, padmode=PAD_PKCS5)\nd = k.encrypt(data)\nprint \"Encrypted: %r\" % d\nprint \"Decrypted: %r\" % k.decrypt(d)\nassert k.decrypt(d, padmode=PAD_PKCS5) == data\n\n\nSee the module source (pyDes.py) for more examples of use.\nYou can also run the pyDes.py file without and arguments to see a simple test.\n\nNote: This code was not written for high-end systems needing a fast\n      implementation, but rather a handy portable solution with small usage.\n\n\"\"\"\n\nimport sys\n\n# _pythonMajorVersion is used to handle Python2 and Python3 differences.\n_pythonMajorVersion = sys.version_info[0]\n\n# Modes of crypting / cyphering\nECB =\t0\nCBC =\t1\n\n# Modes of padding\nPAD_NORMAL = 1\nPAD_PKCS5 = 2\n\n# PAD_PKCS5: is a method that will unambiguously remove all padding\n#            characters after decryption, when originally encrypted with\n#            this padding mode.\n# For a good description of the PKCS5 padding technique, see:\n# http://www.faqs.org/rfcs/rfc1423.html\n\n# The base class shared by des and triple des.\nclass _baseDes(object):\n\tdef __init__(self, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):\n\t\tif IV:\n\t\t\tIV = self._guardAgainstUnicode(IV)\n\t\tif pad:\n\t\t\tpad = self._guardAgainstUnicode(pad)\n\t\tself.block_size = 8\n\t\t# Sanity checking of arguments.\n\t\tif pad and padmode == PAD_PKCS5:\n\t\t\traise ValueError(\"Cannot use a pad character with PAD_PKCS5\")\n\t\tif IV and len(IV) != self.block_size:\n\t\t\traise ValueError(\"Invalid Initial Value (IV), must be a multiple of \" + str(self.block_size) + \" bytes\")\n\n\t\t# Set the passed in variables\n\t\tself._mode = mode\n\t\tself._iv = IV\n\t\tself._padding = pad\n\t\tself._padmode = padmode\n\n\tdef getKey(self):\n\t\t\"\"\"getKey() -> bytes\"\"\"\n\t\treturn self.__key\n\n\tdef setKey(self, key):\n\t\t\"\"\"Will set the crypting key for this object.\"\"\"\n\t\tkey = self._guardAgainstUnicode(key)\n\t\tself.__key = key\n\n\tdef getMode(self):\n\t\t\"\"\"getMode() -> pyDes.ECB or pyDes.CBC\"\"\"\n\t\treturn self._mode\n\n\tdef setMode(self, mode):\n\t\t\"\"\"Sets the type of crypting mode, pyDes.ECB or pyDes.CBC\"\"\"\n\t\tself._mode = mode\n\n\tdef getPadding(self):\n\t\t\"\"\"getPadding() -> bytes of length 1. Padding character.\"\"\"\n\t\treturn self._padding\n\n\tdef setPadding(self, pad):\n\t\t\"\"\"setPadding() -> bytes of length 1. Padding character.\"\"\"\n\t\tif pad is not None:\n\t\t\tpad = self._guardAgainstUnicode(pad)\n\t\tself._padding = pad\n\n\tdef getPadMode(self):\n\t\t\"\"\"getPadMode() -> pyDes.PAD_NORMAL or pyDes.PAD_PKCS5\"\"\"\n\t\treturn self._padmode\n\n\tdef setPadMode(self, mode):\n\t\t\"\"\"Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5\"\"\"\n\t\tself._padmode = mode\n\n\tdef getIV(self):\n\t\t\"\"\"getIV() -> bytes\"\"\"\n\t\treturn self._iv\n\n\tdef setIV(self, IV):\n\t\t\"\"\"Will set the Initial Value, used in conjunction with CBC mode\"\"\"\n\t\tif not IV or len(IV) != self.block_size:\n\t\t\traise ValueError(\"Invalid Initial Value (IV), must be a multiple of \" + str(self.block_size) + \" bytes\")\n\t\tIV = self._guardAgainstUnicode(IV)\n\t\tself._iv = IV\n\n\tdef _padData(self, data, pad, padmode):\n\t\t# Pad data depending on the mode\n\t\tif padmode is None:\n\t\t\t# Get the default padding mode.\n\t\t\tpadmode = self.getPadMode()\n\t\tif pad and padmode == PAD_PKCS5:\n\t\t\traise ValueError(\"Cannot use a pad character with PAD_PKCS5\")\n\n\t\tif padmode == PAD_NORMAL:\n\t\t\tif len(data) % self.block_size == 0:\n\t\t\t\t# No padding required.\n\t\t\t\treturn data\n\n\t\t\tif not pad:\n\t\t\t\t# Get the default padding.\n\t\t\t\tpad = self.getPadding()\n\t\t\tif not pad:\n\t\t\t\traise ValueError(\"Data must be a multiple of \" + str(self.block_size) + \" bytes in length. Use padmode=PAD_PKCS5 or set the pad character.\")\n\t\t\tdata += (self.block_size - (len(data) % self.block_size)) * pad\n\n\t\telif padmode == PAD_PKCS5:\n\t\t\tpad_len = 8 - (len(data) % self.block_size)\n\t\t\tif _pythonMajorVersion < 3:\n\t\t\t\tdata += pad_len * chr(pad_len)\n\t\t\telse:\n\t\t\t\tdata += bytes([pad_len] * pad_len)\n\n\t\treturn data\n\n\tdef _unpadData(self, data, pad, padmode):\n\t\t# Unpad data depending on the mode.\n\t\tif not data:\n\t\t\treturn data\n\t\tif pad and padmode == PAD_PKCS5:\n\t\t\traise ValueError(\"Cannot use a pad character with PAD_PKCS5\")\n\t\tif padmode is None:\n\t\t\t# Get the default padding mode.\n\t\t\tpadmode = self.getPadMode()\n\n\t\tif padmode == PAD_NORMAL:\n\t\t\tif not pad:\n\t\t\t\t# Get the default padding.\n\t\t\t\tpad = self.getPadding()\n\t\t\tif pad:\n\t\t\t\tdata = data[:-self.block_size] + \\\n\t\t\t\t       data[-self.block_size:].rstrip(pad)\n\n\t\telif padmode == PAD_PKCS5:\n\t\t\tif _pythonMajorVersion < 3:\n\t\t\t\tpad_len = ord(data[-1])\n\t\t\telse:\n\t\t\t\tpad_len = data[-1]\n\t\t\tdata = data[:-pad_len]\n\n\t\treturn data\n\n\tdef _guardAgainstUnicode(self, data):\n\t\t# Only accept byte strings or ascii unicode values, otherwise\n\t\t# there is no way to correctly decode the data into bytes.\n\t\tif _pythonMajorVersion < 3:\n\t\t\tif isinstance(data, unicode):\n\t\t\t\traise ValueError(\"pyDes can only work with bytes, not Unicode strings.\")\n\t\telse:\n\t\t\tif isinstance(data, str):\n\t\t\t\t# Only accept ascii unicode values.\n\t\t\t\ttry:\n\t\t\t\t\treturn data.encode('ascii')\n\t\t\t\texcept UnicodeEncodeError:\n\t\t\t\t\tpass\n\t\t\t\traise ValueError(\"pyDes can only work with encoded strings, not Unicode.\")\n\t\treturn data\n\n#############################################################################\n# \t\t\t\t    DES\t\t\t\t\t    #\n#############################################################################\nclass des(_baseDes):\n\t\"\"\"DES encryption/decrytpion class\n\n\tSupports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.\n\n\tpyDes.des(key,[mode], [IV])\n\n\tkey  -> Bytes containing the encryption key, must be exactly 8 bytes\n\tmode -> Optional argument for encryption type, can be either pyDes.ECB\n\t\t(Electronic Code Book), pyDes.CBC (Cypher Block Chaining)\n\tIV   -> Optional Initial Value bytes, must be supplied if using CBC mode.\n\t\tMust be 8 bytes in length.\n\tpad  -> Optional argument, set the pad character (PAD_NORMAL) to use\n\t\tduring all encrypt/decrpt operations done with this instance.\n\tpadmode -> Optional argument, set the padding mode (PAD_NORMAL or\n\t\tPAD_PKCS5) to use during all encrypt/decrpt operations done\n\t\twith this instance.\n\t\"\"\"\n\n\n\t# Permutation and translation tables for DES\n\t__pc1 = [56, 48, 40, 32, 24, 16,  8,\n\t\t  0, 57, 49, 41, 33, 25, 17,\n\t\t  9,  1, 58, 50, 42, 34, 26,\n\t\t 18, 10,  2, 59, 51, 43, 35,\n\t\t 62, 54, 46, 38, 30, 22, 14,\n\t\t  6, 61, 53, 45, 37, 29, 21,\n\t\t 13,  5, 60, 52, 44, 36, 28,\n\t\t 20, 12,  4, 27, 19, 11,  3\n\t]\n\n\t# number left rotations of pc1\n\t__left_rotations = [\n\t\t1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1\n\t]\n\n\t# permuted choice key (table 2)\n\t__pc2 = [\n\t\t13, 16, 10, 23,  0,  4,\n\t\t 2, 27, 14,  5, 20,  9,\n\t\t22, 18, 11,  3, 25,  7,\n\t\t15,  6, 26, 19, 12,  1,\n\t\t40, 51, 30, 36, 46, 54,\n\t\t29, 39, 50, 44, 32, 47,\n\t\t43, 48, 38, 55, 33, 52,\n\t\t45, 41, 49, 35, 28, 31\n\t]\n\n\t# initial permutation IP\n\t__ip = [57, 49, 41, 33, 25, 17, 9,  1,\n\t\t59, 51, 43, 35, 27, 19, 11, 3,\n\t\t61, 53, 45, 37, 29, 21, 13, 5,\n\t\t63, 55, 47, 39, 31, 23, 15, 7,\n\t\t56, 48, 40, 32, 24, 16, 8,  0,\n\t\t58, 50, 42, 34, 26, 18, 10, 2,\n\t\t60, 52, 44, 36, 28, 20, 12, 4,\n\t\t62, 54, 46, 38, 30, 22, 14, 6\n\t]\n\n\t# Expansion table for turning 32 bit blocks into 48 bits\n\t__expansion_table = [\n\t\t31,  0,  1,  2,  3,  4,\n\t\t 3,  4,  5,  6,  7,  8,\n\t\t 7,  8,  9, 10, 11, 12,\n\t\t11, 12, 13, 14, 15, 16,\n\t\t15, 16, 17, 18, 19, 20,\n\t\t19, 20, 21, 22, 23, 24,\n\t\t23, 24, 25, 26, 27, 28,\n\t\t27, 28, 29, 30, 31,  0\n\t]\n\n\t# The (in)famous S-boxes\n\t__sbox = [\n\t\t# S1\n\t\t[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,\n\t\t 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,\n\t\t 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,\n\t\t 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13],\n\n\t\t# S2\n\t\t[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,\n\t\t 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,\n\t\t 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,\n\t\t 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9],\n\n\t\t# S3\n\t\t[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,\n\t\t 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,\n\t\t 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,\n\t\t 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12],\n\n\t\t# S4\n\t\t[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,\n\t\t 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,\n\t\t 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,\n\t\t 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14],\n\n\t\t# S5\n\t\t[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,\n\t\t 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,\n\t\t 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,\n\t\t 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3],\n\n\t\t# S6\n\t\t[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,\n\t\t 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,\n\t\t 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,\n\t\t 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13],\n\n\t\t# S7\n\t\t[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,\n\t\t 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,\n\t\t 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,\n\t\t 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12],\n\n\t\t# S8\n\t\t[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,\n\t\t 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,\n\t\t 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,\n\t\t 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11],\n\t]\n\n\n\t# 32-bit permutation function P used on the output of the S-boxes\n\t__p = [\n\t\t15, 6, 19, 20, 28, 11,\n\t\t27, 16, 0, 14, 22, 25,\n\t\t4, 17, 30, 9, 1, 7,\n\t\t23,13, 31, 26, 2, 8,\n\t\t18, 12, 29, 5, 21, 10,\n\t\t3, 24\n\t]\n\n\t# final permutation IP^-1\n\t__fp = [\n\t\t39,  7, 47, 15, 55, 23, 63, 31,\n\t\t38,  6, 46, 14, 54, 22, 62, 30,\n\t\t37,  5, 45, 13, 53, 21, 61, 29,\n\t\t36,  4, 44, 12, 52, 20, 60, 28,\n\t\t35,  3, 43, 11, 51, 19, 59, 27,\n\t\t34,  2, 42, 10, 50, 18, 58, 26,\n\t\t33,  1, 41,  9, 49, 17, 57, 25,\n\t\t32,  0, 40,  8, 48, 16, 56, 24\n\t]\n\n\t# Type of crypting being done\n\tENCRYPT =\t0x00\n\tDECRYPT =\t0x01\n\n\t# Initialisation\n\tdef __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):\n\t\t# Sanity checking of arguments.\n\t\tif len(key) != 8:\n\t\t\traise ValueError(\"Invalid DES key size. Key must be exactly 8 bytes long.\")\n\t\t_baseDes.__init__(self, mode, IV, pad, padmode)\n\t\tself.key_size = 8\n\n\t\tself.L = []\n\t\tself.R = []\n\t\tself.Kn = [ [0] * 48 ] * 16\t# 16 48-bit keys (K1 - K16)\n\t\tself.final = []\n\n\t\tself.setKey(key)\n\n\tdef setKey(self, key):\n\t\t\"\"\"Will set the crypting key for this object. Must be 8 bytes.\"\"\"\n\t\t_baseDes.setKey(self, key)\n\t\tself.__create_sub_keys()\n\n\tdef __String_to_BitList(self, data):\n\t\t\"\"\"Turn the string data, into a list of bits (1, 0)'s\"\"\"\n\t\tif _pythonMajorVersion < 3:\n\t\t\t# Turn the strings into integers. Python 3 uses a bytes\n\t\t\t# class, which already has this behaviour.\n\t\t\tdata = [ord(c) for c in data]\n\t\tl = len(data) * 8\n\t\tresult = [0] * l\n\t\tpos = 0\n\t\tfor ch in data:\n\t\t\ti = 7\n\t\t\twhile i >= 0:\n\t\t\t\tif ch & (1 << i) != 0:\n\t\t\t\t\tresult[pos] = 1\n\t\t\t\telse:\n\t\t\t\t\tresult[pos] = 0\n\t\t\t\tpos += 1\n\t\t\t\ti -= 1\n\n\t\treturn result\n\n\tdef __BitList_to_String(self, data):\n\t\t\"\"\"Turn the list of bits -> data, into a string\"\"\"\n\t\tresult = []\n\t\tpos = 0\n\t\tc = 0\n\t\twhile pos < len(data):\n\t\t\tc += data[pos] << (7 - (pos % 8))\n\t\t\tif (pos % 8) == 7:\n\t\t\t\tresult.append(c)\n\t\t\t\tc = 0\n\t\t\tpos += 1\n\n\t\tif _pythonMajorVersion < 3:\n\t\t\treturn ''.join([ chr(c) for c in result ])\n\t\telse:\n\t\t\treturn bytes(result)\n\n\tdef __permutate(self, table, block):\n\t\t\"\"\"Permutate this block with the specified table\"\"\"\n\t\treturn list(map(lambda x: block[x], table))\n\n\t# Transform the secret key, so that it is ready for data processing\n\t# Create the 16 subkeys, K[1] - K[16]\n\tdef __create_sub_keys(self):\n\t\t\"\"\"Create the 16 subkeys K[1] to K[16] from the given key\"\"\"\n\t\tkey = self.__permutate(des.__pc1, self.__String_to_BitList(self.getKey()))\n\t\ti = 0\n\t\t# Split into Left and Right sections\n\t\tself.L = key[:28]\n\t\tself.R = key[28:]\n\t\twhile i < 16:\n\t\t\tj = 0\n\t\t\t# Perform circular left shifts\n\t\t\twhile j < des.__left_rotations[i]:\n\t\t\t\tself.L.append(self.L[0])\n\t\t\t\tdel self.L[0]\n\n\t\t\t\tself.R.append(self.R[0])\n\t\t\t\tdel self.R[0]\n\n\t\t\t\tj += 1\n\n\t\t\t# Create one of the 16 subkeys through pc2 permutation\n\t\t\tself.Kn[i] = self.__permutate(des.__pc2, self.L + self.R)\n\n\t\t\ti += 1\n\n\t# Main part of the encryption algorithm, the number cruncher :)\n\tdef __des_crypt(self, block, crypt_type):\n\t\t\"\"\"Crypt the block of data through DES bit-manipulation\"\"\"\n\t\tblock = self.__permutate(des.__ip, block)\n\t\tself.L = block[:32]\n\t\tself.R = block[32:]\n\n\t\t# Encryption starts from Kn[1] through to Kn[16]\n\t\tif crypt_type == des.ENCRYPT:\n\t\t\titeration = 0\n\t\t\titeration_adjustment = 1\n\t\t# Decryption starts from Kn[16] down to Kn[1]\n\t\telse:\n\t\t\titeration = 15\n\t\t\titeration_adjustment = -1\n\n\t\ti = 0\n\t\twhile i < 16:\n\t\t\t# Make a copy of R[i-1], this will later become L[i]\n\t\t\ttempR = self.R[:]\n\n\t\t\t# Permutate R[i - 1] to start creating R[i]\n\t\t\tself.R = self.__permutate(des.__expansion_table, self.R)\n\n\t\t\t# Exclusive or R[i - 1] with K[i], create B[1] to B[8] whilst here\n\t\t\tself.R = list(map(lambda x, y: x ^ y, self.R, self.Kn[iteration]))\n\t\t\tB = [self.R[:6], self.R[6:12], self.R[12:18], self.R[18:24], self.R[24:30], self.R[30:36], self.R[36:42], self.R[42:]]\n\t\t\t# Optimization: Replaced below commented code with above\n\t\t\t#j = 0\n\t\t\t#B = []\n\t\t\t#while j < len(self.R):\n\t\t\t#\tself.R[j] = self.R[j] ^ self.Kn[iteration][j]\n\t\t\t#\tj += 1\n\t\t\t#\tif j % 6 == 0:\n\t\t\t#\t\tB.append(self.R[j-6:j])\n\n\t\t\t# Permutate B[1] to B[8] using the S-Boxes\n\t\t\tj = 0\n\t\t\tBn = [0] * 32\n\t\t\tpos = 0\n\t\t\twhile j < 8:\n\t\t\t\t# Work out the offsets\n\t\t\t\tm = (B[j][0] << 1) + B[j][5]\n\t\t\t\tn = (B[j][1] << 3) + (B[j][2] << 2) + (B[j][3] << 1) + B[j][4]\n\n\t\t\t\t# Find the permutation value\n\t\t\t\tv = des.__sbox[j][(m << 4) + n]\n\n\t\t\t\t# Turn value into bits, add it to result: Bn\n\t\t\t\tBn[pos] = (v & 8) >> 3\n\t\t\t\tBn[pos + 1] = (v & 4) >> 2\n\t\t\t\tBn[pos + 2] = (v & 2) >> 1\n\t\t\t\tBn[pos + 3] = v & 1\n\n\t\t\t\tpos += 4\n\t\t\t\tj += 1\n\n\t\t\t# Permutate the concatination of B[1] to B[8] (Bn)\n\t\t\tself.R = self.__permutate(des.__p, Bn)\n\n\t\t\t# Xor with L[i - 1]\n\t\t\tself.R = list(map(lambda x, y: x ^ y, self.R, self.L))\n\t\t\t# Optimization: This now replaces the below commented code\n\t\t\t#j = 0\n\t\t\t#while j < len(self.R):\n\t\t\t#\tself.R[j] = self.R[j] ^ self.L[j]\n\t\t\t#\tj += 1\n\n\t\t\t# L[i] becomes R[i - 1]\n\t\t\tself.L = tempR\n\n\t\t\ti += 1\n\t\t\titeration += iteration_adjustment\n\n\t\t# Final permutation of R[16]L[16]\n\t\tself.final = self.__permutate(des.__fp, self.R + self.L)\n\t\treturn self.final\n\n\n\t# Data to be encrypted/decrypted\n\tdef crypt(self, data, crypt_type):\n\t\t\"\"\"Crypt the data in blocks, running it through des_crypt()\"\"\"\n\n\t\t# Error check the data\n\t\tif not data:\n\t\t\treturn ''\n\t\tif len(data) % self.block_size != 0:\n\t\t\tif crypt_type == des.DECRYPT: # Decryption must work on 8 byte blocks\n\t\t\t\traise ValueError(\"Invalid data length, data must be a multiple of \" + str(self.block_size) + \" bytes\\n.\")\n\t\t\tif not self.getPadding():\n\t\t\t\traise ValueError(\"Invalid data length, data must be a multiple of \" + str(self.block_size) + \" bytes\\n. Try setting the optional padding character\")\n\t\t\telse:\n\t\t\t\tdata += (self.block_size - (len(data) % self.block_size)) * self.getPadding()\n\t\t\t# print \"Len of data: %f\" % (len(data) / self.block_size)\n\n\t\tif self.getMode() == CBC:\n\t\t\tif self.getIV():\n\t\t\t\tiv = self.__String_to_BitList(self.getIV())\n\t\t\telse:\n\t\t\t\traise ValueError(\"For CBC mode, you must supply the Initial Value (IV) for ciphering\")\n\n\t\t# Split the data into blocks, crypting each one seperately\n\t\ti = 0\n\t\tdict = {}\n\t\tresult = []\n\t\t#cached = 0\n\t\t#lines = 0\n\t\twhile i < len(data):\n\t\t\t# Test code for caching encryption results\n\t\t\t#lines += 1\n\t\t\t#if dict.has_key(data[i:i+8]):\n\t\t\t\t#print \"Cached result for: %s\" % data[i:i+8]\n\t\t\t#\tcached += 1\n\t\t\t#\tresult.append(dict[data[i:i+8]])\n\t\t\t#\ti += 8\n\t\t\t#\tcontinue\n\n\t\t\tblock = self.__String_to_BitList(data[i:i+8])\n\n\t\t\t# Xor with IV if using CBC mode\n\t\t\tif self.getMode() == CBC:\n\t\t\t\tif crypt_type == des.ENCRYPT:\n\t\t\t\t\tblock = list(map(lambda x, y: x ^ y, block, iv))\n\t\t\t\t\t#j = 0\n\t\t\t\t\t#while j < len(block):\n\t\t\t\t\t#\tblock[j] = block[j] ^ iv[j]\n\t\t\t\t\t#\tj += 1\n\n\t\t\t\tprocessed_block = self.__des_crypt(block, crypt_type)\n\n\t\t\t\tif crypt_type == des.DECRYPT:\n\t\t\t\t\tprocessed_block = list(map(lambda x, y: x ^ y, processed_block, iv))\n\t\t\t\t\t#j = 0\n\t\t\t\t\t#while j < len(processed_block):\n\t\t\t\t\t#\tprocessed_block[j] = processed_block[j] ^ iv[j]\n\t\t\t\t\t#\tj += 1\n\t\t\t\t\tiv = block\n\t\t\t\telse:\n\t\t\t\t\tiv = processed_block\n\t\t\telse:\n\t\t\t\tprocessed_block = self.__des_crypt(block, crypt_type)\n\n\n\t\t\t# Add the resulting crypted block to our list\n\t\t\t#d = self.__BitList_to_String(processed_block)\n\t\t\t#result.append(d)\n\t\t\tresult.append(self.__BitList_to_String(processed_block))\n\t\t\t#dict[data[i:i+8]] = d\n\t\t\ti += 8\n\n\t\t# print \"Lines: %d, cached: %d\" % (lines, cached)\n\n\t\t# Return the full crypted string\n\t\tif _pythonMajorVersion < 3:\n\t\t\treturn ''.join(result)\n\t\telse:\n\t\t\treturn bytes.fromhex('').join(result)\n\n\tdef encrypt(self, data, pad=None, padmode=None):\n\t\t\"\"\"encrypt(data, [pad], [padmode]) -> bytes\n\n\t\tdata : Bytes to be encrypted\n\t\tpad  : Optional argument for encryption padding. Must only be one byte\n\t\tpadmode : Optional argument for overriding the padding mode.\n\n\t\tThe data must be a multiple of 8 bytes and will be encrypted\n\t\twith the already specified key. Data does not have to be a\n\t\tmultiple of 8 bytes if the padding character is supplied, or\n\t\tthe padmode is set to PAD_PKCS5, as bytes will then added to\n\t\tensure the be padded data is a multiple of 8 bytes.\n\t\t\"\"\"\n\t\tdata = self._guardAgainstUnicode(data)\n\t\tif pad is not None:\n\t\t\tpad = self._guardAgainstUnicode(pad)\n\t\tdata = self._padData(data, pad, padmode)\n\t\treturn self.crypt(data, des.ENCRYPT)\n\n\tdef decrypt(self, data, pad=None, padmode=None):\n\t\t\"\"\"decrypt(data, [pad], [padmode]) -> bytes\n\n\t\tdata : Bytes to be encrypted\n\t\tpad  : Optional argument for decryption padding. Must only be one byte\n\t\tpadmode : Optional argument for overriding the padding mode.\n\n\t\tThe data must be a multiple of 8 bytes and will be decrypted\n\t\twith the already specified key. In PAD_NORMAL mode, if the\n\t\toptional padding character is supplied, then the un-encrypted\n\t\tdata will have the padding characters removed from the end of\n\t\tthe bytes. This pad removal only occurs on the last 8 bytes of\n\t\tthe data (last data block). In PAD_PKCS5 mode, the special\n\t\tpadding end markers will be removed from the data after decrypting.\n\t\t\"\"\"\n\t\tdata = self._guardAgainstUnicode(data)\n\t\tif pad is not None:\n\t\t\tpad = self._guardAgainstUnicode(pad)\n\t\tdata = self.crypt(data, des.DECRYPT)\n\t\treturn self._unpadData(data, pad, padmode)\n\n\n\n#############################################################################\n# \t\t\t\tTriple DES\t\t\t\t    #\n#############################################################################\nclass triple_des(_baseDes):\n\t\"\"\"Triple DES encryption/decrytpion class\n\n\tThis algorithm uses the DES-EDE3 (when a 24 byte key is supplied) or\n\tthe DES-EDE2 (when a 16 byte key is supplied) encryption methods.\n\tSupports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.\n\n\tpyDes.des(key, [mode], [IV])\n\n\tkey  -> Bytes containing the encryption key, must be either 16 or\n\t        24 bytes long\n\tmode -> Optional argument for encryption type, can be either pyDes.ECB\n\t\t(Electronic Code Book), pyDes.CBC (Cypher Block Chaining)\n\tIV   -> Optional Initial Value bytes, must be supplied if using CBC mode.\n\t\tMust be 8 bytes in length.\n\tpad  -> Optional argument, set the pad character (PAD_NORMAL) to use\n\t\tduring all encrypt/decrpt operations done with this instance.\n\tpadmode -> Optional argument, set the padding mode (PAD_NORMAL or\n\t\tPAD_PKCS5) to use during all encrypt/decrpt operations done\n\t\twith this instance.\n\t\"\"\"\n\tdef __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):\n\t\t_baseDes.__init__(self, mode, IV, pad, padmode)\n\t\tself.setKey(key)\n\n\tdef setKey(self, key):\n\t\t\"\"\"Will set the crypting key for this object. Either 16 or 24 bytes long.\"\"\"\n\t\tself.key_size = 24  # Use DES-EDE3 mode\n\t\tif len(key) != self.key_size:\n\t\t\tif len(key) == 16: # Use DES-EDE2 mode\n\t\t\t\tself.key_size = 16\n\t\t\telse:\n\t\t\t\traise ValueError(\"Invalid triple DES key size. Key must be either 16 or 24 bytes long\")\n\t\tif self.getMode() == CBC:\n\t\t\tif not self.getIV():\n\t\t\t\t# Use the first 8 bytes of the key\n\t\t\t\tself._iv = key[:self.block_size]\n\t\t\tif len(self.getIV()) != self.block_size:\n\t\t\t\traise ValueError(\"Invalid IV, must be 8 bytes in length\")\n\t\tself.__key1 = des(key[:8], self._mode, self._iv,\n\t\t\t\t  self._padding, self._padmode)\n\t\tself.__key2 = des(key[8:16], self._mode, self._iv,\n\t\t\t\t  self._padding, self._padmode)\n\t\tif self.key_size == 16:\n\t\t\tself.__key3 = self.__key1\n\t\telse:\n\t\t\tself.__key3 = des(key[16:], self._mode, self._iv,\n\t\t\t\t\t  self._padding, self._padmode)\n\t\t_baseDes.setKey(self, key)\n\n\t# Override setter methods to work on all 3 keys.\n\n\tdef setMode(self, mode):\n\t\t\"\"\"Sets the type of crypting mode, pyDes.ECB or pyDes.CBC\"\"\"\n\t\t_baseDes.setMode(self, mode)\n\t\tfor key in (self.__key1, self.__key2, self.__key3):\n\t\t\tkey.setMode(mode)\n\n\tdef setPadding(self, pad):\n\t\t\"\"\"setPadding() -> bytes of length 1. Padding character.\"\"\"\n\t\t_baseDes.setPadding(self, pad)\n\t\tfor key in (self.__key1, self.__key2, self.__key3):\n\t\t\tkey.setPadding(pad)\n\n\tdef setPadMode(self, mode):\n\t\t\"\"\"Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5\"\"\"\n\t\t_baseDes.setPadMode(self, mode)\n\t\tfor key in (self.__key1, self.__key2, self.__key3):\n\t\t\tkey.setPadMode(mode)\n\n\tdef setIV(self, IV):\n\t\t\"\"\"Will set the Initial Value, used in conjunction with CBC mode\"\"\"\n\t\t_baseDes.setIV(self, IV)\n\t\tfor key in (self.__key1, self.__key2, self.__key3):\n\t\t\tkey.setIV(IV)\n\n\tdef encrypt(self, data, pad=None, padmode=None):\n\t\t\"\"\"encrypt(data, [pad], [padmode]) -> bytes\n\n\t\tdata : bytes to be encrypted\n\t\tpad  : Optional argument for encryption padding. Must only be one byte\n\t\tpadmode : Optional argument for overriding the padding mode.\n\n\t\tThe data must be a multiple of 8 bytes and will be encrypted\n\t\twith the already specified key. Data does not have to be a\n\t\tmultiple of 8 bytes if the padding character is supplied, or\n\t\tthe padmode is set to PAD_PKCS5, as bytes will then added to\n\t\tensure the be padded data is a multiple of 8 bytes.\n\t\t\"\"\"\n\t\tENCRYPT = des.ENCRYPT\n\t\tDECRYPT = des.DECRYPT\n\t\tdata = self._guardAgainstUnicode(data)\n\t\tif pad is not None:\n\t\t\tpad = self._guardAgainstUnicode(pad)\n\t\t# Pad the data accordingly.\n\t\tdata = self._padData(data, pad, padmode)\n\t\tif self.getMode() == CBC:\n\t\t\tself.__key1.setIV(self.getIV())\n\t\t\tself.__key2.setIV(self.getIV())\n\t\t\tself.__key3.setIV(self.getIV())\n\t\t\ti = 0\n\t\t\tresult = []\n\t\t\twhile i < len(data):\n\t\t\t\tblock = self.__key1.crypt(data[i:i+8], ENCRYPT)\n\t\t\t\tblock = self.__key2.crypt(block, DECRYPT)\n\t\t\t\tblock = self.__key3.crypt(block, ENCRYPT)\n\t\t\t\tself.__key1.setIV(block)\n\t\t\t\tself.__key2.setIV(block)\n\t\t\t\tself.__key3.setIV(block)\n\t\t\t\tresult.append(block)\n\t\t\t\ti += 8\n\t\t\tif _pythonMajorVersion < 3:\n\t\t\t\treturn ''.join(result)\n\t\t\telse:\n\t\t\t\treturn bytes.fromhex('').join(result)\n\t\telse:\n\t\t\tdata = self.__key1.crypt(data, ENCRYPT)\n\t\t\tdata = self.__key2.crypt(data, DECRYPT)\n\t\t\treturn self.__key3.crypt(data, ENCRYPT)\n\n\tdef decrypt(self, data, pad=None, padmode=None):\n\t\t\"\"\"decrypt(data, [pad], [padmode]) -> bytes\n\n\t\tdata : bytes to be encrypted\n\t\tpad  : Optional argument for decryption padding. Must only be one byte\n\t\tpadmode : Optional argument for overriding the padding mode.\n\n\t\tThe data must be a multiple of 8 bytes and will be decrypted\n\t\twith the already specified key. In PAD_NORMAL mode, if the\n\t\toptional padding character is supplied, then the un-encrypted\n\t\tdata will have the padding characters removed from the end of\n\t\tthe bytes. This pad removal only occurs on the last 8 bytes of\n\t\tthe data (last data block). In PAD_PKCS5 mode, the special\n\t\tpadding end markers will be removed from the data after\n\t\tdecrypting, no pad character is required for PAD_PKCS5.\n\t\t\"\"\"\n\t\tENCRYPT = des.ENCRYPT\n\t\tDECRYPT = des.DECRYPT\n\t\tdata = self._guardAgainstUnicode(data)\n\t\tif pad is not None:\n\t\t\tpad = self._guardAgainstUnicode(pad)\n\t\tif self.getMode() == CBC:\n\t\t\tself.__key1.setIV(self.getIV())\n\t\t\tself.__key2.setIV(self.getIV())\n\t\t\tself.__key3.setIV(self.getIV())\n\t\t\ti = 0\n\t\t\tresult = []\n\t\t\twhile i < len(data):\n\t\t\t\tiv = data[i:i+8]\n\t\t\t\tblock = self.__key3.crypt(iv,    DECRYPT)\n\t\t\t\tblock = self.__key2.crypt(block, ENCRYPT)\n\t\t\t\tblock = self.__key1.crypt(block, DECRYPT)\n\t\t\t\tself.__key1.setIV(iv)\n\t\t\t\tself.__key2.setIV(iv)\n\t\t\t\tself.__key3.setIV(iv)\n\t\t\t\tresult.append(block)\n\t\t\t\ti += 8\n\t\t\tif _pythonMajorVersion < 3:\n\t\t\t\tdata = ''.join(result)\n\t\t\telse:\n\t\t\t\tdata = bytes.fromhex('').join(result)\n\t\telse:\n\t\t\tdata = self.__key3.crypt(data, DECRYPT)\n\t\t\tdata = self.__key2.crypt(data, ENCRYPT)\n\t\t\tdata = self.__key1.crypt(data, DECRYPT)\n\t\treturn self._unpadData(data, pad, padmode)\n"
  },
  {
    "path": "universe/vncdriver/vnc_client.py",
    "content": "import collections\ntry:\n    import cStringIO as StringIO\nexcept ImportError:\n    from six import StringIO\nimport logging\nimport math\nimport numpy as np\nimport os\nfrom universe import pyprofile\nimport re\nimport struct\nimport zlib\n\nfrom twisted.internet import defer, protocol, threads\n\nfrom universe import utils\nfrom universe.twisty import reactor\nfrom universe.vncdriver import auth, constants, error, screen, server_messages\n\nlogger = logging.getLogger(__name__)\n\n# pyprofile.profile.print_frequency = 1\n# pyprofile.profile.print_filter = lambda event: event.startswith('vncdriver.recv_rectangle')\n\nclass UnknownEncoding(Exception):\n    pass\n\ndef peer_address(peer):\n    return '{}:{}'.format(peer.host, peer.port)\n\nclass Framebuffer(object):\n    def __init__(self, width, height, server_pixel_format, name):\n        # self.observer = observer\n\n        self.width = width\n        self.height = height\n        self.name = name\n\n        self.numpy_screen = screen.NumpyScreen(width, height)\n        self.apply_format(server_pixel_format)\n\n    def apply_format(self, server_pixel_format):\n        self.server_pixel_format = server_pixel_format\n        (self.bpp, self.depth, self.bigendian, self.truecolor,\n         self.redmax, self.greenmax, self.bluemax,\n         self.redshift, self.greenshift, self.blueshift) = \\\n           struct.unpack('!BBBBHHHBBBxxx', server_pixel_format)\n\n        # x11vnc will set truecolor == 0 by default. We just have to\n        # hope the client will override it.\n        #\n        # assert self.bigendian == 0\n        # Don't want to deal with colormaps...\n        # assert self.truecolor == 1\n\n        # Derived values\n        self.bypp = self.bpp // 8 # bytes per pixel\n\n        shifts = [self.redshift, self.greenshift, self.blueshift]\n        assert set(shifts) == set([0, 8, 16]), 'Surprising pixelformat: {}'.format(self.__dict__)\n        # How to cycle pixels from images to get RGB\n        self.color_cycle = np.argsort(shifts)\n        self.server_init = struct.pack('!HH16sI', self.width, self.height, self.server_pixel_format, len(self.name)) + self.name\n\n        self.numpy_screen.color_cycle = self.color_cycle\n\nclass VNCClient(protocol.Protocol, object):\n    def __init__(self):\n        self.numpy_screen = None\n\n        self.buf = []\n        self.buf_len = 0\n\n        self.initialized = False\n\n        # These could be passed around in\n        # expected_args/expected_kwargs, but they are needed in so\n        # many places it'd become confusing.\n        self._remaining_rectangles = None\n        self._rectangles = None\n\n        self._pause = False\n\n        self.expect(self.recv_ProtocolVersion_Handshake, 12)\n\n        self._close = False\n        self.zlib_decompressor = zlib.decompressobj()\n\n        self._pointer_x = None\n        self._pointer_y = None\n\n    def connectionLost(self, reason):\n        if not self._close:\n            logger.info('Server %s hung up: %s', peer_address(self.transport.getPeer()), reason)\n            self._error(error.Error('[{}] Lost connection: {}'.format(self.factory.label, reason)))\n\n    def sendMessage(self, data):\n        pyprofile.incr('vnc_client.data.sent.messages')\n        pyprofile.incr('vnc_client.data.sent.bytes', len(data), unit=pyprofile.BYTES)\n        if self.transport:\n            self.transport.write(data)\n\n    def dataReceived(self, data):\n        pyprofile.incr('vnc_client.data.received.messages')\n        pyprofile.incr('vnc_client.data.received.bytes', len(data), unit=pyprofile.BYTES)\n\n        self.buf.append(data)\n        self.buf_len += len(data)\n        logger.debug('Received data: %s bytes (brings us to %s total)', len(data), self.buf_len)\n\n        self.flush()\n\n    def flush(self):\n        if self.buf_len < self.expected_len:\n            return\n        elif self._pause:\n            # Not strictly needed, but short circuits in case we're\n            # paused for a while.\n            return\n        elif self._close:\n            return\n\n        buffer = b''.join(self.buf)\n        while len(buffer) >= self.expected_len:\n            logger.debug('Remaining in buffer: %s bytes', len(buffer))\n            if self._pause:\n                logger.debug('Pausing with %s bytes left in the buffer', len(buffer))\n                break\n            block, buffer = buffer[:self.expected_len], buffer[self.expected_len:]\n            if not self.handle(self.expected, block):\n                logger.debug('Stopping due to error in handle()')\n                buffer = block + buffer\n                break\n\n        self.buf[:] = [buffer]\n        self.buf_len = len(buffer)\n\n    def handle(self, type, block):\n        logger.debug('Handling server event: type=%s', type.__name__)\n        try:\n            self.expected(block, *self.expected_args, **self.expected_kwargs)\n            return True\n        except Exception as e:\n            self._error(e)\n            return False\n\n    def recv_ProtocolVersion_Handshake(self, block):\n        match = re.search(b'^RFB (\\d{3}).(\\d{3})\\n$', block)\n        assert match, 'Expected RFB line, but got: {!r}'.format(block)\n        major = int(match.group(1))\n        minor = int(match.group(2))\n        self.sendMessage(b'RFB 003.003\\n')\n\n        self.expect(self.recv_Security_Handshake, 4)\n\n    def recv_Security_Handshake(self, block):\n        (auth,) = struct.unpack('!I', block)\n        if auth == 0:\n            self.expect(self.recv_SecurityResult_Handshake_failed_length, 4)\n        elif auth == 1:\n            self.send_ClientInit()\n        elif auth == 2:\n            self.expect(self.recv_VNC_Authentication, 16)\n        else:\n            assert False, 'Bad auth: {}'.format(auth)\n\n    def recv_SecurityResult_Handshake(self, block):\n        (result,) = struct.unpack('!xxxB', block)\n        if result == 0:\n            logger.debug('VNC Auth succeeded')\n            self.send_ClientInit()\n        elif result == 1:\n            logger.debug('VNC Auth failed.')\n            # Server optionally can say why\n            self.expect(self.recv_SecurityResult_Handshake_failed_length, 4)\n        else:\n            assert False, 'Bad security result: {}'.format(result)\n\n    def recv_SecurityResult_Handshake_failed_length(self, block):\n        (length,) = struct.unpack('!I', block)\n        self.expect(self.recv_SecurityResult_Handshake_failed_reason, length)\n\n    def recv_SecurityResult_Handshake_failed_reason(self, block):\n        logger.info('Connection to server failed: %s', block)\n\n    def recv_VNC_Authentication(self, block):\n        response = auth.challenge_response(block)\n        self.sendMessage(response)\n        self.expect(self.recv_SecurityResult_Handshake, 4)\n\n    def send_ClientInit(self):\n        shared = True\n        self.sendMessage(struct.pack('!B', shared))\n        self.expect(self.recv_ServerInit, 24)\n\n    def recv_ServerInit(self, block):\n        # This can be rewritten, so don't proxy immediately\n        (width, height, server_pixel_format, namelen) = struct.unpack('!HH16sI', block)\n        self.expect(self.recv_ServerInit_name, namelen, width, height, server_pixel_format)\n\n    def recv_ServerInit_name(self, block, width, height, server_pixel_format):\n        self.framebuffer = Framebuffer(width, height, server_pixel_format, block)\n        self.numpy_screen = self.framebuffer.numpy_screen\n\n        self.initialized = True\n        self.send_PixelFormat()\n        self.send_SetEncodings([\n            constants.ZRLE_ENCODING,\n            constants.ZLIB_ENCODING,\n            constants.RAW_ENCODING,\n        ])\n        self.send_FramebufferUpdateRequest(incremental=1)\n\n        if self.factory.deferred:\n            self.factory.deferred.callback(self)\n\n        # All connected!\n        self.expect(self.recv_ServerToClient, 1)\n\n    def recv_ServerToClient(self, block):\n        (message_type,) = struct.unpack('!B', block)\n        if message_type == 0:\n            # self.observer.server_data_block(block)\n            self.expect(self.recv_FramebufferUpdate, 3)\n        elif message_type == 1:\n            # self.observer.server_data_block(block)\n            self.expect(self.recv_SetColorMapEntries, 5)\n        elif message_type == 2:\n            # self.observer.server_data_block(block)\n            # self.observer.server_bell()\n            self.expect(self.recv_ServerToClient, 1)\n        elif message_type == 3:\n            # Just drop ServerCutText messages\n            self.expect(self.recv_ServerCutText, 7)\n        else:\n            assert False, 'Unknown server to client message type received: {}'.format(message_type)\n\n    def recv_FramebufferUpdate(self, block):\n        (number_of_rectangles, ) = struct.unpack('!xH', block)\n        logger.debug('Receiving %d rectangles', number_of_rectangles)\n        pyprofile.incr('vncdriver.framebuffer_update')\n        pyprofile.incr('vncdriver.framebuffer_update.number_of_rectangles', number_of_rectangles)\n        self._remaining_rectangles = number_of_rectangles\n        self._rectangles = []\n\n        self._process_rectangles()\n\n    def _process_rectangles(self):\n        if self._remaining_rectangles > 0:\n            self.expect(self.recv_Rectangle, 12)\n        else:\n            framebuffer_update = server_messages.FramebufferUpdate(self._rectangles)\n            self.numpy_screen.apply(framebuffer_update)\n            self._remaining_rectangles = None\n            self._rectangles = None\n\n            # Once you're done, send another framebufferUpdateRequest.\n            #\n            # Empirically, after a few framebufferUpdateRequest's without\n            # any changes, Xvnc will hold off on sending another\n            # framebuffer update until the display data changes.\n            self.send_FramebufferUpdateRequest(incremental=1)\n            self.expect(self.recv_ServerToClient, 1)\n\n    def recv_Rectangle(self, block):\n        self._remaining_rectangles -= 1\n\n        (x, y, width, height, encoding) = struct.unpack('!HHHHi', block)\n\n        if encoding == constants.RAW_ENCODING:\n            self.expect(self.recv_DecodeRAW, width*height*self.framebuffer.bypp, x, y, width, height)\n        elif encoding == constants.ZRLE_ENCODING:\n            self.expect(self.recv_DecodeZRLE, 4, x, y, width, height)\n        elif encoding == constants.ZLIB_ENCODING:\n            self.expect(self.recv_DecodeZlib, 4, x, y, width, height)\n        elif encoding == constants.PSEUDO_CURSOR_ENCODING:\n            length = width * height * self.framebuffer.bypp\n            length += int(math.floor((width + 7.0) / 8)) * height\n            self.expect(self.recv_DecodePseudoCursor, length, x, y, width, height)\n        else:\n            raise UnknownEncoding('Unknown pixel encoding received: {}'.format(encoding))\n\n    # Encodings\n\n    def recv_DecodePseudoCursor(self, block, x, y, width, height):\n        # cf https://github.com/sibson/vncdotool/blob/master/vncdotool/rfb.py\n        rectangle = server_messages.PseudoCursorEncoding.parse_rectangle(self, x, y, width, height, block)\n        self._rectangles.append(rectangle)\n        self._process_rectangles()\n\n    def recv_DecodeRAW(self, block, x, y, width, height):\n        pyprofile.incr('vncdriver.recv_rectangle.raw_encoding')\n        pyprofile.incr('vncdriver.recv_rectangle.raw_encoding.bytes', len(block), unit=pyprofile.BYTES)\n        rectangle = server_messages.RAWEncoding.parse_rectangle(self, x, y, width, height, block)\n        self._rectangles.append(rectangle)\n        self._process_rectangles()\n\n    def recv_DecodeZRLE(self, block, x, y, width, height):\n        pyprofile.incr('vncdriver.recv_rectangle.zrle_encoding')\n        pyprofile.incr('vncdriver.recv_rectangle.zrle_encoding.bytes', len(block), unit=pyprofile.BYTES)\n\n        (length,) = struct.unpack('!I', block)\n        self.expect(self.recv_DecodeZRLE_value, length, x, y, width, height)\n\n    def recv_DecodeZRLE_value(self, block, x, y, width, height):\n        pyprofile.incr('vncdriver.recv_rectangle.zrle_encoding.bytes', len(block), unit=pyprofile.BYTES)\n        rectangle = server_messages.ZRLEEncoding.parse_rectangle(self, x, y, width, height, block)\n        self._rectangles.append(rectangle)\n        self._process_rectangles()\n\n    def recv_DecodeZlib(self, block, x, y, width, height):\n        pyprofile.incr('vncdriver.recv_rectangle.zlib_encoding')\n        pyprofile.incr('vncdriver.recv_rectangle.zlib_encoding.bytes', len(block), unit=pyprofile.BYTES)\n\n        (length,) = struct.unpack('!I', block)\n        self.expect(self.recv_DecodeZlib_value, length, x, y, width, height)\n\n    def recv_DecodeZlib_value(self, block, x, y, width, height):\n        pyprofile.incr('vncdriver.recv_rectangle.zlib_encoding.bytes', len(block), unit=pyprofile.BYTES)\n        rectangle = server_messages.ZlibEncoding.parse_rectangle(self, x, y, width, height, block)\n        self._rectangles.append(rectangle)\n        self._process_rectangles()\n\n    def recv_SetColorMapEntries(self, block):\n        # self.observer.server_data_block(block)\n\n        (first_color, number_of_colors) = struct.unpack('!xHH', block)\n        self._handle_SetColorMapEntries(first_color, number_of_colors, [])\n\n    def _handle_SetColorMapEntries(self, first_color, number_of_colors, colors):\n        if number_of_colors > 0:\n            self.expect(self.recv_SetColorMapEntries_color, 6, first_color, number_of_colors-1, colors)\n        else:\n            # self.observer.server_set_color_map_entries(first_color, colors)\n            self.expect(self.recv_ServerToClient, 1)\n\n    def recv_SetColorMapEntries_color(self, block, first_color, number_of_colors, colors):\n        # self.observer.server_data_block(block)\n\n        red, green, blue = struct.unpack('!HHH', block)\n        colors.append((red, green, blue))\n        self._handle_SetColorMapEntries(first_color, number_of_colors, colors)\n\n    def recv_ServerCutText(self, block):\n        # We drop these messages\n        (length,) = struct.unpack('!xxxI', block)\n        self.expect(self.recv_ServerCutText_value, length)\n\n    def recv_ServerCutText_value(self, block):\n        # We drop these messages\n        # self.observer.server_cut_text(block)\n        self.expect(self.recv_ServerToClient, 1)\n\n    def send_SetEncodings(self, encodings):\n        self.sendMessage(struct.pack(\"!BxH\", 2, len(encodings)))\n        for encoding in encodings:\n            self.sendMessage(struct.pack(\"!i\", encoding))\n\n    def send_PixelFormat(self, bpp=32, depth=24, bigendian=0, truecolor=1, redmax=255, greenmax=255, bluemax=255, redshift=0, greenshift=8, blueshift=16):\n        if not self.initialized:\n            # Not too bad to add, but no need right now. (We'd need to\n            # make sure the framebuffer settings don't get\n            # overridden.)\n            raise error.Error('Framebuffer not initialized. We have not yet added support for queuing PixelFormat messages before initialization')\n        server_pixel_format = struct.pack(\"!BBBBHHHBBBxxx\", bpp, depth, bigendian, truecolor, redmax, greenmax, bluemax, redshift, greenshift, blueshift)\n        self.sendMessage(struct.pack(\"!Bxxx16s\", 0, server_pixel_format))\n        self.framebuffer.apply_format(server_pixel_format)\n\n    def send_FramebufferUpdateRequest(self, x=0, y=0, width=None, height=None, incremental=0):\n        if not self.initialized:\n            # Not too bad to add, but no need right now. (We'd need to\n            # calculate the message after the framebuffer is\n            # initialized.)\n            raise error.Error('Framebuffer not initialized. We have not yet added support for queuing FramebufferUpdateRequest messages before initialization')\n        if width is None:\n            width  = self.framebuffer.width - x\n        if height is None:\n            height = self.framebuffer.height - y\n        self.sendMessage(struct.pack(\"!BBHHHH\", 3, incremental, x, y, width, height))\n\n    def send_KeyEvent(self, key, down):\n        \"\"\"For most ordinary keys, the \"keysym\" is the same as the\n        corresponding ASCII value.  Other common keys are shown in the\n        KEY_ constants.\n        \"\"\"\n        self.sendMessage(struct.pack('!BBxxI', 4, down, key))\n\n    def send_PointerEvent(self, x, y, buttonmask=0):\n        \"\"\"Indicates either pointer movement or a pointer button press or\n           release. The pointer is now at (x-position, y-position),\n           and the current state of buttons 1 to 8 are represented by\n           bits 0 to 7 of button-mask respectively, 0 meaning up, 1\n           meaning down (pressed).\n        \"\"\"\n        self.sendMessage(struct.pack('!BBHH', 5, buttonmask, x, y))\n\n    def send_ClientCutText(self, message):\n        \"\"\"The client has new text in its clipboard.\n        \"\"\"\n        self.sendMessage(struct.pack(\"!BxxxI\", 6, len(message)))\n        self.sendMessage(message)\n\n    def expect(self, type, length, *args, **kwargs):\n        logger.debug('Expecting: %s (length=%s)', type.__name__, length)\n        assert isinstance(length, int), \"Bad length (not an int): {}\".format(length)\n\n        self.expected = type\n        self.expected_len = length\n        self.expected_args = args\n        self.expected_kwargs = kwargs\n\n    def close(self):\n        self._close = True\n        if self.transport:\n            self.transport.loseConnection()\n\n    def _error(self, e):\n        self.close()\n        self.factory.error_buffer.record(e)\n        if self.factory.deferred:\n            try:\n                self.factory.deferred.errback(utils.format_error(e))\n            except defer.AlreadyCalledError:\n                pass\n\ndef client_factory(deferred, error_buffer):\n    factory = protocol.ClientFactory()\n    factory.deferred = deferred\n    factory.error_buffer = error_buffer\n    factory.protocol = VNCClient\n    return factory\n"
  },
  {
    "path": "universe/vncdriver/vnc_proxy_server.py",
    "content": "import logging\nimport os\nimport re\nimport shutil\nimport struct\nimport time\nimport traceback\n\nfrom universe import pyprofile\nfrom universe.vncdriver import auth, constants, fbs_writer\nfrom twisted.internet import defer, endpoints, protocol, reactor\n\nlogger = logging.getLogger(__name__)\n\nclass LogManager(object):\n    def __init__(self, base_logfile_dir, recorder_id, id):\n        self.base_logfile_dir = base_logfile_dir\n        self.recorder_id = recorder_id\n        self.id = id\n\n        self.logfile_dir = os.path.join(self.base_logfile_dir, '{}-{}-{}'.format(int(time.time()), self.recorder_id, str(self.id)))\n\n        logger.info('[vnc_proxy] logfile_dir = %s', self.logfile_dir)\n        # Make the logfile directory that will be written to\n        if not os.path.isdir(self.logfile_dir):\n            logger.info('[vnc_proxy] [%s] Creating log directory %s', self.id, self.logfile_dir)\n            os.makedirs(self.logfile_dir)\n\n    @property\n    def global_rewards_logfile(self):\n        \"\"\"\n        We assume that there is only a single rewards file that is ever written to.\n        This is enforced by the reward_recorder that limits connections to one\n        \"\"\"\n        return '/tmp/demo/rewards.demo'\n\n    @property\n    def global_botaction_logfile(self):\n        \"\"\"\n        We assume that there is only a single botactions file that is ever written to.\n        This is enforced by the botaction_recorder that appends everything to one file\n        \"\"\"\n        return '/tmp/demo/botactions.jsonl'\n\n\n    @property\n    def global_env_id_file(self):\n        \"\"\"\n        We assume that there is only a single rewards file that is ever written to.\n        This is enforced by the reward_recorder that limits connections to one\n        \"\"\"\n        return '/tmp/demo/env_id.txt'\n\n    @property\n    def server_logfile(self):\n        return os.path.join(self.logfile_dir, 'server.fbs')\n\n    @property\n    def client_logfile(self):\n        return os.path.join(self.logfile_dir, 'client.fbs')\n\n    def close(self):\n        logger.info(\"[%s] Copying rewards.demo into this connection's log dir\", self.id)\n\n        if os.path.exists(self.global_rewards_logfile):\n            # Each recording includes all the rewards that we've seen. We count on the player to\n            # crop them to only contain the ones that occurred during this recording\n\n            # TODO: Upload to S3 immediately upon disconnect\n            shutil.copyfile(self.global_rewards_logfile, os.path.join(self.logfile_dir, 'rewards.demo'))\n        else:\n            logger.info(\"%s does not exist; not copying into recording directory\", self.global_rewards_logfile)\n\n        if os.path.exists(self.global_botaction_logfile):\n            shutil.copyfile(self.global_botaction_logfile, os.path.join(self.logfile_dir, 'botactions.jsonl'))\n        else:\n            logger.info(\"%s does not exist; not copying into recording directory\", self.global_botaction_logfile)\n\n\n        if os.path.exists(self.global_env_id_file):\n            shutil.copyfile(self.global_env_id_file, os.path.join(self.logfile_dir, 'env_id.txt'))\n        else:\n            logger.info(\"%s does not exist; not copying into recording directory\", self.global_env_id_file)\n\n        if os.environ.get('COMPLETED_DEMONSTRATION_DIR'):\n            dest = os.path.join(os.environ['COMPLETED_DEMONSTRATION_DIR'], os.path.basename(self.logfile_dir))\n            logger.info('copying to %s', dest)\n            shutil.copytree(self.logfile_dir, dest)\n            shutil.copystat(self.logfile_dir, dest)\n\n\nclass VNCProxyServer(protocol.Protocol, object):\n    \"\"\"Bytes received from the end user. (So received data are mostly\n    actions.)\"\"\"\n\n    _next_id = 0\n\n    SUPPORTED_ENCODINGS = {\n        # Maybe we can do copy-rect at some point. May not help with\n        # much though.\n        # constants.COPY_RECTANGLE_ENCODING,\n        constants.TIGHT_ENCODING,\n        constants.RAW_ENCODING,\n        constants.ZLIB_ENCODING,\n        # constants.HEXTILE_ENCODING,\n        # constants.CORRE_ENCODING,\n        # constants.RRE_ENCODING,\n        constants.PSEUDO_CURSOR_ENCODING\n    }\n\n    if os.getenv('VNC_ENCODINGS'):\n        for enc in os.getenv('VNC_ENCODINGS').split():\n            SUPPORTED_ENCODINGS.add(getattr(constants, enc.upper() + '_ENCODING'))\n    add_pseudo_cursor_encoding = True\n    if os.getenv('VNC_ENCODINGS_NO_ADD_PSEUDO_CURSOR_ENCODING'):\n        add_pseudo_cursor_encoding = False\n\n    # ZRLE format is much smaller, but slower to read.\n    # SUPPORTED_ENCODINGS.add(constants.ZRLE_ENCODING)\n\n    @classmethod\n    def next_id(cls):\n        id = cls._next_id\n        cls._next_id += 1\n        return id\n\n    def __init__(self, action_queue=None, error_buffer=None, enable_logging=True):\n        self.id = self.next_id()\n\n        self.server_log = None\n        self.action_queue = action_queue\n        self.error_buffer = error_buffer\n        self.server_log_buffer = []\n        self.enable_logging = enable_logging\n\n        self._broken = False\n        self.vnc_client = None\n        self.log_manager = None\n\n        self.buf = []\n        self.buf_len = 0\n\n        self.queued_data = []\n        self.initialized = False\n\n        self.challenge = auth.challenge()\n        self.accept_any_password = True\n        self.expect(self.recv_ProtocolVersion_Handshake, 12)\n\n    def start_logging(self):\n        self.log_manager = LogManager(self.factory.logfile_dir, self.factory.recorder_id, self.id)\n        self.server_log = fbs_writer.FBSWriter(self.log_manager.server_logfile)\n\n        for data in self.server_log_buffer:\n            self.server_log.write(data)\n        # Done with the buffer!\n        self.server_log_buffer = None\n\n\n    def connectionMade(self):\n        logger.info('[%s] Connection received from VNC client', self.id)\n        factory = protocol.ClientFactory()\n        factory.protocol = VNCProxyClient\n        factory.vnc_server = self\n        factory.deferrable = defer.Deferred()\n        endpoint = endpoints.clientFromString(reactor, self.factory.vnc_address)\n\n        def _established_callback(client):\n            if self._broken:\n                client.close()\n            self.vnc_client = client\n            self.flush()\n        def _established_errback(reason):\n            logger.error('[VNCProxyServer] Connection succeeded but could not establish session: %s', reason)\n            self.close()\n        factory.deferrable.addCallbacks(_established_callback, _established_errback)\n\n        def _connect_errback(reason):\n            logger.error('[VNCProxyServer] Connection failed: %s', reason)\n            self.close()\n        endpoint.connect(factory).addErrback(_connect_errback)\n\n        self.send_ProtocolVersion_Handshake()\n\n    def connectionLost(self, reason):\n        logger.info('Losing connection from VNC user')\n        if self.vnc_client:\n            self.vnc_client.close()\n\n    def dataReceived(self, data):\n        pyprofile.incr('vnc_proxy_server.data.sent.messages')\n        pyprofile.incr('vnc_proxy_server.data.sent.bytes', len(data))\n\n        self.buf.append(data)\n        self.buf_len += len(data)\n        self.flush()\n\n    def sendData(self, data):\n        if self.server_log is None:\n            self.server_log_buffer.append(data)\n        else:\n            self.server_log.write(data)\n        self.transport.write(data)\n\n    def flush(self):\n        if self.buf_len < self.expected_len:\n            return\n        elif self.vnc_client is None and self.action_queue is None:\n            return\n\n        buffer = b''.join(self.buf)\n        while not self._broken and len(buffer) >= self.expected_len:\n            block, buffer = buffer[:self.expected_len], buffer[self.expected_len:]\n            self.handle(self.expected, block)\n\n        self.buf[:] = [buffer]\n        self.buf_len = len(buffer)\n\n    def handle(self, type, block):\n        logger.debug('[%s] Handling: type=%s', self.id, type)\n        try:\n            self.expected(block, *self.expected_args, **self.expected_kwargs)\n        except Exception as e:\n            self._error(e)\n\n    def send_ProtocolVersion_Handshake(self):\n        self.sendData(b'RFB 003.003\\n')\n\n    def recv_ProtocolVersion_Handshake(self, block):\n        # Client chooses RFB version\n        match = re.search(b'^RFB (\\d{3}).(\\d{3})\\n$', block)\n        assert match, 'Block does not match: {!r}'.format(block)\n        major = int(match.group(1))\n        minor = int(match.group(2))\n        self.protocol_version = (major, minor)\n        assert major == 3 and minor in (3, 8), 'Unexpected version: {}'.format((major, minor))\n\n        if minor == 3:\n            self.send_VNC_Authentication()\n        elif minor == 8:\n            self.send_SecurityTypes()\n\n    def send_SecurityTypes(self):\n        self.sendData(struct.pack('!BB', 1, 2))\n        self.expect(self.recv_SecurityTypesResponse, 1)\n\n    def recv_SecurityTypesResponse(self, block):\n        (type,) = struct.unpack('!B', block)\n        assert type == 2\n        self.send_VNC_Authentication()\n\n    def send_VNC_Authentication(self):\n        # Now we tell the client to auth with password. (Only do this\n        # because the built-in Mac viewer prompts for a password no\n        # matter what.)\n        self.sendData(struct.pack('!I', 2))\n        self.sendData(self.challenge)\n        self.expect(self.recv_VNC_Authentication_response, 16)\n\n    def recv_VNC_Authentication_response(self, block):\n        expected = auth.challenge_response(self.challenge)\n        if block == expected or self.accept_any_password:\n            logger.debug('Client authenticated successfully')\n            self.send_SecurityResult_Handshake_success()\n        else:\n            logger.debug('VNC client supplied incorrect password')\n            self.send_SecurityResult_Handshake_failed('Your password was incorrect')\n\n    def send_SecurityResult_Handshake_success(self):\n        logger.debug('[%s] Send SecurityResult_Handshake_success', self.id)\n        self.sendData(struct.pack('!I', 0))\n        self.expect(self.recv_ClientInit, 1)\n\n    def send_SecurityResult_Handshake_failed(self, reason):\n        self.sendData(struct.pack('!I', 1))\n        self.sendData(struct.pack('!I', len(reason)))\n        self.sendData(reason)\n        self.close()\n\n    def recv_ClientInit(self, block):\n        (shared,) = struct.unpack('!B', block)\n\n        ### Now that the server is up and running, we flush\n        ### everything.\n\n        # We don't even create log directory until we've successfully\n        # established the connection.\n\n        if self.enable_logging and self.factory.logfile_dir:\n            # Log in vnc_recorder; don't log in playback\n            self.start_logging()\n            self.vnc_client.start_logging()\n\n        for data in self.queued_data:\n            self.sendData(data)\n        self.queued_data = None\n        self.initialized = True\n\n        # Listen for messages\n        self.expect(self.recv_ClientToServer, 1)\n\n    def recv_ClientToServer(self, block):\n        (message_type,) = struct.unpack('!B', block)\n        if message_type == 0:\n            self.proxyData(block)\n            self.expect(self.recv_SetPixelFormat, 19)\n        elif message_type == 2:\n            # Do not proxy since we want to transform it\n            self.expect(self.recv_SetEncodings, 3)\n        elif message_type == 3:\n            self.proxyData(block)\n            self.expect(self.recv_FramebufferUpdateRequest, 9)\n        elif message_type == 4:\n            self.proxyData(block)\n            self.expect(self.recv_KeyEvent, 7)\n        elif message_type == 5:\n            self.proxyData(block)\n            self.expect(self.recv_PointerEvent, 5)\n        elif message_type == 6:\n            # Do not proxy since we don't support it\n            self.expect(self.recv_ClientCutText, 7)\n        else:\n            assert False, 'Unknown client to server message type received: {}'.format(message_type)\n\n    def recv_SetPixelFormat(self, block):\n        self.proxyData(block)\n\n        (server_pixel_format,) = struct.unpack('!xxx16s', block)\n\n        if self.action_queue:\n            self.action_queue.set_pixel_format(server_pixel_format)\n\n        # self.vnc_client.framebuffer.apply_format(server_pixel_format)\n        self.expect(self.recv_ClientToServer, 1)\n\n    def recv_SetEncodings(self, block):\n        # Do not proxy, as we will write our own transformed version\n        # of this shortly.\n\n        (number_of_encodings,) = struct.unpack('!xH', block)\n        self._handle_SetEncodings(number_of_encodings, [])\n\n    def _handle_SetEncodings(self, number_of_encodings, encodings):\n        if number_of_encodings > 0:\n            self.expect(self.recv_SetEncodings_encoding_type, 4, number_of_encodings-1, encodings)\n        else:\n            supported = []\n            unsupported = []\n            for encoding in encodings:\n                if encoding in self.SUPPORTED_ENCODINGS:\n                    supported.append(encoding)\n                else:\n                    unsupported.append(encoding)\n\n            if unsupported:\n                logger.info('[%s] Requested %s unsupported encodings: unsupported=%s supported=%s', self.id, len(unsupported), unsupported, supported)\n\n            if self.add_pseudo_cursor_encoding and constants.PSEUDO_CURSOR_ENCODING not in supported:\n                logger.info('[%s] Add PSEUDO_CURSOR_ENCODING', self.id)\n                supported.append(constants.PSEUDO_CURSOR_ENCODING)\n\n            logger.debug('[%s] Encodings: %s', self.id, supported)\n            if self.vnc_client:\n                self.vnc_client.send_SetEncodings(supported)\n            self.expect(self.recv_ClientToServer, 1)\n\n    def recv_SetEncodings_encoding_type(self, block, number_of_encodings, encodings):\n        # Do not proxy, as we will write our own transformed version\n        # of this shortly.\n\n        (encoding,) = struct.unpack('!i', block)\n        encodings.append(encoding)\n        self._handle_SetEncodings(number_of_encodings, encodings)\n\n    def recv_FramebufferUpdateRequest(self, block):\n        self.proxyData(block)\n\n        incremental, x, y, width, height = struct.unpack('!BHHHH', block)\n        self.expect(self.recv_ClientToServer, 1)\n\n    def recv_KeyEvent(self, block):\n        self.proxyData(block)\n\n        down, key = struct.unpack('!BxxI', block)\n        if self.action_queue is not None:\n            self.action_queue.key_event(key, down)\n        self.expect(self.recv_ClientToServer, 1)\n\n    def recv_PointerEvent(self, block):\n        self.proxyData(block)\n\n        buttonmask, x, y = struct.unpack('!BHH', block)\n        if self.action_queue is not None:\n            self.action_queue.pointer_event(x, y, buttonmask)\n        self.expect(self.recv_ClientToServer, 1)\n\n    def recv_ClientCutText(self, block):\n        # Drop ClientCutText\n\n        (length,) = struct.unpack('!xxxI', block)\n        self.expect(self.recv_ClientCutText_value, length)\n\n    def recv_ClientCutText_value(self, block):\n        # Drop ClientCutText\n\n        self.expect(self.recv_ClientToServer, 1)\n\n    def expect(self, type, length, *args, **kwargs):\n        self.expected = type\n        self.expected_len = length\n        self.expected_args = args\n        self.expected_kwargs = kwargs\n\n    def proxyData(self, data):\n        if self.vnc_client:\n            self.vnc_client.recvProxyData(data)\n\n    def recvProxyData(self, data):\n        \"\"\"Write data to server\"\"\"\n        if self.initialized:\n            self.sendData(data)\n        else:\n            self.queued_data.append(data)\n\n    def close(self):\n        logger.info('[%s] Closing', self.id)\n        self._broken = True\n        if self.transport:\n            self.transport.loseConnection()\n        if self.log_manager:\n            self.log_manager.close()\n        if self.server_log:\n            self.server_log.close()\n\n    def _error(self, e):\n        logger.error('[%s] Connection from client aborting with error: %s', self.id, e)\n        traceback.print_exc()\n        if self.error_buffer:\n            self.error_buffer.record(e)\n        self.close()\n\nclass VNCProxyClient(protocol.Protocol, object):\n    def __init__(self):\n        self.id = None\n        self.vnc_server = None\n        self.client_log = None\n        # Messages heading for the server, which haven't been written\n        # to disk.\n        self.client_log_buffer = []\n        self.buf = []\n        self.buf_len = 0\n        self._broken = False\n\n        self.queued_data = []\n        self.initialized = False\n\n        self.expect(self.recv_ProtocolVersion_Handshake, 12)\n\n    def start_logging(self):\n        self.client_log = fbs_writer.FBSWriter(self.vnc_server.log_manager.client_logfile)\n        for data in self.client_log_buffer:\n            self.client_log.write(data)\n        # Done with the buffer!\n        self.client_log_buffer = None\n\n    def connectionMade(self):\n        logger.debug('Connection made to VNC server')\n        self.vnc_server = self.factory.vnc_server\n        self.id = '{}-client'.format(self.vnc_server.id)\n\n    def connectionLost(self, reason):\n        logger.info('Losing connection to VNC server')\n        if self.vnc_server:\n            self.vnc_server.close()\n\n    def proxyData(self, data):\n        \"\"\"Write data to client\"\"\"\n        assert self.initialized\n        self.vnc_server.recvProxyData(data)\n\n    def recvProxyData(self, data):\n        \"\"\"Write data to client\"\"\"\n        self.sendData(data)\n\n    def sendData(self, data):\n        \"\"\"Write data to server\"\"\"\n        # Not set up yet\n        if self.client_log is None:\n            self.client_log_buffer.append(data)\n        else:\n            self.client_log.write(data)\n        self.transport.write(data)\n\n    def dataReceived(self, data):\n        if self.expected is None:\n            # We're in direct proxy mode\n            self.proxyData(data)\n            return\n\n        pyprofile.incr('vnc_proxy_server.data.sent.messages')\n        pyprofile.incr('vnc_proxy_server.data.sent.bytes', len(data))\n\n        self.buf.append(data)\n        self.buf_len += len(data)\n        self.flush()\n\n    def flush(self):\n        if self.buf_len < self.expected_len:\n            return\n\n        buffer = b''.join(self.buf)\n        while self.expected is not None and not self._broken and len(buffer) >= self.expected_len:\n            block, buffer = buffer[:self.expected_len], buffer[self.expected_len:]\n            self.handle(self.expected, block)\n\n        self.buf[:] = [buffer]\n        self.buf_len = len(buffer)\n\n        if self.expected is None:\n            data = b''.join(self.buf)\n            if data != '':\n                self.proxyData(data)\n            self.buf = []\n\n    def handle(self, type, block):\n        logger.debug('[%s] Handling: type=%s', self.id, type)\n        try:\n            self.expected(block, *self.expected_args, **self.expected_kwargs)\n        except Exception as e:\n            self._error(e)\n\n    def recv_ProtocolVersion_Handshake(self, block):\n        match = re.search(b'^RFB (\\d{3}).(\\d{3})\\n$', block)\n        assert match, 'Expected RFB line, but got: {!r}'.format(block)\n        major = int(match.group(1))\n        minor = int(match.group(2))\n        self.sendData(b'RFB 003.003\\n')\n\n        self.expect(self.recv_Security_Handshake, 4)\n\n    def recv_Security_Handshake(self, block):\n        (auth,) = struct.unpack('!I', block)\n        if auth == 0:\n            self.expect(self.recv_SecurityResult_Handshake_failed_length, 4)\n        elif auth == 1:\n            self.send_ClientInit()\n        elif auth == 2:\n            self.expect(self.recv_VNC_Authentication, 16)\n        else:\n            assert False, 'Bad auth: {}'.format(auth)\n\n    def recv_VNC_Authentication(self, block):\n        response = auth.challenge_response(block)\n        self.sendData(response)\n        self.expect(self.recv_SecurityResult_Handshake, 4)\n\n    def recv_SecurityResult_Handshake(self, block):\n        (result,) = struct.unpack('!xxxB', block)\n        if result == 0:\n            logger.debug('VNC Auth succeeded')\n            self.send_ClientInit()\n        elif result == 1:\n            logger.debug('VNC Auth failed.')\n            # Server optionally can say why\n            self.expect(self.recv_SecurityResult_Handshake_failed_length, 4)\n        else:\n            assert False, 'Bad security result: {}'.format(result)\n\n    def recv_SecurityResult_Handshake_failed_length(self, block):\n        (length,) = struct.unpack('!I', block)\n        self.expect(self.recv_SecurityResult_Handshake_failed_reason, length)\n\n    def recv_SecurityResult_Handshake_failed_reason(self, block):\n        logger.info('Connection to server failed: %s', block)\n\n    def send_ClientInit(self):\n        shared = True\n        self.sendData(struct.pack('!B', shared))\n\n        ### Now that the session is up and running, we flush\n        ### everything and stop parsing.\n\n        # We're up and running!\n        logger.info('[%s] Marking server as connected', self.id)\n        self.factory.deferrable.callback(self)\n\n        self.initialized = True\n        # Flush queue\n        for data in self.queued_data:\n            self.sendData(data)\n        self.queued_data = None\n\n        # And from now on just do a straight proxy\n        self.expect(None, None)\n\n    def expect(self, type, length, *args, **kwargs):\n        if type is not None:\n            logger.debug('Expecting: %s (length=%s)', type.__name__, length)\n            assert isinstance(length, int), \"Bad length: {}\".format(length)\n\n        self.expected = type\n        self.expected_len = length\n        self.expected_args = args\n        self.expected_kwargs = kwargs\n\n    def close(self):\n        logger.info('[%s] Closing', self.id)\n        self._broken = True\n        if self.transport:\n            self.transport.loseConnection()\n        if self.client_log:\n            self.client_log.close()\n\n    def _error(self, e):\n        logger.error('[%s] Connection to server aborting with error: %s', self.id, e)\n        traceback.print_exc()\n        self.close()\n\n    def send_SetEncodings(self, encodings):\n        self.sendData(struct.pack(\"!BxH\", 2, len(encodings)))\n        for encoding in encodings:\n            self.sendData(struct.pack(\"!i\", encoding))\n"
  },
  {
    "path": "universe/vncdriver/vnc_session.py",
    "content": "import logging\n\nfrom twisted.internet import defer, endpoints\n\nfrom universe import error, utils\nfrom universe.twisty import reactor\nfrom universe.vncdriver import screen, vnc_client\n\nlogger = logging.getLogger(__name__)\n\nclass VNCSession(object):\n    def __init__(self, remotes, error_buffer):\n        self.remotes = remotes\n        self.error_buffer = error_buffer\n        self._pyglet_screen = None\n        self.connect()\n\n    def connect(self):\n        utils.blockingCallFromThread(self._connect)\n\n    def _connect(self):\n        deferreds = []\n\n        for i, remote in enumerate(self.remotes):\n            d = defer.Deferred()\n            deferreds.append(d)\n\n            factory = vnc_client.client_factory(d, self.error_buffer)\n            factory.rewarder_session = self\n            factory.label = 'vnc:{}:{}'.format(i, remote)\n            endpoint = endpoints.clientFromString(reactor, 'tcp:'+remote)\n\n            def success(i):\n                logger.info('[%s] VNC connection established', factory.label)\n\n            def fail(reason):\n                reason = error.Error('[{}] Connection failed: {}'.format(factory.label, reason.value))\n                try:\n                    d.errback(utils.format_error(reason))\n                except defer.AlreadyCalledError:\n                    pass\n            endpoint.connect(factory).addCallback(success).addErrback(fail)\n\n        d = defer.DeferredList(deferreds, fireOnOneErrback=True)\n\n        def success(results):\n            # Store the _clients list when connected\n            self._clients = [client for success, client in results]\n        d.addCallback(success)\n        return d\n\n    def flip(self):\n        observation_n = []\n        info_n = []\n        for i, client in enumerate(self._clients):\n            observation, info = client.numpy_screen.flip()\n            updates = info['vnc_session.framebuffer_updates']\n\n            # Keep the pyglet screen fed, but don't flip it until the user calls render\n            if i == 0 and self._pyglet_screen:\n                for update in updates:\n                    self._pyglet_screen.apply(update)\n\n            observation_n.append(observation)\n            info_n.append({'vnc.updates.n': len(updates)})\n\n        return observation_n, info_n\n\n    def peek(self):\n        observations = [client.numpy_screen.peek() for client in self._clients]\n        return observations\n\n    def step(self, action):\n        reactor.callFromThread(self._step, action)\n        return self.flip()\n\n    def _step(self, action):\n        try:\n            for a, client in zip(action, self._clients):\n                for event in a:\n                    if event[0] == 'KeyEvent':\n                        key, down = event[1:]\n                        client.send_KeyEvent(key, down)\n                    elif event[0] == 'PointerEvent':\n                        x, y, buttomask = event[1:]\n                        client.send_PointerEvent(x, y, buttomask)\n                    else:\n                        raise error.Error('Bad event type: {}'.format(type))\n        except Exception as e:\n            self.error_buffer.record(e)\n\n    def render(self):\n        if not self._pyglet_screen:\n            start = self.peek()[0]\n            self._pyglet_screen = screen.PygletScreen(start)\n        self._pyglet_screen.flip()\n\n    def close(self):\n        utils.blockingCallFromThread(self._close)\n\n    def _close(self):\n        if getattr(self, '_clients', None) is not None:\n            for client in self._clients:\n                client.close()\n            self._clients = None\n"
  },
  {
    "path": "universe/wrappers/__init__.py",
    "content": "import gym\nimport universe.wrappers.experimental\nfrom universe import envs, spaces\nfrom universe.wrappers import gym_core_sync\nfrom universe.wrappers.blocking_reset import BlockingReset\nfrom universe.wrappers.diagnostics import Diagnostics\nfrom universe.wrappers.gym_core import GymCoreAction, GymCoreObservation, CropAtari\nfrom universe.wrappers.joint import Joint\nfrom universe.wrappers.logger import Logger\nfrom universe.wrappers.monitoring import Monitor\nfrom universe.wrappers.multiprocessing_env import WrappedMultiprocessingEnv, EpisodeID\nfrom universe.wrappers.recording import Recording\nfrom universe.wrappers.render import Render\nfrom universe.wrappers.throttle import Throttle\nfrom universe.wrappers.time_limit import TimeLimit\nfrom universe.wrappers.timer import Timer\nfrom universe.wrappers.vectorize import Vectorize, Unvectorize, WeakUnvectorize\nfrom universe.wrappers.vision import Vision\n\n\ndef wrap(env):\n    return Timer(Render(Throttle(env)))\n\ndef WrappedVNCEnv():\n    return wrap(envs.VNCEnv())\n\ndef WrappedGymCoreEnv(gym_core_id, fps=None, rewarder_observation=False):\n    # Don't need to store the ID on the instance; it'll be retrieved\n    # directly from the spec\n    env = wrap(envs.VNCEnv(fps=fps))\n    if rewarder_observation:\n        env = GymCoreObservation(env, gym_core_id=gym_core_id)\n    return env\n\ndef WrappedGymCoreSyncEnv(gym_core_id, fps=60, rewarder_observation=False):\n    spec = gym.spec(gym_core_id)\n    env = gym_core_sync.GymCoreSync(BlockingReset(wrap(envs.VNCEnv(fps=fps))))\n    if rewarder_observation:\n        env = GymCoreObservation(env, gym_core_id=gym_core_id)\n    elif spec._entry_point.startswith('gym.envs.atari:'):\n        env = CropAtari(env)\n\n    return env\n\ndef WrappedFlashgamesEnv():\n    keysym = spaces.KeyEvent.by_name('`').key\n    return wrap(envs.VNCEnv(probe_key=keysym))\n\ndef WrappedInternetEnv(*args, **kwargs):\n    return wrap(envs.InternetEnv(*args, **kwargs))\n\ndef WrappedStarCraftEnv(*args, **kwargs):\n    return wrap(envs.StarCraftEnv(*args, **kwargs))\n\ndef WrappedGTAVEnv(*args, **kwargs):\n    return wrap(envs.GTAVEnv(*args, **kwargs))\n\ndef WrappedWorldOfGooEnv(*args, **kwargs):\n    return wrap(envs.WorldOfGooEnv(*args, **kwargs))\n"
  },
  {
    "path": "universe/wrappers/action_space.py",
    "content": "class SoftmaxClickMouse():\n    def init(self):\n        raise DeprecationWarning('DEPRECATION WARNING: wrappers.SoftmaxClickMouse has been moved to wrappers.experimental.action_space.SoftmaxClickMouse as of 2017-02-08.')\n\n\nclass SafeActionSpace():\n    def init(self):\n        raise DeprecationWarning('DEPRECATION WARNING: wrappers.SafeActionSpace has been moved to '\n                     'wrappers.experimental.action_space.SafeActionSpace as of 2017-01-07. '\n                     'Using legacy wrappers.SafeActionSpace will soon be removed')\n"
  },
  {
    "path": "universe/wrappers/blocking_reset.py",
    "content": "from universe import rewarder, spaces, vectorized\n\nclass BlockingReset(vectorized.Wrapper):\n    \"\"\"\nBy default, a reset in universe is not a blocking operation.  This \nwrapper changes it. \n\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        super(BlockingReset, self).__init__(*args, **kwargs)\n        self.reward_n = None\n        self.done_n = None\n        self.info = None\n\n    def _reset(self):\n        observation_n = self.env.reset()\n        self.reward_n = [0] * self.n\n        self.done_n = [False] * self.n\n        self.info = {'n': [{} for _ in range(self.n)]}\n\n        while any(ob is None for ob in observation_n):\n            action_n = []\n            for done in self.done_n:\n                if done:\n                    # No popping of reward/done. Don't want to merge across episode boundaries.\n                    action_n.append([spaces.PeekReward])\n                else:\n                    action_n.append([])\n            new_observation_n, new_reward_n, new_done_n, new_info = self.env.step(action_n)\n            rewarder.merge_n(\n                observation_n, self.reward_n, self.done_n, self.info,\n                new_observation_n, new_reward_n, new_done_n, new_info\n            )\n        return observation_n\n\n    def _step(self, action_n):\n        observation_n, reward_n, done_n, info = self.env.step(action_n)\n        if self.reward_n is not None:\n            rewarder.merge_n(\n                observation_n, reward_n, done_n, info,\n                [None] * self.n, self.reward_n, self.done_n, self.info\n            )\n            self.reward_n = self.done_n = self.info = None\n\n        while any(ob is None for ob in observation_n):\n            action_n = []\n            for done in done_n:\n                if done:\n                    # No popping of reward/done. Don't want to merge across episode boundaries.\n                    action_n.append([spaces.PeekReward])\n                else:\n                    action_n.append([])\n            new_observation_n, new_reward_n, new_done_n, new_info = self.env.step(action_n)\n            rewarder.merge_n(\n                observation_n, reward_n, done_n, info,\n                new_observation_n, new_reward_n, new_done_n, new_info\n            )\n        return observation_n, reward_n, done_n, info\n"
  },
  {
    "path": "universe/wrappers/diagnostics.py",
    "content": "import logging\nimport six\nfrom universe import pyprofile, vectorized\n\nlogger = logging.getLogger(__name__)\n\n# Not used in core; but used in play_flashgames\nclass Diagnostics(vectorized.Wrapper):\n\n    def _step(self, action_n):\n        observation_n, reward_n, done_n, info = self.env.step(action_n)\n        # We want this to be above Mask, so we know whether or not a\n        # particular index is resetting.\n        if self.unwrapped.diagnostics:\n            with pyprofile.push('vnc_env.diagnostics.add_metadata'):\n                self.unwrapped.diagnostics.add_metadata(observation_n, info['n'])\n        return observation_n, reward_n, done_n, info\n"
  },
  {
    "path": "universe/wrappers/experimental/__init__.py",
    "content": "from universe.wrappers.experimental.action_space import SafeActionSpace, SoftmaxClickMouse\nfrom universe.wrappers.experimental.observation import CropObservations\nfrom universe.wrappers.experimental.random_env import RandomEnv\n"
  },
  {
    "path": "universe/wrappers/experimental/action_space.py",
    "content": "import logging\n\nimport gym\nimport numpy as np\nfrom universe import spaces\nfrom universe import vectorized\nfrom universe.wrappers.gym_core import gym_core_action_space\n\nlogger = logging.getLogger(__name__)\n\ndef slither_vnc(space=False, left=False, right=False):\n    return [spaces.KeyEvent.by_name('space', down=space),\n            spaces.KeyEvent.by_name('left', down=left),\n            spaces.KeyEvent.by_name('right', down=right)]\n\ndef racing_vnc(up=False, left=False, right=False):\n    return [spaces.KeyEvent.by_name('up', down=up),\n            spaces.KeyEvent.by_name('left', down=left),\n            spaces.KeyEvent.by_name('right', down=right)]\n\ndef platform_vnc(up=False, left=False, right=False, space=False):\n    return [spaces.KeyEvent.by_name('up', down=up),\n            spaces.KeyEvent.by_name('left', down=left),\n            spaces.KeyEvent.by_name('right', down=right),\n            spaces.KeyEvent.by_name('space', down=space)]\n\n\nclass SafeActionSpace(vectorized.Wrapper):\n    \"\"\"\n    Recall that every universe environment receives a list of VNC events as action.\n    There exist many environments for which the set of relevant action is much smaller\n    and is known.   For example, Atari environments have a modest number of keys,\n    so this wrapper, when applied to an Atari environment will reduce its action space.\n    Doing so is very convenient for research, since today's RL algorithms rely on random\n    exploration, which is hurt by small action spaces.  As our algorithms get better\n    and we switch to using the raw VNC commands, this wrapper will become less important.\n    \"\"\"\n    def __init__(self, env):\n        super(SafeActionSpace, self).__init__(env)\n\n        if self.spec.tags.get('runtime') == 'gym-core':\n            self.action_space = gym_core_action_space(self.spec._kwargs['gym_core_id'])\n        elif self.spec is None:\n            pass\n        elif self.spec.id in ['internet.SlitherIO-v0',\n                              'internet.SlitherIOErmiyaEskandaryBot-v0',\n                              'internet.SlitherIOEasy-v0']:\n            self.action_space = spaces.Hardcoded([slither_vnc(left=True),\n                                                  slither_vnc(right=True),\n                                                  slither_vnc(space=True),\n                                                  slither_vnc(left=True, space=True),\n                                                  slither_vnc(right=True, space=True)])\n        elif self.spec.id in ['flashgames.DuskDrive-v0']:\n            # TODO: be more systematic\n            self.action_space = spaces.Hardcoded([racing_vnc(up=True),\n                                                  racing_vnc(left=True),\n                                                  racing_vnc(right=True)])\n        elif self.spec.id in ['flashgames.RedBeard-v0']:\n            self.action_space = spaces.Hardcoded([platform_vnc(up=True),\n                                                  platform_vnc(left=True),\n                                                  platform_vnc(right=True),\n                                                  platform_vnc(space=True)])\n\n\nclass SoftmaxClickMouse(vectorized.ActionWrapper):\n    \"\"\"\n    Creates a Discrete action space of mouse clicks.\n\n    This wrapper divides the active region into cells and creates an action for\n    each which clicks in the middle of the cell.\n    \"\"\"\n    def __init__(self, env, active_region=(10, 75 + 50, 10 + 160, 75 + 210), discrete_mouse_step=10, noclick_regions=[]):\n        super(SoftmaxClickMouse, self).__init__(env)\n        logger.info('Using SoftmaxClickMouse with action_region={}, noclick_regions={}'.format(active_region, noclick_regions))\n        xlow, ylow, xhigh, yhigh = active_region\n        xs = range(xlow, xhigh, discrete_mouse_step)\n        ys = range(ylow, yhigh, discrete_mouse_step)\n        self.active_region = active_region\n        self.discrete_mouse_step = discrete_mouse_step\n        self.noclick_regions = noclick_regions\n        self._points = []\n        removed = 0\n        for x in xs:\n            for y in ys:\n                xc = min(x+int(discrete_mouse_step/2), xhigh-1) # click to center of a cell\n                yc = min(y+int(discrete_mouse_step/2), yhigh-1)\n                if any(self.is_contained((xc, yc), r) for r in noclick_regions):\n                    removed += 1\n                    continue\n                self._points.append((xc, yc))\n        logger.info('SoftmaxClickMouse noclick regions removed {} of {} actions'.format(removed, removed + len(self._points)))\n        self.action_space = gym.spaces.Discrete(len(self._points))\n\n    def _action(self, action_n):\n        return [self._discrete_to_action(int(i)) for i in action_n]\n\n    def _discrete_to_action(self, i):\n        xc, yc = self._points[i]\n        return [\n            spaces.PointerEvent(xc, yc, buttonmask=0), # release\n            spaces.PointerEvent(xc, yc, buttonmask=1), # click\n            spaces.PointerEvent(xc, yc, buttonmask=0), # release\n        ]\n\n    def _reverse_action(self, action):\n        xlow, ylow, xhigh, yhigh = self.active_region\n        try:\n            # find first valid mousedown, ignore everything else\n            click_event = next(e for e in action if isinstance(e, spaces.PointerEvent) and e.buttonmask == 1)\n            index = self._action_to_discrete(click_event)\n            if index is None:\n                return np.zeros(len(self._points))\n            else:\n                # return one-hot vector, expected by demo training code\n                # FIXME(jgray): move one-hot translation to separate layer\n                return np.eye(len(self._points))[index]\n        except StopIteration:\n            # no valid mousedowns\n            return np.zeros(len(self._points))\n\n    def _action_to_discrete(self, event):\n        assert isinstance(event, spaces.PointerEvent)\n        x, y = event.x, event.y\n        step = self.discrete_mouse_step\n        xlow, ylow, xhigh, yhigh = self.active_region\n        xc = min((int((x - xlow) / step) * step) + xlow + step / 2, xhigh - 1)\n        yc = min((int((y - ylow) / step) * step) + ylow + step / 2, yhigh - 1)\n        try:\n            return self._points.index((xc, yc))\n        except ValueError:\n            # ignore clicks outside of active region or in noclick regions\n            return None\n\n    @classmethod\n    def is_contained(cls, point, coords):\n        px, py = point\n        x, width, y, height = coords\n        return x <= px <= x + width and y <= py <= y + height\n"
  },
  {
    "path": "universe/wrappers/experimental/observation.py",
    "content": "import logging\n\nfrom universe import vectorized, runtime_spec\n\nlogger = logging.getLogger(__name__)\nlogger.setLevel(logging.INFO)\n\n\ndef CropObservations(env):\n    \"\"\"\"\n    Crops the visual observations of an environment so that they only contain the game screen.\n    Removes anything outside the game that usually belongs to universe (browser borders and so on).\n    \"\"\"\n    if env.spec.tags.get('flashgames', False):\n        spec = runtime_spec('flashgames').server_registry[env.spec.id]\n        return _CropObservations(env, x=18, y=84, height=spec[\"height\"], width=spec[\"width\"])\n    elif (env.spec.tags.get('atari', False) and env.spec.tags.get('vnc', False)):\n        return _CropObservations(env, height=194, width=160)\n    else:\n        # if unknown environment (or local atari), do nothing\n        return env\n\nclass _CropObservations(vectorized.ObservationWrapper):\n    def __init__(self, env, height, width, x=0, y=0):\n        super(_CropObservations, self).__init__(env)\n        self.x = x\n        self.y = y\n        self.height = height\n        self.width = width\n\n        # modify observation_space? (if so, how to know depth and channels before we have seen the first frame?)\n        # self.observation_space = Box(0, 255, shape=(height, width, 3))\n\n    def _observation(self, observation_n):\n        return [self._crop_frame(observation) for observation in observation_n]\n\n    def _crop_frame(self, frame):\n        if frame is not None:\n            if isinstance(frame, dict):\n                frame['vision'] = frame['vision'][self.y:self.y + self.height, self.x:self.x + self.width]\n            else:\n                frame = frame[self.y:self.y + self.height, self.x:self.x + self.width]\n        return frame\n"
  },
  {
    "path": "universe/wrappers/experimental/random_env.py",
    "content": "import logging\nfrom universe import vectorized\n\nlogger = logging.getLogger(__name__)\n\nclass RandomEnv(vectorized.Wrapper):\n    '''\n    Randomly sample from a list of env_ids between episodes.\n\n    Passes a list of env_ids to configure. When done=True, calls env.reset()\n    to sample from the list.\n    '''\n    def __init__(self, env, env_ids):\n        super(RandomEnv, self).__init__(env)\n        self.env_ids = env_ids\n\n    def configure(self, **kwargs):\n        super(RandomEnv, self).configure(sample_env_ids=self.env_ids, **kwargs)\n\n    def _reset(self):\n        observation_n = self.env.reset()\n        return [ob['vision'] if ob is not None else ob for ob in observation_n]\n\n    def _step(self, action_n):\n        assert self.n == 1\n        observation, reward, done, info = self.env.step(action_n)\n        if any(done):\n            self.env.reset()\n        return observation, reward, done, info\n"
  },
  {
    "path": "universe/wrappers/gym_core.py",
    "content": "import logging\nimport gym\nimport time\nimport numpy as np\nfrom universe import error\nfrom gym import spaces as gym_spaces\nfrom universe import spaces\nfrom universe import rewarder, vectorized\nfrom universe.envs.vnc_core_env import translator\n\nlogger = logging.getLogger(__name__)\n\nATARI_HEIGHT = 210\nATARI_WIDTH = 160\n\ndef atari_vnc(up=False, down=False, left=False, right=False, z=False):\n    return [spaces.KeyEvent.by_name('up', down=up),\n            spaces.KeyEvent.by_name('left', down=left),\n            spaces.KeyEvent.by_name('right', down=right),\n            spaces.KeyEvent.by_name('down', down=down),\n            spaces.KeyEvent.by_name('z', down=z)]\n\ndef gym_core_action_space(gym_core_id):\n    spec = gym.spec(gym_core_id)\n\n    if spec.id == 'CartPole-v0':\n        return spaces.Hardcoded([[spaces.KeyEvent.by_name('left', down=True)],\n                                 [spaces.KeyEvent.by_name('left', down=False)]])\n    elif spec._entry_point.startswith('gym.envs.atari:'):\n        actions = []\n        env = spec.make()\n        for action in env.unwrapped.get_action_meanings():\n            z = 'FIRE' in action\n            left = 'LEFT' in action\n            right = 'RIGHT' in action\n            up = 'UP' in action\n            down = 'DOWN' in action\n            translated = atari_vnc(up=up, down=down, left=left, right=right, z=z)\n            actions.append(translated)\n        return spaces.Hardcoded(actions)\n    else:\n        raise error.Error('Unsupported env type: {}'.format(spec.id))\n\n\nclass CropAtari(vectorized.ObservationWrapper):\n    \"\"\"\nCrop the relevant portion of the monitor where an Atari enviroment resides.\n\"\"\"\n\n    def __init__(self, env):\n        super(CropAtari, self).__init__(env)\n        self.observation_space = gym_spaces.Box(0, 255, shape=(ATARI_HEIGHT, ATARI_WIDTH, 3))\n\n    def _observation(self, observation_n):\n        return [{'vision': ob['vision'][:ATARI_HEIGHT, :ATARI_WIDTH, :]} for ob in observation_n]\n\ndef one_hot(indices, depth):\n    return np.eye(depth)[indices]\n\nclass GymCoreAction(vectorized.ActionWrapper):\n    def __init__(self, env, gym_core_id=None):\n        super(GymCoreAction, self).__init__(env)\n\n        if gym_core_id is None:\n            # self.spec is None while inside of the make, so we need\n            # to pass gym_core_id in explicitly there. This case will\n            # be hit when instantiating by hand.\n            gym_core_id = self.spec._kwargs['gym_core_id']\n\n        spec = gym.spec(gym_core_id)\n        raw_action_space = gym_core_action_space(gym_core_id)\n\n        self._actions = raw_action_space.actions\n        self.action_space = gym_spaces.Discrete(len(self._actions))\n\n        if spec._entry_point.startswith('gym.envs.atari:'):\n            self.key_state = translator.AtariKeyState(gym.make(gym_core_id))\n        else:\n            self.key_state = None\n\n    def _action(self, action_n):\n        # Each action might be a length-1 np.array. Cast to int to\n        # avoid warnings.\n        return [self._actions[int(action)] for action in action_n]\n\n    def _reverse_action(self, action_n):\n        # Only works for core envs currently\n        self.key_state.apply_vnc_actions(action_n)\n        return one_hot(self.key_state.to_index(), self.action_space.n)\n\nclass GymCoreObservation(vectorized.Wrapper):\n    def __init__(self, env, gym_core_id=None):\n        super(GymCoreObservation, self).__init__(env)\n\n        if gym_core_id is None:\n            # self.spec is None while inside of the make, so we need\n            # to pass gym_core_id in explicitly there. This case will\n            # be hit when instantiating by hand.\n            gym_core_id = self.spec._kwargs['gym_core_id']\n\n        self._reward_n = None\n        self._done_n = None\n        self._info_n = None\n\n        self._gym_core_env = gym.spec(gym_core_id).make()\n\n    def _reset(self):\n        observation_n = self.env.reset()\n        self.reward_n = [0] * self.n\n        self.done_n = [False] * self.n\n        self.info = {'n': [{} for _ in range(self.n)]}\n        new_observation_n, new_reward_n, new_done_n, new_info = self.env.step([[] for i in range(self.n)])\n        rewarder.merge_n(\n            observation_n, self.reward_n, self.done_n, self.info,\n            new_observation_n, new_reward_n, new_done_n, new_info\n        )\n        return self._observation(self.done_n, self.info)\n\n    def _step(self, action_n):\n        observation_n, reward_n, done_n, info = self.env.step(action_n)\n        if self.reward_n is not None:\n            rewarder.merge_n(\n                observation_n, reward_n, done_n, info,\n                [None] * self.n, self.reward_n, self.done_n, self.info,\n            )\n            self.reward_n = self.done_n = self.info = None\n        return self._observation(done_n, info), reward_n, done_n, info\n\n    def _observation(self, done_n, info):\n        missing = set()\n\n        observation_n = [None] * self.n\n        for i, (done, info_i) in enumerate(zip(done_n, info['n'])):\n            rewarder_observation = info_i.pop('rewarder.observation', None)\n            if rewarder_observation is not None:\n                observation, episode_id = rewarder_observation\n                observation_n[i] = self._gym_core_env.observation_space.from_jsonable(observation)\n\n                if done:\n                    # Check whether we should mask\n                    completed = info_i['env_status.completed_episode_id']\n                    # Observation from old!\n                    if episode_id == completed:\n                        logger.debug('[%d] Masking rewarder_observation on episode boundary', i)\n                        observation_n[i] = None\n            else:\n                missing.add(i)\n\n        if len(missing) > 0:\n            logger.debug('Missing rewarder observations: %s', missing)\n        return observation_n\n"
  },
  {
    "path": "universe/wrappers/gym_core_sync.py",
    "content": "import gym\nimport logging\nfrom universe import rewarder, spaces, vectorized\n\nlogger = logging.getLogger(__name__)\n\nclass GymCoreSync(vectorized.Wrapper):\n    \"\"\"A synchronized version of the core envs. Its semantics should match\n    that of the core envs. (By default, observations are pixels from\n    the VNC session, but it also supports receiving the normal Gym\n    observations over the rewarder protocol.)\n\n    Provided primarily for testing and debugging.\n    \"\"\"\n\n    def __init__(self, env):\n        super(GymCoreSync, self).__init__(env)\n        self.reward_n = None\n        self.done_n = None\n        self.info = None\n\n        # Metadata has already been cloned\n        self.metadata['semantics.async'] = False\n\n    def _reset(self):\n        observation_n = self.env.reset()\n        new_observation_n, self.reward_n, self.done_n, self.info = self.env.step([[] for i in range(self.n)])\n        rewarder.merge_observation_n(observation_n, new_observation_n)\n\n        # Fast forward until the observation is caught up with the rewarder\n        self._flip_past(observation_n, self.reward_n, self.done_n, self.info)\n\n        assert all(r == 0 for r in self.reward_n), \"Unexpectedly received rewards during reset phase: {}\".format(self.reward_n)\n        return observation_n\n\n    def _step(self, action_n):\n        # Add C keypress in order to \"commit\" the action, as\n        # interpreted by the remote.\n        action_n = [action + [\n            spaces.KeyEvent.by_name('c', down=True),\n            spaces.KeyEvent.by_name('c', down=False)\n        ] for action in action_n]\n\n        observation_n, reward_n, done_n, info = self.env.step(action_n)\n        if self.reward_n is not None:\n            rewarder.merge_n(\n                observation_n, reward_n, done_n, info,\n                [None] * self.n, self.reward_n, self.done_n, self.info,\n            )\n            self.reward_n = self.done_n = self.info = None\n\n        while True:\n            count = len([True for info_i in info['n'] if info_i['stats.reward.count'] == 0])\n            if count > 0:\n                logger.debug('[GymCoreSync] Still waiting on %d envs to receive their post-commit reward', count)\n            else:\n                break\n\n            new_observation_n, new_reward_n, new_done_n, new_info = self.env.step([[] for i in range(self.n)])\n            rewarder.merge_n(\n                observation_n, reward_n, done_n, info,\n                new_observation_n, new_reward_n, new_done_n, new_info\n            )\n\n        assert all(info_i['stats.reward.count'] == 1 for info_i in info['n']), \"Expected all stats.reward.counts to be 1: {}\".format(info)\n\n        # Fast forward until the observation is caught up with the rewarder\n        self._flip_past(observation_n, reward_n, done_n, info)\n        return observation_n, reward_n, done_n, info\n\n    def _flip_past(self, observation_n, reward_n, done_n, info):\n        # Wait until all observations are past the corresponding reset times\n        remote_target_time = [info_i['reward_buffer.remote_time'] for info_i in info['n']]\n        while True:\n            new_observation_n, new_reward_n, new_done_n, new_info = self.env.step([[] for i in range(self.n)])\n\n            # info_i.get['diagnostics.image_remote_time'] may not exist, for example when an env\n            # is resetting. target is a timestamp, thus > 0, so these will count as \"need to catch up\"\n            deltas = [target - info_i.get('diagnostics.image_remote_time', 0) for target, info_i in zip(remote_target_time, new_info['n'])]\n            count = len([d for d in deltas if d > 0])\n\n            rewarder.merge_n(\n                observation_n, reward_n, done_n, info,\n                new_observation_n, new_reward_n, new_done_n, new_info\n            )\n\n            if count == 0:\n                return\n            else:\n                logger.debug('[GymCoreSync] Still waiting on %d envs to catch up to their targets: %s', count, deltas)\n"
  },
  {
    "path": "universe/wrappers/joint.py",
    "content": "from multiprocessing import pool\nfrom universe import error, rewarder, vectorized\n\nclass Joint(vectorized.Wrapper):\n    def __init__(self, env_m):\n        self.env_m = env_m\n\n        # TODO: generalize this. Doing so requires adding a vectorized\n        # space mode.\n        self.action_space = env_m[0].action_space\n        self.observation_space = env_m[0].observation_space\n\n        self.pool = pool.ThreadPool(min(len(env_m), 5))\n\n        self._n = sum(env.n for env in self.env_m)\n        self.metadata = self.metadata.copy()\n        self.metadata['render.modes'] = self.env_m[0].metadata['render.modes']\n\n    @property\n    def n(self):\n        return self._n\n\n    def _close(self):\n        if hasattr(self, 'pool'):\n            self.pool.close()\n\n    def _render(self, mode='human', close=False):\n        return self.env_m[0]._render(mode=mode, close=close)\n\n    def _reset(self):\n        # Keep all env[0] action on the main thread, in case we ever\n        # need to render. Otherwise we get segfaults from the\n        # go-vncdriver.\n        reset_m_async = self.pool.map_async(lambda env: env.reset(), self.env_m[1:])\n        reset = self.env_m[0].reset()\n        reset_m = [reset] + reset_m_async.get()\n\n        observation_n = []\n        for observation_m in reset_m:\n            observation_n += observation_m\n        return observation_n\n\n    def _step(self, action_n):\n        observation_n = []\n        reward_n = []\n        done_n = []\n        info_n = []\n        info = {}\n\n        action_m = []\n        for env in self.env_m:\n            action_m.append(action_n[len(action_m):len(action_m)+env.n])\n\n        # Keep all env[0] action on the main thread, in case we ever\n        # need to render. Otherwise we get segfaults from the\n        # go-vncdriver.\n        step_m_async = self.pool.map_async(lambda arg: arg[0].step(arg[1]), zip(self.env_m[1:], action_m[1:]))\n        step = self.env_m[0].step(action_m[0])\n        step_m = [step] + step_m_async.get()\n\n        for observation_m, reward_m, done_m, _info in step_m:\n            observation_n += observation_m\n            reward_n += reward_m\n            done_n += done_m\n\n            # copy in any info keys\n            rewarder.merge_infos(info, _info)\n            info_n += _info['n']\n\n        info['n'] = info_n\n        return observation_n, reward_n, done_n, info\n"
  },
  {
    "path": "universe/wrappers/logger.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport logging\nimport numpy as np\nimport six\nimport time\n\nfrom universe import vectorized\nfrom universe.utils import display\n\nlogger = logging.getLogger(__name__)\nextra_logger = logging.getLogger('universe.extra.'+__name__)\n\ndef stats(count):\n    flat = [e for vals in count for e in vals]\n    if len(flat) == 0:\n        return '(empty)'\n    s = '%0.1f±%0.1f' % (np.mean(flat), np.std(flat))\n    if six.PY2:\n        # There is not a great way to backport Unicode support to Python 2.\n        # We don't use it much, anyway. Easier just not to try.\n        s = s.replace('±', '+-')\n    return s\n\nclass Logger(vectorized.Wrapper):\n    metadata = {\n        'configure.required': True\n    }\n    def __init__(self, env, print_frequency=5):\n        super(Logger, self).__init__(env)\n        self.print_frequency = print_frequency\n        extra_logger.info('Running VNC environments with Logger set to print_frequency=%s. To change this, pass \"print_frequency=k\" or \"print_frequency=None\" to \"env.configure\".', self.print_frequency)\n        if self.n is not None:\n            self._clear_step_state()\n        self._last_step_time = None\n\n    def configure(self, **kwargs):\n        self.env.configure(**kwargs)\n        self._clear_step_state()\n\n    def _clear_step_state(self):\n        self.frames = 0\n        self.last_print = time.time()\n        # time between action being sent and processed\n        self.action_lag_n = [[] for _ in range(self.n)]\n        # time between observation being generated on the server and being passed to add_metadata\n        self.observation_lag_n = [[] for _ in range(self.n)]\n        # time between observation being passed to add_metadata and being returned to Logger\n        self.processing_lag = []\n        # time between observation being returned by Logger and then action being passed to Throttle\n        self.thinking_lag = []\n\n        self.vnc_updates_n = [[] for _ in range(self.n)]\n        self.vnc_bytes_n = [[] for _ in range(self.n)]\n        self.vnc_pixels_n = [[] for _ in range(self.n)]\n        self.reward_count_n = [[] for _ in range(self.n)]\n        self.reward_total_n = [[] for _ in range(self.n)]\n        self.reward_lag_n = [[] for _ in range(self.n)]\n        self.rewarder_message_lag_n = [[] for _ in range(self.n)]\n\n    def _step(self, action_n):\n        observation_n, reward_n, done_n, info = self.env.step(action_n)\n        if self.print_frequency is None:\n            return observation_n, reward_n, done_n, info\n\n        last_step_time = self._last_step_time\n        self._last_step_time = time.time()\n\n        # Printing\n        self.frames += 1\n        delta = time.time() - self.last_print\n        if delta > self.print_frequency:\n            fps = self.frames/delta\n\n            # Displayed independently\n            # action_lag = ','.join([diagnostics.display_timestamps_pair_max(action_lag) for action_lag in self.action_lag_n])\n            # observation_lag = ','.join([diagnostics.display_timestamps_pair_max(observation_lag) for observation_lag in self.observation_lag_n])\n\n            flat = False\n\n            # Smooshed together\n            action_lag, action_data = display.compute_timestamps_pair_max(self.action_lag_n, flat=flat)\n            observation_lag, observation_data = display.compute_timestamps_pair_max(self.observation_lag_n, flat=flat)\n            processing_lag, processing_data = display.compute_timestamps_sigma(self.processing_lag)\n            thinking_lag, thinking_data = display.compute_timestamps_sigma(self.thinking_lag)\n            reward_count = [sum(r) / delta for r in self.reward_count_n]\n            if flat and len(reward_count) > 0:\n                reward_count = np.mean(reward_count)\n            reward_total = [sum(r) / delta for r in self.reward_total_n]\n            if flat and len(reward_total) > 0:\n                reward_total = np.mean(reward_total)\n            reward_lag, reward_data = display.compute_timestamps_pair_max(self.reward_lag_n, flat=flat)\n            rewarder_message_lag, rewarder_message_data = display.compute_timestamps_pair_max(self.rewarder_message_lag_n, flat=flat)\n            vnc_updates_count = [sum(v) / delta for v in self.vnc_updates_n]\n            if flat and len(vnc_updates_count) > 0:\n                vnc_updates_count = np.mean(vnc_updates_count)\n\n            # Always aggregate these ones\n            if len(self.vnc_bytes_n) > 0:\n                vnc_bytes_count = np.sum(e for vnc_bytes in self.vnc_bytes_n for e in vnc_bytes) / delta\n            else:\n                vnc_bytes_count = None\n            if len(self.vnc_pixels_n) > 0:\n                vnc_pixels_count = np.sum(e for vnc_pixels in self.vnc_pixels_n for e in vnc_pixels) / delta\n            else:\n                vnc_pixels_count = None\n\n            reward_stats = stats(self.reward_count_n)\n            vnc_updates_stats = stats(self.vnc_updates_n)\n            vnc_bytes_stats = stats(self.vnc_bytes_n)\n            vnc_pixels_stats = stats(self.vnc_pixels_n)\n\n            reaction_time = []\n            for a, o in zip(action_data, observation_data):\n                try:\n                    value = thinking_data['mean'] + processing_data['mean'] + a['mean'] + o['mean']\n                except KeyError:\n                    reaction_time.append(None)\n                else:\n                    reaction_time.append(display.display_timestamp(value))\n\n            log = []\n            for key, spec, value in [\n                    ('vnc_updates_ps', '%0.1f', vnc_updates_count),\n                    ('n', '%s', self.n),\n                    ('reaction_time', '%s', reaction_time),\n                    ('observation_lag', '%s', observation_lag),\n                    ('action_lag', '%s', action_lag),\n                    ('processing_lag', '%s', processing_lag),\n                    ('thinking_lag', '%s', thinking_lag),\n                    ('reward_ps', '%0.1f', reward_count),\n                    ('reward_total', '%0.1f', reward_total),\n                    ('vnc_bytes_ps[total]', '%0.1f', vnc_bytes_count),\n                    ('vnc_pixels_ps[total]', '%0.1f', vnc_pixels_count),\n                    ('reward_lag', '%s', reward_lag),\n                    ('rewarder_message_lag', '%s', rewarder_message_lag),\n                    ('fps', '%0.2f', fps),\n            ]:\n                if value == None:\n                    continue\n\n                if isinstance(value, list):\n                    value = ','.join(spec % v for v in value)\n                else:\n                    value = spec % value\n                log.append('%s=%s' % (key, value))\n\n            if not log:\n                log.append('(empty)')\n\n            if self.frames != 0:\n                logger.info('Stats for the past %.2fs: %s', delta, ' '.join(log))\n            self._clear_step_state()\n\n        # These are properties of the step rather than any one index\n        observation_available_at = info.get('throttle.observation.available_at')\n        if observation_available_at is not None:\n            # (approximate time that we're going to return -- i.e. now, assuming Logger is fast)\n            # - (time that the observation was passed to add_metadata)\n            self.processing_lag.append(self._last_step_time - observation_available_at)\n\n        action_available_at = info.get('throttle.action.available_at')\n        if action_available_at is not None and last_step_time is not None:\n            # (time that the action was generated) - (approximate time that we last returned)\n            self.thinking_lag.append(action_available_at - last_step_time)\n\n        # Saving of lags\n        for i, info_i in enumerate(info['n']):\n            observation_lag = info_i.get('stats.gauges.diagnostics.lag.observation')\n            if observation_lag is not None:\n                self.observation_lag_n[i].append(observation_lag)\n\n            action_lag = info_i.get('stats.gauges.diagnostics.lag.action')\n            if action_lag is not None:\n                self.action_lag_n[i].append(action_lag)\n\n            reward_count = info_i.get('reward.count')\n            if reward_count is not None:\n                self.reward_count_n[i].append(reward_count)\n\n            reward_total = reward_n[i]\n            if reward_total is not None:\n                self.reward_total_n[i].append(reward_total)\n\n            assert 'vnc.updates.n' not in info, 'Looks like you are using an old go-vncdriver. Please update to >=0.4.0: pip install --ignore-installed --no-cache-dir go-vncdriver'\n\n            vnc_updates = info_i.get('stats.vnc.updates.n')\n            if vnc_updates is not None:\n                self.vnc_updates_n[i].append(vnc_updates)\n\n            vnc_bytes = info_i.get('stats.vnc.updates.bytes')\n            if vnc_bytes is not None:\n                self.vnc_bytes_n[i].append(vnc_bytes)\n\n            vnc_pixels = info_i.get('stats.vnc.updates.pixels')\n            if vnc_pixels is not None:\n                self.vnc_pixels_n[i].append(vnc_pixels)\n\n            reward_lag = info_i.get('stats.gauges.diagnostics.lag.reward')\n            if reward_lag is not None:\n                self.reward_lag_n[i].append(reward_lag)\n\n            rewarder_message_lag = info_i.get('stats.gauges.diagnostics.lag.rewarder_message')\n            if rewarder_message_lag is not None:\n                self.rewarder_message_lag_n[i].append(rewarder_message_lag)\n\n        return observation_n, reward_n, done_n, info\n"
  },
  {
    "path": "universe/wrappers/monitoring.py",
    "content": "import logging\n\nimport gym\nfrom universe.vectorized import core  # Cannot import vectorized directly without inducing a cycle\nfrom universe.wrappers.time_limit import TimeLimit\n\nlogger = logging.getLogger(__name__)\n\nclass _UniverseMonitor(core.Wrapper):\n    def __init__(self, env, directory, video_callable=None, force=False,\n                 resume=False, write_upon_reset=False, uid=None, mode=None):\n        super(_UniverseMonitor, self).__init__(env)\n        self.directory = directory\n        self.video_callable = video_callable\n        self.force = force\n        self.resume = resume\n        self.write_upon_reset = write_upon_reset\n        self.uid = uid\n        self.mode = mode\n        # TODO if we want to monitor more than one instance in a vectorized\n        # env we'll have to do this after configure()\n        self._start_monitor()\n\n    def _start_monitor(self):\n        logger.info(\"Starting Monitor. Writing monitor logs to {}\".format(self.directory))\n\n        # Circular dependencies :(\n        from universe import wrappers\n        # We need to maintain pointers to these to avoid them being\n        # GC'd. They have a weak reference to us to avoid cycles.\n        # TODO if we want to monitor more than one instance in a vectorized\n        # env we'll need to actually fix WeakUnvectorize\n        self._unvectorized_envs = [wrappers.WeakUnvectorize(self.env, i) for i in range(1)]\n\n        # For now we only monitor the first env\n        if hasattr(gym, 'wrappers'):\n            self._monitor = gym.wrappers.Monitor(self._unvectorized_envs[0],\n                directory=self.directory,\n                video_callable=self.video_callable,\n                force=self.force,\n                resume=self.resume,\n                write_upon_reset=self.write_upon_reset,\n                uid=self.uid,\n                mode=self.mode\n            )\n        else:\n            logger.warn(\"DEPRECATION WARNING: You are using an older version of gym that has a deprecated Monitor, please update to gym:v0.8.0. This change was made 2017/02/01 and is included in universe version 0.21.3\")\n            from gym import monitoring\n            self._monitor = monitoring.MonitorManager(self._unvectorized_envs[0])\n            self._monitor.start(\n                self.directory,\n                self.video_callable,\n                self.force,\n                self.resume,\n                self.write_upon_reset,\n                self.uid,\n                self.mode\n            )\n\n    def _step(self, action_n):\n        self._monitor._before_step(action_n[0])\n        observation_n, reward_n, done_n, info = self.env.step(action_n)\n        done_n[0] = self._monitor._after_step(observation_n[0], reward_n[0], done_n[0], info)\n        return observation_n, reward_n, done_n, info\n\n    def _reset(self):\n        self._monitor._before_reset()\n        observation_n = self.env.reset()\n        self._monitor._after_reset(observation_n[0])\n        return observation_n\n\n    def _close(self):\n        super(_UniverseMonitor, self)._close()\n        self._monitor.close()\n\n    def set_monitor_mode(self, mode):\n        logger.info(\"Setting the monitor mode is deprecated and will be removed soon\")\n        self._monitor._set_mode(mode)\n\ndef Monitor(env, directory, video_callable=None, force=False, resume=False,\n            write_upon_reset=False, uid=None, mode=None):\n    return _UniverseMonitor(TimeLimit(env), directory, video_callable, force, resume,\n                    write_upon_reset, uid, mode)\n"
  },
  {
    "path": "universe/wrappers/multiprocessing_env.py",
    "content": "import logging\nimport numpy as np\nfrom universe import vectorized\nfrom universe.wrappers import render\n\nlogger = logging.getLogger(__name__)\n\ndef WrappedMultiprocessingEnv(env_id):\n    return render.Render(EpisodeID(vectorized.MultiprocessingEnv(env_id)))\n\nclass RemoveNones(vectorized.Wrapper):\n    \"\"\"The vectorized environment will return None for any indexes that\n    have already exceeded their episode count (not to be confused with\n    the Nones returned by resetting environments in the real-time\n    case). For convenience, we instead return a plausible observation\n    in each such slot.\n    \"\"\"\n    def __init__(self, env):\n        super(RemoveNones, self).__init__(env)\n        self.plausible_observation = None\n\n    def _reset(self):\n        observation_n = self.env.reset()\n        self.plausible_observation = observation_n[0]\n        return observation_n\n\n    def _step(self, action_n):\n        observation_n, reward_n, done_n, info = self.env.step(action_n)\n        observation_n = [ob if ob is not None else self.plausible_observation for ob in observation_n]\n        return observation_n, reward_n, done_n, info\n\nclass EpisodeID(vectorized.Wrapper):\n    metadata = {\n        'configure.required': True\n    }\n    \"\"\"\nFor each episode, return its id, and also return the total number of contiguous\nepisodes that are now done.\n\"\"\"\n    def configure(self, episode_limit=None, **kwargs):\n        self.env.configure(**kwargs)\n        self.episode_limit = episode_limit\n        self._clear_state()\n\n    def _clear_state(self):\n        self.done_to = -1\n        self.extra_done = set()\n        self.episode_ids = list(range(self.n))\n\n    def _set_done_to(self):\n        while True:\n            next_done_to = self.done_to + 1\n            if next_done_to in self.extra_done:\n                self.done_to = next_done_to\n                self.extra_done.remove(next_done_to)\n            else:\n                break\n\n    def _reset(self):\n        self._clear_state()\n        return self.env.reset()\n\n    def _step(self, action_n):\n        observation_n, reward_n, done_n, info = self.env.step(action_n)\n        # Pass along ID of potentially-done episode\n        for i, info_i in enumerate(info['n']):\n            info_i['vectorized.episode_id'] = self.episode_ids[i]\n\n        done_i = np.argwhere(done_n).reshape(-1)\n        if len(done_i):\n            for i in done_i:\n                self.extra_done.add(self.episode_ids[i])\n                # Episode completed, so we bump its value\n                self.episode_ids[i] += self.n\n                if self.episode_limit is not None and self.episode_ids[i] > self.episode_limit:\n                    logger.debug('Masking: index=%s episode_id=%s', i, self.episode_ids[i])\n                    self.env.mask(i)\n            self._set_done_to()\n\n        # Pass along the number of contiguous episodes that are now done\n        info['vectorized.done_to'] = self.done_to\n        return observation_n, reward_n, done_n, info\n"
  },
  {
    "path": "universe/wrappers/recording.py",
    "content": "import logging\nimport time\nimport os\nimport json\nimport numpy as np\nimport threading\nfrom six.moves import queue\nfrom universe import rewarder, spaces, vectorized, pyprofile\nfrom universe.utils import random_alphanumeric\n\nlogger = logging.getLogger(__name__)\nextra_logger = logging.getLogger('universe.extra.'+__name__)\n\n\nclass Recording(vectorized.Wrapper):\n    \"\"\"\nRecord all action/observation/reward/info to a log file.\n\nIt will do nothing, unless given a (recording_dir='/path/to/results') argument.\nrecording_policy can be one of:\n    'capped_cubic' will record a subset of episodes (those that are a perfect cube: 0, 1, 8, 27, 64, 125, 216, 343, 512, 729, 1000, and every multiple of 1000 thereafter).\n    'always' records all\n    'never' records none\nrecording_notes can be used to record hyperparameters in the log file\n\nThe format is line-separated json, with large observations stored separately in binary.\n\nThe universe-viewer project (http://github.com/openai/universe-viewer) provides a browser-based UI\nfor examining logs.\n\n\"\"\"\n\n    def __init__(self, env, recording_dir=None, recording_policy=None, recording_notes=None):\n        super(Recording, self).__init__(env)\n        self._log_n = None\n        self._episode_ids = None\n        self._step_ids = None\n        self._episode_id_counter = 0\n        self._env_semantics_autoreset = env.metadata.get('semantics.autoreset', False)\n        self._env_semantics_async = env.metadata.get('semantics.async', False)\n        self._async_write = self._env_semantics_async\n\n        self._recording_dir = recording_dir\n        if self._recording_dir is not None:\n            if recording_policy == 'never' or recording_policy is False:\n                self._recording_policy = lambda episode_id: False\n            elif recording_policy == 'always' or recording_policy is True:\n                self._recording_policy = lambda episode_id: True\n            elif recording_policy == 'capped_cubic' or recording_policy is None:\n                self._recording_policy = lambda episode_id: (int(round(episode_id ** (1. / 3))) ** 3 == episode_id) if episode_id < 1000 else episode_id % 1000 < 2\n            else:\n                self._recording_policy = recording_policy\n        else:\n            self._recording_policy = lambda episode_id: False\n        logger.info('Running Recording wrapper with recording_dir=%s policy=%s. To change this, pass recording_dir=\"...\" to env.configure.', self._recording_dir, recording_policy)\n\n        self._recording_notes = {\n            'env_id': env.spec.id,\n            'env_metadata': env.metadata,\n            'env_spec_tags': env.spec.tags,\n            'env_semantics_async': self._env_semantics_async,\n            'env_semantics_autoreset': self._env_semantics_autoreset,\n        }\n        if recording_notes is not None:\n            self._recording_notes.update(recording_notes)\n\n        if self._recording_dir is not None:\n            os.makedirs(self._recording_dir, exist_ok=True)\n\n        self._instance_id = random_alphanumeric(6)\n\n    def _get_episode_id(self):\n        ret = self._episode_id_counter\n        self._episode_id_counter += 1\n        return ret\n\n    def _get_writer(self, i):\n        \"\"\"\n        Returns a tuple of (log_fn, log_f, bin_fn, bin_f) to be written to by vectorized env channel i\n        Or all Nones if recording is inactive on that channel\n        \"\"\"\n        if self._recording_dir is None:\n            return None\n        if self._log_n is None:\n            self._log_n = [None] * self.n\n        if self._log_n[i] is None:\n            self._log_n[i] = RecordingWriter(self._recording_dir, self._instance_id, i, async_write=self._async_write)\n        return self._log_n[i]\n\n    def _reset(self):\n        if self._episode_ids is None:\n            self._episode_ids = [None] * self.n\n        if self._step_ids is None:\n            self._step_ids = [None] * self.n\n\n        for i in range(self.n):\n            writer = self._get_writer(i)\n            if writer is not None:\n                if self._recording_notes is not None:\n                    writer(type='notes', notes=self._recording_notes)\n                    self._recording_notes = None\n                writer(type='reset', timestamp=time.time())\n            self._episode_ids[i] = self._get_episode_id()\n            self._step_ids[i] = 0\n\n        return self.env.reset()\n\n    def _step(self, action_n):\n        observation_n, reward_n, done_n, info = self.env.step(action_n)\n        info_n = info[\"n\"]\n\n        for i in range(self.n):\n            if self._recording_policy(self._episode_ids[i]):\n                writer = self._get_writer(i)\n                if writer is not None:\n                    writer(type='step',\n                           timestamp=time.time(),\n                           episode_id=self._episode_ids[i],\n                           step_id=self._step_ids[i],\n                           action=action_n[i],\n                           observation=observation_n[i],\n                           reward=reward_n[i],\n                           done=done_n[i],\n                           info=info_n[i])\n                    # Agents can later call info_n[i]['annotate'](...) to add more things to be visualized\n                    info_n[i]['annotate'] = RecordingAnnotator(writer, self._episode_ids[i], self._step_ids[i])\n                self._step_ids[i] += 1\n            if done_n[i] and self._env_semantics_autoreset:\n                self._episode_ids[i] = self._get_episode_id()\n                self._step_ids[i] = 0\n\n        return observation_n, reward_n, done_n, info\n\n    def _close(self):\n        super(Recording, self)._close()\n        if self._log_n is not None:\n            for i in range(self.n):\n                if self._log_n[i] is not None:\n                    self._log_n[i].close()\n                    self._log_n[i] = None\n\nclass RecordingWriter(object):\n    \"\"\"\n    Safe to use from multiple threads, in case your agent action generator & learning are running in parallel.\n    \"\"\"\n    def __init__(self, recording_dir, instance_id, channel_id, async_write=True):\n        self.log_fn = 'universe.recording.{}.{}.{}.jsonl'.format(os.getpid(), instance_id, channel_id)\n        log_path = os.path.join(recording_dir, self.log_fn)\n        self.bin_fn = 'universe.recording.{}.{}.{}.bin'.format(os.getpid(), instance_id, channel_id)\n        bin_path = os.path.join(recording_dir, self.bin_fn)\n        extra_logger.info('Logging to %s and %s', log_path, self.bin_fn)\n        self.log_f = open(log_path, 'w')\n        self.bin_f = open(bin_path, 'wb')\n        # It would be better to measure memory use and block the writer when the queue is sitting on too much memory\n        self.q = queue.Queue(1000)\n        self.t = threading.Thread(target=self.writer_main)\n        self.t.start()\n\n    def close(self):\n        self.q.put(None)\n\n    def close_files(self):\n        if self.bin_f is not None:\n            self.bin_f.close()\n            self.bin_f = None\n        if self.log_f is not None:\n            self.log_f.close()\n            self.log_f = None\n\n    def json_encode(self, obj):\n        if isinstance(obj, np.ndarray):\n            offset = self.bin_f.tell()\n            while offset%8 != 0:\n                self.bin_f.write(b'\\x00')\n                offset += 1\n            obj.tofile(self.bin_f)\n            size = self.bin_f.tell() - offset\n            return {'__type': 'ndarray', 'shape': obj.shape, 'order': 'C', 'dtype': str(obj.dtype), 'npyfile': self.bin_fn, 'npyoff': offset, 'size': size}\n        elif isinstance(obj, np.float32):\n            return float(obj)\n        elif isinstance(obj, np.float64):\n            return float(obj)\n        elif isinstance(obj, np.int32):\n            return int(obj)\n        elif isinstance(obj, np.int64):\n            return int(obj)\n        elif isinstance(obj, RecordingAnnotator):\n            return 'RecordingAnnotator'\n        else:\n            return obj\n\n    def writer_main(self):\n        while True:\n            item = self.q.get()\n            if item is None: break\n            self.write_item(item)\n            self.q.task_done()\n        self.close_files()\n\n    def __call__(self, **kwargs):\n        pyprofile.gauge('recording.qsize', self.q.qsize())\n        self.q.put(kwargs)\n\n    def write_item(self, item):\n        with pyprofile.push('recording.write'):\n            l = json.dumps(item, skipkeys=True, default=self.json_encode)\n            self.log_f.write(l + '\\n')\n            self.log_f.flush()\n\nclass RecordingAnnotator(object):\n    def __init__(self, writer, episode_id, step_id):\n        self.writer = writer\n        self.episode_id = episode_id\n        self.step_id = step_id\n    def __call__(self, **kwargs):\n        self.writer.__call__(type='annotate', episode_id=self.episode_id, step_id=self.step_id, **kwargs)\n"
  },
  {
    "path": "universe/wrappers/render.py",
    "content": "import logging\nimport os\nfrom twisted.python.runtime import platform\nfrom universe import vectorized\n\nlogger = logging.getLogger(__name__)\n\nclass Render(vectorized.Wrapper):\n    metadata = {\n        'configure.required': True\n    }\n    def __init__(self, *args, **kwargs):\n        if platform.isLinux() and not os.environ.get('DISPLAY'):\n            self.renderable = False\n        else:\n            self.renderable = True\n        self._observation = None\n        super(Render, self).__init__(*args, **kwargs)\n\n    def configure(self, **kwargs):\n        self.env.configure(**kwargs)\n        self.metadata = self.metadata.copy()\n        modes = self.metadata.setdefault('render.modes', [])\n        if 'rgb_array' not in modes:\n            modes.append('rgb_array')\n\n    def _reset(self):\n        observation_n = self.env.reset()\n        self._observation = observation_n[0]\n        return observation_n\n\n    def _step(self, action_n):\n        observation_n, reward_n, done_n, info_n = self.env.step(action_n)\n        self._observation = observation_n[0]\n        return observation_n, reward_n, done_n, info_n\n\n    def _render(self, mode='human', *args, **kwargs):\n        if not self.renderable and mode == 'human':\n            return\n        elif self.env is None:\n            # Only when this breaks\n            return\n        elif mode == 'rgb_array':\n            if self._observation is not None:\n                observation = self._observation\n                if isinstance(self._observation, dict):\n                    observation = observation['vision']\n                return observation\n            else:\n                return None\n        # Could log, but no need.\n        return self.env.render(mode=mode, *args, **kwargs)\n"
  },
  {
    "path": "universe/wrappers/tests/test_joint.py",
    "content": "import gym\nimport universe\nfrom universe import wrappers\n\ndef test_joint():\n    env1 = gym.make('test.DummyVNCEnv-v0')\n    env2 = gym.make('test.DummyVNCEnv-v0')\n    env1.configure(_n=3)\n    env2.configure(_n=3)\n    for reward_buffer in [env1._reward_buffers[0], env2._reward_buffers[0]]:\n        reward_buffer.set_env_info('running', 'test.DummyVNCEnv-v0', '1', 60)\n        reward_buffer.reset('1')\n        reward_buffer.push('1', 10, False, {})\n\n    env = wrappers.Joint([env1, env2])\n    assert env.n == 6\n    observation_n = env.reset()\n    assert observation_n == [None] * 6\n\n    observation_n, reward_n, done_n, info = env.step([[] for _ in range(env.n)])\n    assert reward_n == [10.0, 0.0, 0.0, 10.0, 0.0, 0.0]\n    assert done_n == [False] * 6\n"
  },
  {
    "path": "universe/wrappers/tests/test_time_limit.py",
    "content": "import gym\nimport time\nimport universe\nfrom gym.envs import register\nfrom universe import wrappers\n\nregister(\n    id='test.SecondsLimitDummyVNCEnv-v0',\n    entry_point='universe.envs:DummyVNCEnv',\n    max_episode_seconds=0.1,\n    tags={\n        'vnc': True,\n        }\n    )\n\nregister(\n    id='test.StepsLimitDummyVNCEnv-v0',\n    entry_point='universe.envs:DummyVNCEnv',\n    max_episode_steps=2,\n    tags={\n        'vnc': True,\n        }\n    )\n\n\ndef test_steps_limit_restart():\n    env = gym.make('test.StepsLimitDummyVNCEnv-v0')\n    env.configure(_n=1)\n    env = wrappers.TimeLimit(env)\n    env.reset()\n\n    assert env._max_episode_seconds == None\n    assert env._max_episode_steps == 2\n\n    # Episode has started\n    _, _, done, info = env.step([[]])\n    assert done == [False]\n\n    # Limit reached, now we get a done signal and the env resets itself\n    _, _, done, info = env.step([[]])\n    assert done == [True]\n    assert env._elapsed_steps == 0\n\n\ndef test_steps_limit_restart_unused_when_not_wrapped():\n    env = gym.make('test.StepsLimitDummyVNCEnv-v0')\n    env.configure(_n=1)\n    env.reset()\n\n    for i in range(10):\n        _, _, done, info = env.step([[]])\n        assert done == [False]\n\n\ndef test_seconds_limit_restart():\n    env = gym.make('test.SecondsLimitDummyVNCEnv-v0')\n    env.configure(_n=1)\n    env = wrappers.TimeLimit(env)\n    env.reset()\n\n    assert env._max_episode_seconds == 0.1\n    assert env._max_episode_steps == None\n\n    # Episode has started\n    _, _, done, info = env.step([[]])\n    assert done == [False]\n\n    # Not enough time has passed\n    _, _, done, info = env.step([[]])\n    assert done == [False]\n\n    time.sleep(0.2)\n\n    # Limit reached, now we get a done signal and the env resets itself\n    _, _, done, info = env.step([[]])\n    assert done == [True]\n\n\ndef test_default_time_limit():\n    # We need an env without a default limit\n    register(\n        id='test.NoLimitDummyVNCEnv-v0',\n        entry_point='universe.envs:DummyVNCEnv',\n        tags={\n            'vnc': True,\n            },\n    )\n\n    env = gym.make('test.NoLimitDummyVNCEnv-v0')\n    env.configure(_n=1)\n    env = wrappers.TimeLimit(env)\n    env.reset()\n\n    assert env._max_episode_seconds == wrappers.time_limit.DEFAULT_MAX_EPISODE_SECONDS\n    assert env._max_episode_steps == None\n"
  },
  {
    "path": "universe/wrappers/throttle.py",
    "content": "import logging\nimport time\nfrom universe import pyprofile, rewarder, spaces, vectorized\n\nlogger = logging.getLogger(__name__)\n\nclass Throttle(vectorized.Wrapper):\n    \"\"\"\n    A env wrapper that makes sending the action ASAP.\n\n    Previous implementation would sleep first and then call env._step.\n    This implementation calls env._step twice:\n        1. first call submits given action\n        2. after sleeping based on fps, second call submits empty action to\n           receive observation.\n\n    visual observation from first call is discarded.\n    metadata and rewards from the two calls are merged.\n    text observations are merged as well.\n    \"\"\"\n    def __init__(self, env):\n        super(Throttle, self).__init__(env)\n\n        self._steps = None\n\n    def configure(self, skip_metadata=False, fps='default', **kwargs):\n        if fps == 'default':\n            fps = self.metadata['video.frames_per_second']\n        self.fps = fps\n        self.skip_metadata = skip_metadata\n\n        self.env.configure(**kwargs)\n        self.diagnostics = self.unwrapped.diagnostics\n\n    def _reset(self):\n        # We avoid aggregating reward/info across episode boundaries\n        # by caching it on the object\n        self._deferred_reward_n = None\n        self._deferred_done_n = None\n        self._deferred_info_n = None\n\n        observation = self.env.reset()\n        self._start_timer()\n        return observation\n\n    def _step(self, action_n):\n        if self._steps is None:\n            self._start_timer()\n        self._steps += 1\n\n        accum_observation_n, accum_reward_n, accum_done_n, accum_info = self._substep(action_n)\n        accum_info['throttle.action.available_at'] = time.time()\n\n        # Record which indexes we were just peeking at, so when we\n        # make the follow-up we'll be sure to peek there too.\n        peek_n = [any(spaces.PeekReward for peek in action) for action in action_n]\n\n        if self.fps is None:\n            return accum_observation_n, accum_reward_n, accum_done_n, accum_info\n\n        accum_info['stats.throttle.sleep'] = 0\n        while True:\n            # See how much time we have to idle\n            delta = self._start + 1./self.fps * self._steps - time.time()\n\n            # The following assumes that our control loop\n            if delta < 0:\n                # We're out of time. Just get out of here.\n                delta = abs(delta)\n                if delta >= 1:\n                    logger.info('Throttle fell behind by %.2fs; lost %.2f frames', delta, self.fps*delta)\n                pyprofile.timing('vnc_env.Throttle.lost_sleep', delta)\n                self._start_timer()\n                break\n            # elif delta < 0.008:\n            #     # Only have 8ms. Let's spend it sleeping, and\n            #     # return an image which may have up to an\n            #     # additional 8ms lag.\n            #     #\n            #     # 8ms is reasonably arbitrary; we just want something\n            #     # that's small where it's not actually going to help\n            #     # if we make another step call. Step with 32 parallel\n            #     # envs takes about 6ms (about half of which is\n            #     # diagnostics, which could be totally async!), so 8 is\n            #     # a reasonable choice for now..\n            #     pyprofile.timing('vnc_env.Throttle.sleep', delta)\n            #     accum_info['stats.throttle.sleep'] += delta\n            #     time.sleep(delta)\n            #     break\n            else:\n                # We've got plenty of time. Sleep for up to 16ms, and\n                # then refresh our current frame. We need to\n                # constantly be calling step so that our lags are\n                # reported correctly, within 16ms. (The layering is\n                # such that the vncdriver doesn't know which pixels\n                # correspond to metadata, and the diagnostics don't\n                # know when pixels first got painted. So we do our\n                # best to present frames as they're ready to the\n                # diagnostics.)\n                delta = min(delta, 0.016)\n                pyprofile.timing('vnc_env.Throttle.sleep', delta)\n                accum_info['stats.throttle.sleep'] += delta\n                time.sleep(delta)\n\n                # We want to merge in the latest reward/done/info so that our\n                # agent has the most up-to-date info post-sleep, but also want\n                # to avoid popping any rewards where done=True (since we'd\n                # have to merge across episode boundaries).\n                action_n = []\n                for done, peek in zip(accum_done_n, peek_n):\n                    if done or peek:\n                        # No popping of reward/done\n                        action_n.append([spaces.PeekReward])\n                    else:\n                        action_n.append([])\n\n                observation_n, reward_n, done_n, info = self._substep(action_n)\n\n                # Merge observation, rewards and metadata.\n                # Text observation has order in which the messages are sent.\n                rewarder.merge_n(\n                    accum_observation_n, accum_reward_n, accum_done_n, accum_info,\n                    observation_n, reward_n, done_n, info,\n                )\n\n        return accum_observation_n, accum_reward_n, accum_done_n, accum_info\n\n    def _substep(self, action_n):\n        with pyprofile.push('vnc_env.Throttle.step'):\n            start = time.time()\n            # Submit the action ASAP, before the thread goes to sleep.\n            observation_n, reward_n, done_n, info = self.env.step(action_n)\n\n            available_at = info['throttle.observation.available_at'] = time.time()\n            if available_at - start > 1:\n                logger.info('env.step took a long time: %.2fs', available_at - start)\n            if not self.skip_metadata and self.diagnostics is not None:\n                # Run (slow) diagnostics\n                self.diagnostics.add_metadata(observation_n, info['n'], available_at=available_at)\n            return observation_n, reward_n, done_n, info\n\n    def _start_timer(self):\n        self._start = time.time()\n        self._steps = 0\n"
  },
  {
    "path": "universe/wrappers/time_limit.py",
    "content": "import logging\n\nimport time\nfrom universe import pyprofile\nfrom universe.vectorized import core\n\nlogger = logging.getLogger(__name__)\n\nDEFAULT_MAX_EPISODE_SECONDS = 20 * 60.  # Default to 20 minutes if there is no explicit limit\n\nclass UniverseTimeLimit(core.Wrapper):\n    def __init__(self, env):\n        super(UniverseTimeLimit, self).__init__(env)\n        self._max_episode_seconds = self.env.spec.max_episode_seconds\n        self._max_episode_steps = self.env.spec.max_episode_steps\n\n        if self._max_episode_seconds is None and self._max_episode_steps is None:\n            self._max_episode_seconds = DEFAULT_MAX_EPISODE_SECONDS\n\n        self._elapsed_steps = 0\n        self._episode_started_at = None\n\n    @property\n    def _elapsed_seconds(self):\n        return time.time() - self._episode_started_at\n\n    def _past_limit(self):\n        \"\"\"Return true if we are past our limit\"\"\"\n        if self._max_episode_steps is not None and self._max_episode_steps <= self._elapsed_steps:\n            logger.debug(\"Env has passed the step limit defined by TimeLimit.\")\n            return True\n\n        if self._max_episode_seconds is not None and self._max_episode_seconds <= self._elapsed_seconds:\n            logger.debug(\"Env has passed the seconds limit defined by TimeLimit.\")\n            return True\n\n        return False\n\n    def _step(self, action_n):\n        assert self._episode_started_at is not None, \"Cannot call env.step() before calling reset()\"\n        observation_n, reward_n, done_n, info = self.env.step(action_n)\n        self._elapsed_steps += 1\n\n        if self._past_limit():\n            _ = self.reset()  # Force a reset, discard the observation\n            done_n = [True] * self.n  # Force a done = True\n\n        return observation_n, reward_n, done_n, info\n\n    def _reset(self):\n        self._episode_started_at = time.time()\n        self._elapsed_steps = 0\n        return self.env.reset()\nTimeLimit = UniverseTimeLimit\n"
  },
  {
    "path": "universe/wrappers/timer.py",
    "content": "import logging\nimport time\nfrom universe import pyprofile, vectorized\n\nlogger = logging.getLogger(__name__)\n\nclass Timer(vectorized.Wrapper):\n    \"\"\"\nCalculate how much time was spent actually doing work.  Display result\nvia pyprofile.\n\"\"\"\n\n    def configure(self, **kwargs):\n        self.env.configure(**kwargs)\n\n    def _reset(self):\n        with pyprofile.push('vnc_env.Timer.reset'):\n            return self.env.reset()\n\n    def _step(self, action_n):\n        start = time.time()\n        with pyprofile.push('vnc_env.Timer.step'):\n            observation_n, reward_n, done_n, info = self.env.step(action_n)\n\n        # Calculate how much time was spent actually doing work\n        sleep = info.get('stats.throttle.sleep')\n        if sleep is None or sleep < 0:\n            sleep = 0\n        pyprofile.timing('vnc_env.Timer.step.excluding_sleep', time.time() - start - sleep)\n        return observation_n, reward_n, done_n, info\n"
  },
  {
    "path": "universe/wrappers/vectorize.py",
    "content": "import gym\nimport weakref\n\nfrom universe import error\nfrom universe.vectorized import core\n\nclass Vectorize(gym.Wrapper):\n    \"\"\"\nGiven an unvectorized environment (where, e.g., the output of .step() is an observation\nrather than a list of observations), turn it into a vectorized environment with a batch of size\n1.\n\"\"\"\n\n    metadata = {'runtime.vectorized': True}\n\n    def __init__(self, env):\n        super(Vectorize, self).__init__(env)\n        assert not env.metadata.get('runtime.vectorized')\n        assert self.metadata.get('runtime.vectorized')\n        self.n = 1\n\n    def _reset(self):\n        observation = self.env.reset()\n        return [observation]\n\n    def _step(self, action):\n        observation, reward, done, info = self.env.step(action[0])\n        return [observation], [reward], [done], {'n': [info]}\n\n    def _seed(self, seed):\n        return [self.env.seed(seed[0])]\n\nclass Unvectorize(core.Wrapper):\n    \"\"\"\nTake a vectorized environment with a batch of size 1 and turn it into an unvectorized environment.\n\"\"\"\n    autovectorize = False\n    metadata = {'runtime.vectorized': False}\n\n    def _reset(self):\n        observation_n = self.env.reset()\n        assert(len(observation_n) == 1)\n        return observation_n[0]\n\n    def _step(self, action):\n        action_n = [action]\n        observation_n, reward_n, done_n, info = self.env.step(action_n)\n        return observation_n[0], reward_n[0], done_n[0], info['n'][0]\n\n    def _seed(self, seed):\n        return self.env.seed([seed])[0]\n\nclass WeakUnvectorize(Unvectorize):\n    def __init__(self, env, i):\n        self._env_ref = weakref.ref(env)\n        super(WeakUnvectorize, self).__init__(env)\n        # WeakUnvectorize won't get configure called on it\n        self.i = i\n\n    def _check_for_duplicate_wrappers(self):\n        pass  # Disable this check because we need to wrap vectorized envs in multiple unvectorize wrappers\n\n    @property\n    def env(self):\n        # Called upon instantiation\n        if not hasattr(self, '_env_ref'):\n            return\n\n        env = self._env_ref()\n        if env is None:\n            raise error.Error(\"env has been garbage collected. To keep using WeakUnvectorize, you must keep around a reference to the env object. (HINT: try assigning the env to a variable in your code.)\")\n        return env\n\n    @env.setter\n    def env(self, value):\n        # We'll maintain our own weakref, thank you very much.\n        pass\n\n    def _seed(self, seed):\n        # We handle the seeding ourselves in the vectorized Monitor\n        return [seed]\n\n    def close(self):\n        # Don't want to close through this wrapper\n        pass\n"
  },
  {
    "path": "universe/wrappers/vision.py",
    "content": "import logging\nfrom universe import vectorized\n\nlogger = logging.getLogger(__name__)\n\nclass Vision(vectorized.Wrapper):\n    \"\"\"\nAt present, an observation from a vectorized universe environment returns a list of \ndicts. Each dict contains input data for each modality.  Modalities include 'vision'\nand 'text', and it is possible to add other modalities in the future (such as 'audio').\n\nThe Vision wrapper extracts the vision modality and discards all others.  This is convenient\nwhen we only care about the visual input.\n\"\"\"\n\n    def _reset(self):\n        observation_n = self.env.reset()\n        return [ob['vision'] if ob is not None else ob for ob in observation_n]\n\n    def _step(self, action_n):\n        observation_n, reward_n, done_n, info_n = self.env.step(action_n)\n        observation_n = [ob['vision'] if ob is not None else ob for ob in observation_n]\n        return observation_n, reward_n, done_n, info_n\n"
  }
]