# -*- coding: utf-8 -*-
#
# testiaf.py
#
# This file is part of NEST.
#
# Copyright (C) 2004 The NEST Initiative
#
# NEST is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# NEST is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with NEST.  If not, see <http://www.gnu.org/licenses/>.

'''
IAF Neuron example
------------------

A DC current is injected into the neuron using a current generator
device. The membrane potential as well as the spiking activity are
recorded by corresponding devices.

It can be observed how the current charges the membrane, a spike
is emitted, the neuron becomes absolute refractory, and finally
starts to recover.
'''

'''
First, we import all necessary modules for simulation and plotting
'''

import nest
import pylab

'''
Second the Function build_network is defined to build the network and
return the handles of the spike detector and the voltmeter
'''

def build_network(dt) :

    nest.ResetKernel()
    nest.SetKernelStatus({"local_num_threads" : 1, "resolution" : dt})

    neuron = nest.Create('iaf_neuron')
    nest.SetStatus(neuron, "I_e", 376.0)

    vm = nest.Create('voltmeter')
    nest.SetStatus(vm, "withtime", True)

    sd = nest.Create('spike_detector')

    nest.Connect(vm, neuron)
    nest.Connect(neuron, sd)

    return vm, sd

'''
The function build_network takes the resolution as argument.
First the Kernel is reset and the number of threads is set to zero as
well as the resolution to the specified value dt.  The iaf_neuron is
created and the handle is stored in the variable neuron The status of
the neuron is changed so it receives an external current.  Next the
voltmeter is created and the handle stored in vm and the option
'withtime' is set, therefore times are given in the times vector in
events. Now the spike_detecor is created and its handle is stored in
sd.

Voltmeter and spikedetector are then connected to the neuron.  The
connect function takes the handles as input.  The Voltmeter is
connected to the neuron and the neuron to the spikedetector because
the neuron sends spikes to the detector and the voltmeter 'observes'
the neuron.
'''

'''
The neuron is simulated for three different resolutions and then
the voltage trace is plotted
'''

for dt in [0.1, 0.5, 1.0] :
    print("Running simulation with dt=%.2f" % dt)
    vm, sd = build_network(dt)

    '''
    First using build_network the network is build and the handles of
    the spike detector and the voltmeter are stored in vm and sd
    '''

    nest.Simulate(1000.0)

    '''
    The network is simulated using `Simulate`, which takes the desired
    simulation time in milliseconds and advances the network state by
    this amount of time. During simulation, the `spike_detector`
    counts the spikes of the target neuron and the total number is
    read out at the end of the simulation period.
    '''

    potentials = nest.GetStatus(vm, "events")[0]["V_m"]
    times = nest.GetStatus(vm, "events")[0]["times"]

    '''
    The values of the voltage recorded by the voltmeter are read out
    and the values for the membrane potential are stored in potential
    and the corresponding times in the times array
    '''

    pylab.plot(times, potentials, label="dt=%.2f" % dt)
    print("  Number of spikes: {0}".format(nest.GetStatus(sd, "n_events")[0]))

    '''
    Using the pylab library the voltage trace is plotted over time
    '''

    pylab.legend(loc=3)
    pylab.xlabel("time (ms)")
    pylab.ylabel("V_m (mV)")

    '''
    Finally the axis are labelled and a legend is generated
    '''


#!/usr/bin/python2.4
# Copyright 2009, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""Build tool setup for optimized environments.

This module is a SCons tool which setups environments for optimized builds.
It is used as follows:
  optimized_env = env.Clone(tools = ['target_optimized'])
"""

def generate(env):
  # NOTE: SCons requires the use of this name, which fails gpylint.
  """SCons entry point for this tool."""

  # Add in general options.
  env['TARGET_DEBUG'] = False

  env.Append(
      CPPDEFINES=['NDEBUG'] + env.get('CPPDEFINES_OPTIMIZED', []),
      CCFLAGS=env.get('CCFLAGS_OPTIMIZED', []),
      LINKFLAGS=env.get('LINKFLAGS_OPTIMIZED', []),
  )


#!/usr/bin/env python3
# Copyright (c) 2015-2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test p2p mempool message.

Test that nodes are disconnected if they send mempool messages when bloom
filters are not enabled.
"""

from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *

class P2PMempoolTests(BitcoinTestFramework):
    def set_test_params(self):
        self.setup_clean_chain = True
        self.num_nodes = 1
        self.extra_args = [["-peerbloomfilters=0"]]

    def run_test(self):
        # Add a p2p connection
        self.nodes[0].add_p2p_connection(P2PInterface())
        network_thread_start()
        self.nodes[0].p2p.wait_for_verack()

        #request mempool
        self.nodes[0].p2p.send_message(msg_mempool())
        self.nodes[0].p2p.wait_for_disconnect()

        #mininode must be disconnected at this point
        assert_equal(len(self.nodes[0].getpeerinfo()), 0)

if __name__ == '__main__':
    P2PMempoolTests().main()


# Copyright 2012 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials provided
#       with the distribution.
#     * Neither the name of Google Inc. nor the names of its
#       contributors may be used to endorse or promote products derived
#       from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

class Peer(object):
  def __init__(self, address, jobs, rel_perf, pubkey):
    self.address = address  # string: IP address
    self.jobs = jobs  # integer: number of CPUs
    self.relative_performance = rel_perf
    self.pubkey = pubkey # string: pubkey's fingerprint
    self.shells = set()  # set of strings
    self.needed_work = 0
    self.assigned_work = 0
    self.tests = []  # list of TestCase objects
    self.trusting_me = False  # This peer trusts my public key.
    self.trusted = False  # I trust this peer's public key.

  def __str__(self):
    return ("Peer at %s, jobs: %d, performance: %.2f, trust I/O: %s/%s" %
            (self.address, self.jobs, self.relative_performance,
             self.trusting_me, self.trusted))

  def AddTests(self, shell):
    """Adds tests from |shell| to this peer.

    Stops when self.needed_work reaches zero, or when all of shell's tests
    are assigned."""
    assert self.needed_work > 0
    if shell.shell not in self.shells:
      self.shells.add(shell.shell)
    while len(shell.tests) > 0 and self.needed_work > 0:
      t = shell.tests.pop()
      self.needed_work -= t.duration
      self.assigned_work += t.duration
      shell.total_duration -= t.duration
      self.tests.append(t)

  def ForceAddOneTest(self, test, shell):
    """Forcibly adds another test to this peer, disregarding needed_work."""
    if shell.shell not in self.shells:
      self.shells.add(shell.shell)
    self.needed_work -= test.duration
    self.assigned_work += test.duration
    shell.total_duration -= test.duration
    self.tests.append(test)

  def Pack(self):
    """Creates a JSON serializable representation of this Peer."""
    return [self.address, self.jobs, self.relative_performance]

  @staticmethod
  def Unpack(packed):
    """Creates a Peer object built from a packed representation."""
    pubkey_dummy = ""  # Callers of this don't care (only the server does).
    return Peer(packed[0], packed[1], packed[2], pubkey_dummy)


import os
import random

class CPU(object):
    """
    The Chip-8 has 4KB of RAM from 0x000 to 0xFFF. The original interpreter is stored in memory
    from 0x000 to 0x1FF so most programs will start at 0x200. The Chip-8 has 16 8-bit registers
    and a 16-bit register that stores memory addresses. There are also 2 8-bit registers that
    are the delay and sound timers. The stack can hold 16 16-bit values. The Chip-8 had a 16-bit
    keypad from 0~9 and A~F.
    """
    def __init__(self, display):
        """
        Initializes all the needed components of the Chip-8 CPU to their proper values
        """
        self.memory = [0] * 4096
        self.registers = [0] * 16
        self.address = [0] * 16
        self.stack = [0] * 16
        self.keys = [0] * 16
        self.display_pixels = [[0 for _ in range(64)] for _ in range(32)]
        self.pc = 0x200
        self.sp = 0
        self.register_I = 0
        self.delay_timer = 0
        self.sound_timer = 0
        self.display = display
        self.draw = False
        self.test = True

        self.font_set = [
            0xF0, 0x90, 0x90, 0x90, 0xF0, # 0
            0x20, 0x60, 0x20, 0x20, 0x70, # 1
            0xF0, 0x10, 0xF0, 0x80, 0xF0, # 2
            0xF0, 0x10, 0xF0, 0x10, 0xF0, # 3
            0x90, 0x90, 0xF0, 0x10, 0x10, # 4
            0xF0, 0x80, 0xF0, 0x10, 0xF0, # 5
            0xF0, 0x80, 0xF0, 0x90, 0xF0, # 6
            0xF0, 0x10, 0x20, 0x40, 0x40, # 7
            0xF0, 0x90, 0xF0, 0x90, 0xF0, # 8
            0xF0, 0x90, 0xF0, 0x10, 0xF0, # 9
            0xF0, 0x90, 0xF0, 0x90, 0x90, # A
            0xE0, 0x90, 0xE0, 0x90, 0xE0, # B
            0xF0, 0x80, 0x80, 0x80, 0xF0, # C
            0xE0, 0x90, 0x90, 0x90, 0xE0, # D
            0xF0, 0x80, 0xF0, 0x80, 0xF0, # E
            0xF0, 0x80, 0xF0, 0x80, 0x80  # F
            ]

        for x in range(0, len(self.font_set)):
            self.memory[x] = self.font_set[x]

    def testing(self):
        for num in range (0, len(self.registers)):
            print("V" + str(num) + ": " +  str(self.registers[num]))
        print("I: " + str(self.register_I))
        print("pc: " + str(self.pc))
        print("sp: " + str(self.sp))
        print("dt: " + str(self.delay_timer))
        print("st: " + str(self.sound_timer))
    def load_rom(self, rom_name):
        """
        Checks if the user entered rom name exists in the proper directory. If the rom exists
        and is a valid Chip-8 rom, it is stored into the proper addresses in the CPU memory.
        """
        print("Loading %s..." % (rom_name))
        os.chdir('..')
        os.chdir('roms')
        try:
            rom = open(rom_name, "rb")
        except IOError:
            print("Rom does not exist, please enter a valid rom file.")
            sys.exit()
        else:
            rom_bytes = rom.read()
            # First 512 bytes are used by the Chip-8 font set.
            if len(rom_bytes) > (4096 - 512):
                print("Rom file is too large, please choose a valid rom file.")
            #print(len(rom_string))
            # Loads rom into memory starting from the address after the first 512 addresses
            for byte in range(0, len(rom_bytes)):
                self.memory[byte + self.pc] = rom_bytes[byte]
            print("Done loading %s!" %(rom_name))
            rom.close()

    def timer_decrement(self):
        if self.delay_timer != 0:
            self.delay_timer -= 1
        if self.sound_timer != 0:
            self.sound_timer -= 1

    def get_opcode(self):
        """
        Combines bytes in adjacent memory addresses to create a 2 byte long opcode. Left shifts the
        first byte by 8 bits and performs a bitwise OR operation to change the created mask into
        the values of the second byte.
        """
        first_byte = self.memory[self.pc]
        second_byte = self.memory[self.pc + 1]
        opcode = (first_byte << 8 | second_byte)
        return opcode

    def perform_opcode(self, opcode):
        """
        Decodes the given opcode by identifying the first hexidecimal value. If required, the last
        hexidecimal value is also identified and the decoded opcode is performed. The pc is then
        advanced based on the opcode.
        """
        # Identify first hex to determine which opcode nibble to perform
        first_hex = opcode & 0xF000
        if first_hex == 0x0000:
            last_hex = opcode & 0x000F
            # Opcode 00E0: clear screen
            if last_hex == 0x0000:
                self.display.clear_display()
                self.draw = True
                self.pc += 2
            # Opcode 00EE: returns from subroutine
            elif last_hex == 0x000E:
                self.sp -= 1
                self.pc = self.stack[self.sp]
                #self.sp -= 1
                self.pc += 2

        # Opcode 1NNN: Jump to address NNN
        elif first_hex == 0x1000:
            # Get last 3 hex values
            address = opcode & 0x0FFF
            self.pc = address

        # Opcode 2NNN: Call subroutine at NNN
        # Adds current pc to stack and increments sp
        elif first_hex == 0x2000:
            address = opcode & 0x0FFF
            self.stack[self.sp] = self.pc
            self.sp += 1
            self.pc = address
        # Opcode 3XKK: Skips next instruction if value stored in register X = KK
        elif first_hex == 0x3000:
            if (self.registers[(opcode & 0x0F00) >> 8] == (opcode & 0x00FF)):
                self.pc += 4
            else:
                self.pc += 2

        # Opcode 4XKK: Skips next instruction if value stored in register X != KK
        elif first_hex == 0x4000:
            if (self.registers[(opcode & 0x0F00) >> 8] != (opcode & 0x00FF)):
                self.pc += 4
            else:
                self.pc += 2

        # Opcode 5XY0: Skips next instruction if value stored in register X = value in register Y
        elif first_hex == 0x5000:
            if (self.registers[(opcode & 0x0F00) >> 8] == self.registers[(opcode & 0x00F0) >> 4]):
                self.pc += 4
            else:
                self.pc += 2

        # Opcode 6XKK: Load KK into register X
        elif first_hex == 0x6000:
            value = opcode & 0x00FF
            self.registers[(opcode & 0x0F00) >> 8] = value
            self.pc += 2

        # Opcode 7XKK: Adds KK to the value in register X and stores it in register X
        elif first_hex == 0x7000:
            self.registers[(opcode & 0x0F00) >> 8] += (opcode & 0x00FF)
            self.pc += 2

        elif first_hex == 0x8000:
            last_hex = opcode & 0x000F
            # Opcode 8XY0: Set value of register X to the value of register Y
            if last_hex == 0x000:
                self.registers[(opcode & 0x0F00) >> 8] = self.registers[(opcode & 0x00F0) >> 4]
                self.pc += 2
            # Opcode 8XY1: Set value of register X to (value of register X OR value of register Y)
            elif last_hex == 0x001:
                self.registers[(opcode & 0x0F00) >> 8] |= self.registers[(opcode & 0x00F0) >> 4]
                self.pc += 2
            # Opcode 8XY2: Set value of register X to (value of register X AND value of register Y)
            elif last_hex == 0x002:
                self.registers[(opcode & 0x0F00) >> 8] &= self.registers[(opcode & 0x00F0) >> 4]
                self.pc += 2
            # Opcode 8XY3: Set value of register X to (value of register X XOR value of register Y)
            elif last_hex == 0x003:
                self.registers[(opcode & 0x0F00) >> 8] ^= self.registers[(opcode & 0x00F0) >> 4]
                self.pc += 2
            # Opcode 8XY4: Set value of register X to (value of register X ADD value of register Y) and set carry
            elif last_hex == 0x004:
                value_sum  = self.registers[(opcode & 0x0F00) >> 8] + self.registers[(opcode & 0x00F0) >> 4]
                # Only keeps the lowest 8 bits if the sum is greater than 0xFF and sets the carry register to 1
                if value_sum > 0xFF:
                    self.registers[0xF] = 1
                    self.registers[(opcode & 0x0F00) >> 8] = (value_sum & 0x00FF)
                else:
                    self.registers[0xF] =0
                    self.registers[(opcode & 0x0F00) >> 8] = value_sum
                self.pc += 2
            # Opcode 8XY5: Set value of register X to (value of register X SUB value of register Y)
            elif last_hex == 0x005:
                # Sets carry register to 0 if there is a borrow else set to 1
                if (self.registers[(opcode & 0x0F00) >> 8] > self.registers[(opcode & 0x00F0) >> 4]):
                    self.registers[0xF] = 1
                else:
                    self.registers[0xF] = 0
                self.registers[(opcode & 0x0F00) >> 8] -= self.registers[(opcode & 0x00F0) >> 4]
                self.pc += 2
            # Opcode 8XY6: Right shift the value of register X by 1
            elif last_hex == 0x006:
                # Keeps the least significant bit of the value of register X in register F
                self.registers[0xF] = (self.registers[(opcode & 0x0F00) >> 8] & 0x0001)
                self.registers[(opcode & 0x0F00) >> 8] = (self.registers[(opcode & 0x0F00) >> 8] >> 1)
                self.pc += 2
            # Opcode 8XY7: Set value of register X to (value of register Y SUB value of register X)
            elif last_hex == 0x007:
                # Sets carry register to 0 if there is a borrow else set to 1
                if (self.registers[(opcode & 0x0F00) >> 8] < self.registers[(opcode & 0x00F0) >> 4]):
                    self.registers[0xF] = 1
                else:
                    self.registers[0xF] = 0
                self.registers[(opcode & 0x0F00) >> 8] = self.registers[(opcode & 0x00F0) >> 4] - self.registers[(opcode & 0x0F00) >> 8]
                self.pc += 2
            # Opcode 8XYE: Left shift the value of register X by 1
            elif last_hex == 0x00E:
                # Keeps the most significant bit of the value of register X in register F
                self.registers[0xF] = (self.registers[(opcode & 0x0F00) >> 8] >> 7)
                self.registers[(opcode & 0x0F00) >> 8] = (self.registers[(opcode & 0x0F00) >> 8] << 1)
                self.pc += 2

        # Opcode 9XY0: Skip next instruction if value of register X != value of register Y
        elif first_hex == 0x9000:
            if self.registers[(opcode & 0x0F00) >> 8] != self.registers[(opcode & 0x00F0) >> 4]:
                self.pc += 4
            else:
                self.pc += 2

        # Opcode ANNN: Set value of register I to NNN
        elif first_hex == 0xA000:
            self.register_I = (opcode & 0x0FFF)
            self.pc += 2

        # Opcode BNNN: Jump to location NNN + value of register 0
        elif first_hex == 0xB000:
            self.pc = (opcode & 0x0FFF) + self.registers[0]

        # Opcode CXKK: Sets the value of register X to (random byte AND KK)
        elif first_hex == 0xC000:
            random_byte = random.randint(0, 255)
            self.registers[(opcode & 0x0F00) >> 8] = (random_byte & (opcode & 0x00FF))
            self.pc += 2

        # Opcode DXYN: Display an N-byte sprite starting at memory location I at (value of register X, value of register Y)
        # If the pixel of the sprite would go past the edge of the screen, wrap it around instead. Sprites are N pixels tall
        # and 8 pixels wide on the standard CHIP-8. Drawing works by performing an XOR on a pixel on the screen with a given
        # bit. Set value of register F to 1 if collision else set it to 0

        elif first_hex == 0xD000:
            height = opcode & 0x000F
            x_coord = self.registers[(opcode & 0x0F00) >> 8]
            y_coord = self.registers[(opcode & 0x00F0) >> 4]
            location = self.register_I
            self.registers[0xF] = 0
            sprite_list = []
            print(str(height))
            for offset in range(0, height):
                sprite_bits = []
                sprite_byte = self.memory[location + offset]
                sprite_byte = (bin(sprite_byte)[2:]).zfill(8)
                for bit in sprite_byte:
                    sprite_bits.append(bit)
                sprite_list.append(sprite_bits)
            """
            for sprite in sprite_list:
                    print(str(sprite))
            """
            for sprite in range(len(sprite_list)):
                increment = 0
                for pixel in sprite_list[sprite]:
                    screen_pixel = self.display.check_pixel((x_coord + increment) % self.display.width, (y_coord + sprite) % self.display.height)
                    pixel_color = int(pixel)
                    if pixel_color == 1 and screen_pixel == 1:
                        self.registers[0xF] = 1
                        pixel_color = 0
                    elif pixel_color == 0 and screen_pixel == 1:
                        pixel_color = 1
                    self.display.set_pixel((x_coord + increment) % self.display.width, (y_coord + sprite) % self.display.height, pixel_color)
                    increment += 1
            self.draw = True
            self.pc += 2

        elif first_hex == 0xE000:
            last_hex = opcode & 0x000F
            # TODO implement pygame keys
            # Opcode EX9E: Skips the next instruction if key with the value of register X is pressed
            if last_hex == 0x000E:
                if self.keys[(opcode & 0x0F00) >> 8] != 0:
                    self.pc += 4
                else:
                    self.pc += 2
            # Opcode EXA1: Skips the next instruction if key with the value of register X is not pressed
            if last_hex == 0x0001:
                if self.keys[(opcode & 0x0F00) >> 8] == 0:
                    self.pc += 4
                else:
                    self.pc +=2

        elif first_hex == 0xF000:
            last_hex = opcode & 0x000F
            # Opcode FX07: Set the value of register X to the value of the delay timer
            if last_hex == 0x0007:
                self.registers[(opcode & 0x0F00) >> 8] = self.delay_timer
                self.pc += 2
            # TODO implement pygame keys
            # Opcode FX0A: Wait for a key press and stores the value of the pressed key into register X
            if last_hex == 0x000A:
                key_was_pressed = False
                while key_was_pressed is not True:
                    for key in range(0, len(self.keys)):
                        if key is not 0:
                            self.registers[(opcode & 0x0F00) >> 8] = key
                            key_was_pressed = True
                self.pc += 2
            # Opcode FX15: Set the value of the delay timer to the value of register X
            if (opcode & 0x00FF) == 0x0015:
                self.delay_timer = self.registers[(opcode & 0x0F00) >> 8]
                self.pc += 2
            # Opcode FX18: Set the value of the sound timer to the value of register X
            if last_hex == 0x0008:
                self.sound_timer = self.registers[(opcode & 0x0F00) >> 8]
                self.pc += 2
            # Opcode FX1E: Set the value of register I to (value of register I + value of register X)
            if last_hex == 0x000E:
                self.register_I += self.registers[(opcode & 0x0F00) >> 8]
                self.pc += 2
            # Opcode FX29: Set value of register I to the location of sprite for the digit of the value of register X
            # Sprites are 5 bytes long so the value of register X must be multiplied by 5
            if last_hex == 0x0009:
                self.register_I = self.registers[(opcode & 0x0F00) >> 8] * 0x5
                self.pc += 2
            # Opcode FX33: Store the binary-coded decimal representation of the value of register X in memory locations I, I+1, and I+2
            if last_hex == 0x0003:
                value = self.registers[(opcode & 0x0F00) >> 8]
                difference = 2
                while difference >= 0:
                    self.memory[self.register_I + difference] = value % 10
                    value = value // 10
                    difference -= 1
                self.pc += 2
            # Opcode Fx55: Store the values of register 0 through X in memory starting in location of the value of register I
            if (opcode & 0x00FF) == 0x0055:
                location = 0
                end = (opcode & 0x0F00) >> 8
                while location <= end:
                    self.memory[self.register_I + location] = self.registers[location]
                    location += 1
                self.pc += 2
            # Opcode FX65: Load the registers 0 through X with values starting from the address of the value of register I
            if (opcode & 0x00FF) == 0x0065:
                location = 0
                end = (opcode & 0x0F00) >> 8
                while location <= end:
                    self.registers[location] = self.memory[self.register_I + location]
                    location += 1
                self.pc += 2
        else:
            print("Invalid opcode, chippy will now quit")
            quit()

    def perform_cycle(self):
        current_opcode = self.get_opcode()
        print(hex(current_opcode))
        if self.test == True:
            self.testing()
        self.perform_opcode(current_opcode)
        self.timer_decrement()
        if self.draw == True:
            self.display.update_display()
            self.draw = False


"""

For a given aws account, go through all un-attached volumes and tag them.

"""
import boto
import boto.utils
import argparse
import logging
import subprocess
import time
import os
from os.path import join, exists, isdir, islink, realpath, basename, dirname
import yaml
# needs to be pip installed
import netaddr

LOG_FORMAT = "%(asctime)s %(levelname)s - %(filename)s:%(lineno)s - %(message)s"
TIMEOUT = 300

log_level = logging.INFO

def tags_for_hostname(hostname, mapping):
    logging.debug("Hostname is {}".format(hostname))
    if not hostname.startswith('ip-'):
        return {}

    octets = hostname.lstrip('ip-').split('-')
    tags = {}

    # Update with env and deployment info
    tags.update(mapping['CIDR_SECOND_OCTET'][octets[1]])

    ip_addr = netaddr.IPAddress(".".join(octets))
    for key, value in mapping['CIDR_REST'].items():
        cidr = ".".join([
            mapping['CIDR_FIRST_OCTET'],
            octets[1],
            key])

        cidrset = netaddr.IPSet([cidr])

        if ip_addr in cidrset:
            tags.update(value)

    return tags

def potential_devices(root_device):
    device_dir = dirname(root_device)
    relevant_devices = lambda x: x.startswith(basename(root_device))

    all_devices = os.listdir(device_dir)
    all_devices = filter(relevant_devices, all_devices)

    logging.info("Potential devices on {}: {}".format(root_device, all_devices))
    if len(all_devices) > 1:
        all_devices.remove(basename(root_device))

    return map(lambda x: join(device_dir, x), all_devices)

def get_tags_for_disk(mountpoint):
    tag_data = {}
    # Look at some files on it to determine:
    #  - hostname
    #  - environment
    #  - deployment
    #  - cluster
    #  - instance-id
    #  - date created
    hostname_file = join(mountpoint, "etc", "hostname")
    edx_dir = join(mountpoint, 'edx', 'app')
    if exists(hostname_file):
        # This means this was a root volume.
        with open(hostname_file, 'r') as f:
            hostname = f.readline().strip()
            tag_data['hostname'] = hostname

        if exists(edx_dir) and isdir(edx_dir):
            # This is an ansible related ami, we'll try to map
            # the hostname to a knows deployment and cluster.
            cluster_tags = tags_for_hostname(hostname, mappings)
            tag_data.update(cluster_tags)
        else:
            # Not an ansible created root volume.
            tag_data['cluster'] = 'unknown'
    else:
        # Not a root volume
        tag_data['cluster'] = "unknown"

    instance_file = join(mountpoint, "var", "lib", "cloud", "instance")
    if exists(instance_file) and islink(instance_file):
        resolved_path = realpath(instance_file)
        old_instance_id = basename(resolved_path)
        tag_data['instance-id'] = old_instance_id

    return tag_data

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Tag unattached ebs volumes.")
    parser.add_argument("--profile", '-p',
        help="AWS Profile to use with boto.")
    parser.add_argument("--noop", "-n", action="store_true",
        help="Don't actually tag anything.")
    parser.add_argument("--verbose", "-v", action="store_true",
        help="More verbose output.")
    parser.add_argument("--device", "-d", default="/dev/xvdf",
        help="The /dev/??? where the volume should be mounted.")
    parser.add_argument("--mountpoint", "-m", default="/mnt",
        help="Location to mount the new device.")
    parser.add_argument("--config", "-c", required=True,
        help="Configuration to map hostnames to tags.")
    # The config should specify what tags to associate with the second
    # and this octet of the hostname which should be the ip address.
    # example:

    args = parser.parse_args()

    mappings = yaml.safe_load(open(args.config,'r'))

    # Setup Logging
    if args.verbose:
        log_level = logging.DEBUG

    logging.basicConfig(format=LOG_FORMAT, level=log_level)

    # setup boto
    ec2 = boto.connect_ec2(profile_name=args.profile)

    # get mounting args
    id_info = boto.utils.get_instance_identity()['document']
    instance_id = id_info['instanceId']
    az = id_info['availabilityZone']
    root_device = args.device
    mountpoint = args.mountpoint

    # Find all unattached volumes
    filters = { "status": "available", "availability-zone": az }
    potential_volumes = ec2.get_all_volumes(filters=filters)
    logging.debug("Found {} unattached volumes in {}".format(len(potential_volumes), az))

    for vol in potential_volumes:
        if "cluster" in vol.tags:
            continue
        # Attach volume to the instance running this process
        logging.debug("Trying to attach {} to {} at {}".format(
            vol.id, instance_id, root_device))

        try:
            ec2.attach_volume(vol.id, instance_id, root_device)
            # Wait for the volume to finish attaching.
            waiting_msg = "Waiting for {} to be available at {}"
            timeout = TIMEOUT
            while not exists(root_device):
                time.sleep(2)
                logging.debug(waiting_msg.format(vol.id, root_device))
                timeout -= 2
                if timeout <= 0:
                    logging.critical("Timed out while attaching {}.".format(vol.id))
                    exit(1)

            # Because a volume might have multiple mount points
            devices_on_volume = potential_devices(root_device)
            if len(devices_on_volume) != 1:
                vol.add_tag("devices_on_volume", str(devices_on_volume))
                # Don't tag in this case because the different devices
                # may have conflicting tags.
                logging.info("Skipping {} because it has multiple mountpoints.".format(vol.id))
                logging.info("{} has mountpoints {}".format(vol.id, str(devices_on_volume)))
            else:
                device = devices_on_volume[0]
                try:
                    # Mount the volume
                    subprocess.check_call(["sudo", "mount", device, mountpoint])

                    # Learn all tags we can know from content on disk.
                    tag_data = get_tags_for_disk(mountpoint)
                    tag_data['created'] = vol.create_time

                    # If they are found tag the instance with them
                    if args.noop:
                        logging.info("Would have tagged {} with: \n{}".format(vol.id, str(tag_data)))
                    else:
                        logging.info("Tagging {} with: \n{}".format(vol.id, str(tag_data)))
                        vol.add_tags(tag_data)
                finally:
                    # Un-mount the volume
                    subprocess.check_call(['sudo', 'umount', mountpoint])
        finally:
            # Need this to be a function so we always re-check the API for status.
            is_attached = lambda vol_id: ec2.get_all_volumes(vol_id)[0].status != "available"
            timeout = TIMEOUT
            while exists(root_device) or is_attached(vol.id):
                if is_attached(vol.id):
                    try:
                        # detach the volume
                        ec2.detach_volume(vol.id)
                    except boto.exception.EC2ResponseError as e:
                        logging.warning("Failed to detach volume.  Will try again in a bit.")
                time.sleep(2)
                timeout -= 2
                if timeout <= 0:
                    logging.critical("Timed out while detaching {}.".format(vol.id))
                    exit(1)
                logging.debug("Waiting for {} to be detached.".format(vol.id))


from collections import defaultdict
from itertools import product, chain
from math import sqrt, floor, ceil

from PyQt4.QtCore import Qt, QSize
from PyQt4.QtGui import (QGraphicsScene, QGraphicsView, QColor, QPen, QBrush,
                         QDialog, QApplication, QSizePolicy)

import Orange
from Orange.data import Table, filter
from Orange.data.sql.table import SqlTable, LARGE_TABLE, DEFAULT_SAMPLE_TIME
from Orange.statistics.contingency import get_contingency
from Orange.widgets import gui
from Orange.widgets.settings import DomainContextHandler, ContextSetting
from Orange.widgets.utils import getHtmlCompatibleString
from Orange.widgets.utils.itemmodels import VariableListModel
from Orange.widgets.visualize.owmosaic import (OWCanvasText, OWCanvasRectangle,
                                               OWCanvasLine)
from Orange.widgets.widget import OWWidget, Default, AttributeList

class _ViewWithPress(QGraphicsView):
    def __init__(self, *args, **kwargs):
        self.handler = kwargs.pop("handler")
        super().__init__(*args, **kwargs)

    def mousePressEvent(self, ev):
        super().mousePressEvent(ev)
        if not ev.isAccepted():
            self.handler()

class OWSieveDiagram(OWWidget):
    name = "Sieve Diagram"
    description = "A two-way contingency table providing information in " \
                  "relation to expected frequency of combination of feature " \
                  "values under independence."
    icon = "icons/SieveDiagram.svg"
    priority = 4200

    inputs = [("Data", Table, "set_data", Default),
              ("Features", AttributeList, "set_input_features")]
    outputs = [("Selection", Table)]

    graph_name = "canvas"

    want_control_area = False

    settingsHandler = DomainContextHandler()
    attrX = ContextSetting("")
    attrY = ContextSetting("")
    selection = ContextSetting(set())

    def __init__(self):
        super().__init__()

        self.data = None
        self.input_features = None
        self.attrs = []

        self.attr_box = gui.hBox(self.mainArea)
        model = VariableListModel()
        model.wrap(self.attrs)
        self.attrXCombo = gui.comboBox(
            self.attr_box, self, value="attrX", contentsLength=12,
            callback=self.change_attr, sendSelectedValue=True, valueType=str)
        self.attrXCombo.setModel(model)
        gui.widgetLabel(self.attr_box, "\u2715").\
            setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.attrYCombo = gui.comboBox(
            self.attr_box, self, value="attrY", contentsLength=12,
            callback=self.change_attr, sendSelectedValue=True, valueType=str)
        self.attrYCombo.setModel(model)

        self.canvas = QGraphicsScene()
        self.canvasView = _ViewWithPress(self.canvas, self.mainArea,
                                         handler=self.reset_selection)
        self.mainArea.layout().addWidget(self.canvasView)
        self.canvasView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.canvasView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        box = gui.hBox(self.mainArea)
        gui.button(box, None, "&Save Graph",
                   callback=self.save_graph, autoDefault=False)
        gui.button(box, None, "&Report",
                   callback=self.show_report, autoDefault=False)

    def sizeHint(self):
        return QSize(450, 550)

    def set_data(self, data):
        if type(data) == SqlTable and data.approx_len() > LARGE_TABLE:
            data = data.sample_time(DEFAULT_SAMPLE_TIME)

        self.closeContext()
        self.data = data
        self.areas = []
        if self.data is None:
            self.attrs[:] = []
        else:
            self.attrs[:] = [
                var for var in chain(self.data.domain.attributes,
                                     self.data.domain.metas)
                if var.is_discrete
            ]
        if self.attrs:
            self.attrX = self.attrs[0].name
            self.attrY = self.attrs[len(self.attrs) > 1].name
        else:
            self.attrX = self.attrY = None
        self.openContext(self.data)

        self.information(0, "")
        if data and any(attr.is_continuous for attr in data.domain):
            self.information(0, "Data contains continuous variables. "
                                "Discretize the data to use them.")
        self.resolve_shown_attributes()
        self.update_selection()

    def change_attr(self):
        self.selection = set()
        self.updateGraph()
        self.update_selection()

    def set_input_features(self, attrList):
        self.input_features = attrList
        self.resolve_shown_attributes()
        self.update_selection()

    def resolve_shown_attributes(self):
        self.warning(1)
        self.attr_box.setEnabled(True)
        if self.input_features:  # non-None and non-empty!
            features = [f for f in self.input_features if f in self.attrs]
            if not features:
                self.warning(1, "Features from the input signal "
                                "are not present in the data")
            else:
                old_attrs = self.attrX, self.attrY
                self.attrX, self.attrY = [f.name for f in (features * 2)[:2]]
                self.attr_box.setEnabled(False)
                if (self.attrX, self.attrY) != old_attrs:
                    self.selection = set()
        # else: do nothing; keep current features, even if input with the
        # features just changed to None
        self.updateGraph()

    def resizeEvent(self, e):
        OWWidget.resizeEvent(self,e)
        self.updateGraph()

    def showEvent(self, ev):
        OWWidget.showEvent(self, ev)
        self.updateGraph()

    def reset_selection(self):
        self.selection = set()
        self.update_selection()

    def select_area(self, area, ev):
        if ev.button() != Qt.LeftButton:
            return
        index = self.areas.index(area)
        if ev.modifiers() & Qt.ControlModifier:
            self.selection ^= {index}
        else:
            self.selection = {index}
        self.update_selection()

    def update_selection(self):
        if self.areas is None or not self.selection:
            self.send("Selection", None)
            return

        filters = []
        for i, area in enumerate(self.areas):
            if i in self.selection:
                width = 4
                val_x, val_y = area.value_pair
                filters.append(
                    filter.Values([
                        filter.FilterDiscrete(self.attrX, [val_x]),
                        filter.FilterDiscrete(self.attrY, [val_y])
                    ]))
            else:
                width = 1
            pen = area.pen()
            pen.setWidth(width)
            area.setPen(pen)
        if len(filters) == 1:
            filters = filters[0]
        else:
            filters = filter.Values(filters, conjunction=False)
        self.send("Selection", filters(self.data))

    # -----------------------------------------------------------------------
    # Everything from here on is ancient and has been changed only according
    # to what has been changed above. Some clean-up may be in order some day
    #
    def updateGraph(self, *args):
        for item in self.canvas.items():
            self.canvas.removeItem(item)
        if self.data is None or len(self.data) == 0 or \
                self.attrX is None or self.attrY is None:
            return
        data = self.data[:, [self.attrX, self.attrY]]
        valsX = []
        valsY = []
        contX = get_contingency(data, self.attrX, self.attrX)
        contY = get_contingency(data, self.attrY, self.attrY)
        # compute contingency of x and y attributes
        for entry in contX:
            sum_ = 0
            try:
                for val in entry: sum_ += val
            except: pass
            valsX.append(sum_)

        for entry in contY:
            sum_ = 0
            try:
                for val in entry: sum_ += val
            except: pass
            valsY.append(sum_)

        contXY = self.getConditionalDistributions(data, [data.domain[self.attrX], data.domain[self.attrY]])
        # compute probabilities
        probs = {}
        for i in range(len(valsX)):
            valx = valsX[i]
            for j in range(len(valsY)):
                valy = valsY[j]

                actualProb = 0
                try:
                    actualProb = contXY['%s-%s' %(data.domain[self.attrX].values[i], data.domain[self.attrY].values[j])]
                    # for val in contXY['%s-%s' %(i, j)]: actualProb += val
                except:
                    actualProb = 0
                probs['%s-%s' %(data.domain[self.attrX].values[i], data.domain[self.attrY].values[j])] = ((data.domain[self.attrX].values[i], valx), (data.domain[self.attrY].values[j], valy), actualProb, len(data))

        #get text width of Y labels
        max_ylabel_w = 0
        for j in range(len(valsY)):
            xl = OWCanvasText(self.canvas, "", 0, 0, htmlText = getHtmlCompatibleString(data.domain[self.attrY].values[j]), show=False)
            max_ylabel_w = max(int(xl.boundingRect().width()), max_ylabel_w)
        max_ylabel_w = min(max_ylabel_w, 200) #upper limit for label widths
        # get text width of Y attribute name
        text = OWCanvasText(self.canvas, data.domain[self.attrY].name, x  = 0, y = 0, bold = 1, show = 0, vertical=True)
        xOff = int(text.boundingRect().height() + max_ylabel_w)
        yOff = 55
        sqareSize = min(self.canvasView.width() - xOff - 35, self.canvasView.height() - yOff - 50)
        sqareSize = max(sqareSize, 10)
        self.canvasView.setSceneRect(0, 0, self.canvasView.width(), self.canvasView.height())

        # print graph name
        name  = "P(%s, %s) ≠ P(%s)×P(%s)" %(self.attrX, self.attrY, self.attrX, self.attrY)
        OWCanvasText(self.canvas, "" , xOff+ sqareSize/2, 20, Qt.AlignCenter, htmlText = name)
        OWCanvasText(self.canvas, "N = " + str(len(data)), xOff+ sqareSize/2, 38, Qt.AlignCenter, bold = 0)

        ######################
        # compute chi-square
        chisquare = 0.0
        for i in range(len(valsX)):
            for j in range(len(valsY)):
                ((xAttr, xVal), (yAttr, yVal), actual, sum_) = probs['%s-%s' %(data.domain[self.attrX].values[i], data.domain[self.attrY].values[j])]
                expected = float(xVal*yVal)/float(sum_)
                if expected == 0: continue
                pearson2 = (actual - expected)*(actual - expected) / expected
                chisquare += pearson2

        ######################
        # draw rectangles
        currX = xOff
        max_xlabel_h = 0
        normX, normY = sum(valsX), sum(valsY)
        self.areas = []
        for i in range(len(valsX)):
            if valsX[i] == 0: continue
            currY = yOff
            width = int(float(sqareSize * valsX[i])/float(normX))

            for j in range(len(valsY)-1, -1, -1):   # this way we sort y values correctly
                ((xAttr, xVal), (yAttr, yVal), actual, sum_) = probs['%s-%s' %(data.domain[self.attrX].values[i], data.domain[self.attrY].values[j])]
                if valsY[j] == 0: continue
                height = int(float(sqareSize * valsY[j])/float(normY))

                # create rectangle
                selected = len(self.areas) in self.selection
                rect = OWCanvasRectangle(
                    self.canvas, currX+2, currY+2, width-4, height-4, z = -10,
                    onclick=self.select_area)
                rect.value_pair = i, j
                self.areas.append(rect)
                self.addRectIndependencePearson(rect, currX+2, currY+2, width-4, height-4, (xAttr, xVal), (yAttr, yVal), actual, sum_,
                    width=1 + 3 * selected,  # Ugly! This is needed since
                    # resize redraws the graph! When this is handled by resizing
                    # just the viewer, update_selection will take care of this
                    )

                expected = float(xVal*yVal)/float(sum_)
                pearson = (actual - expected) / sqrt(expected)
                tooltipText = """X Attribute: %s
Value: %s
Number of instances (p(x)): %d (%.2f%%)

                                Y Attribute: %s
Value: %s
Number of instances (p(y)): %d (%.2f%%)

                                Number Of Instances (Probabilities):
Expected (p(x)p(y)): %.1f (%.2f%%)
Actual (p(x,y)): %d (%.2f%%)

Statistics:
Chi-square: %.2f
Standardized Pearson residual: %.2f""" %(self.attrX, getHtmlCompatibleString(xAttr), xVal, 100.0*float(xVal)/float(sum_), self.attrY, getHtmlCompatibleString(yAttr), yVal, 100.0*float(yVal)/float(sum_), expected, 100.0*float(xVal*yVal)/float(sum_*sum_), actual, 100.0*float(actual)/float(sum_), chisquare, pearson )
                rect.setToolTip(tooltipText)

                currY += height
                if currX == xOff:
                    OWCanvasText(self.canvas, "", xOff, currY - height/2, Qt.AlignRight | Qt.AlignVCenter, htmlText = getHtmlCompatibleString(data.domain[self.attrY].values[j]))

            xl = OWCanvasText(self.canvas, "", currX + width/2, yOff + sqareSize, Qt.AlignHCenter | Qt.AlignTop, htmlText = getHtmlCompatibleString(data.domain[self.attrX].values[i]))
            max_xlabel_h = max(int(xl.boundingRect().height()), max_xlabel_h)

            currX += width

        # show attribute names
        OWCanvasText(self.canvas, self.attrY, 0, yOff + sqareSize/2, Qt.AlignLeft | Qt.AlignVCenter, bold = 1, vertical=True)
        OWCanvasText(self.canvas, self.attrX, xOff + sqareSize/2, yOff + sqareSize + max_xlabel_h, Qt.AlignHCenter | Qt.AlignTop, bold = 1)

    # create a dictionary with all possible pairs of "combination-of-attr-values" : count
    def getConditionalDistributions(self, data, attrs):
        cond_dist = defaultdict(int)
        all_attrs = [data.domain[a] for a in attrs]
        if data.domain.class_var is not None:
            all_attrs.append(data.domain.class_var)

        for i in range(1, len(all_attrs) + 1):
            attr = all_attrs[:i]
            if type(data) == SqlTable:
                # make all possible pairs of attributes + class_var
                attr = [a.to_sql() for a in attr]
                fields = attr + ["COUNT(*)"]
                query = data._sql_query(fields, group_by=attr)
                with data._execute_sql_query(query) as cur:
                    res = cur.fetchall()
                for r in res:
                    str_values =[a.repr_val(a.to_val(x)) for a, x in zip(all_attrs, r[:-1])]
                    str_values = [x if x != '?' else 'None' for x in str_values]
                    cond_dist['-'.join(str_values)] = r[-1]
            else:
                for indices in product(*(range(len(a.values)) for a in attr)):
                    vals = []
                    conditions = []
                    for k, ind in enumerate(indices):
                        vals.append(attr[k].values[ind])
                        fd = Orange.data.filter.FilterDiscrete(column=attr[k], values=[attr[k].values[ind]])
                        conditions.append(fd)
                    filt = Orange.data.filter.Values(conditions)
                    filtdata = filt(data)
                    cond_dist['-'.join(vals)] = len(filtdata)
        return cond_dist

    ######################################################################
    ## show deviations from attribute independence with standardized pearson residuals
    def addRectIndependencePearson(self, rect, x, y, w, h, xAttr_xVal, yAttr_yVal, actual, sum, width):
        xAttr, xVal = xAttr_xVal
        yAttr, yVal = yAttr_yVal
        expected = float(xVal*yVal)/float(sum)
        pearson = (actual - expected) / sqrt(expected)

        if pearson > 0:     # if there are more examples that we would expect under the null hypothesis
            intPearson = floor(pearson)
            pen = QPen(QColor(0,0,255), width); rect.setPen(pen)
            b = 255
            r = g = 255 - intPearson*20
            r = g = max(r, 55)  #
        elif pearson < 0:
            intPearson = ceil(pearson)
            pen = QPen(QColor(255,0,0), width)
            rect.setPen(pen)
            r = 255
            b = g = 255 + intPearson*20
            b = g = max(b, 55)
        else:
            pen = QPen(QColor(255,255,255), width)
            r = g = b = 255         # white
        color = QColor(r,g,b)
        brush = QBrush(color); rect.setBrush(brush)

        if pearson > 0:
            pearson = min(pearson, 10)
            kvoc = 1 - 0.08 * pearson       #  if pearson in [0..10] --> kvoc in [1..0.2]
        else:
            pearson = max(pearson, -10)
            kvoc = 1 - 0.4*pearson

        self.addLines(x,y,w,h, kvoc, pen)

    ##################################################
    # add lines
    def addLines(self, x,y,w,h, diff, pen):
        if w == 0 or h == 0: return

        # create lines
        dist = 20   # original distance between two lines in pixels
        dist = dist * diff
        temp = dist
        while (temp < w):
            OWCanvasLine(self.canvas, temp+x, y, temp+x, y+h, 1, pen.color())
            temp += dist

        temp = dist
        while (temp < h):
            OWCanvasLine(self.canvas, x, y+temp, x+w, y+temp, 1, pen.color())
            temp += dist

    def closeEvent(self, ce):
        QDialog.closeEvent(self, ce)

    def get_widget_name_extension(self):
        if self.data is not None:
            return "{} vs {}".format(self.attrX, self.attrY)

    def send_report(self):
        self.report_plot()

# test widget appearance
if __name__=="__main__":
    import sys
    a=QApplication(sys.argv)
    ow=OWSieveDiagram()
    ow.show()
    data = Table(r"zoo.tab")
    ow.set_data(data)
    a.exec_()
    ow.saveSettings()


"""
Views related to course tabs
"""
from access import has_course_access
from util.json_request import expect_json, JsonResponse

from django.http import HttpResponseNotFound
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django_future.csrf import ensure_csrf_cookie
from django.views.decorators.http import require_http_methods
from edxmako.shortcuts import render_to_response
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.django import loc_mapper
from xmodule.modulestore.locator import BlockUsageLocator
from xmodule.tabs import CourseTabList, StaticTab, CourseTab, InvalidTabsException

from ..utils import get_modulestore, get_lms_link_for_item

__all__ = ['tabs_handler']

@expect_json
@login_required
@ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT"))
def tabs_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
    """
    The restful handler for static tabs.

    GET
        html: return page for editing static tabs
        json: not supported
    PUT or POST
        json: update the tab order. It is expected that the request body contains a JSON-encoded dict with entry "tabs".
        The value for "tabs" is an array of tab locators, indicating the desired order of the tabs.

    Creating a tab, deleting a tab, or changing its contents is not supported through this method.
    Instead use the general xblock URL (see item.xblock_handler).
    """
    locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
    if not has_course_access(request.user, locator):
        raise PermissionDenied()

    old_location = loc_mapper().translate_locator_to_location(locator)
    store = get_modulestore(old_location)
    course_item = store.get_item(old_location)

    if 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'):
        if request.method == 'GET':
            raise NotImplementedError('coming soon')
        else:
            if 'tabs' in request.json:
                return reorder_tabs_handler(course_item, request)
            elif 'tab_id_locator' in request.json:
                return edit_tab_handler(course_item, request)
            else:
                raise NotImplementedError('Creating or changing tab content is not supported.')

    elif request.method == 'GET':  # assume html
        # get all tabs from the tabs list: static tabs (a.k.a. user-created tabs) and built-in tabs
        # present in the same order they are displayed in LMS

        tabs_to_render = []
        for tab in CourseTabList.iterate_displayable_cms(
                course_item,
                settings,
        ):
            if isinstance(tab, StaticTab):
                # static tab needs its locator information to render itself as an xmodule
                static_tab_loc = old_location.replace(category='static_tab', name=tab.url_slug)
                tab.locator = loc_mapper().translate_location(
                    course_item.location.course_id, static_tab_loc, False, True
                )
            tabs_to_render.append(tab)

        return render_to_response('edit-tabs.html', {
            'context_course': course_item,
            'tabs_to_render': tabs_to_render,
            'course_locator': locator,
            'lms_link': get_lms_link_for_item(course_item.location),
        })
    else:
        return HttpResponseNotFound()

def reorder_tabs_handler(course_item, request):
    """
    Helper function for handling reorder of tabs request
    """

    # Tabs are identified by tab_id or locators.
    # The locators are used to identify static tabs since they are xmodules.
    # Although all tabs have tab_ids, newly created static tabs do not know
    # their tab_ids since the xmodule editor uses only locators to identify new objects.
    requested_tab_id_locators = request.json['tabs']

    # original tab list in original order
    old_tab_list = course_item.tabs

    # create a new list in the new order
    new_tab_list = []
    for tab_id_locator in requested_tab_id_locators:
        tab = get_tab_by_tab_id_locator(old_tab_list, tab_id_locator)
        if tab is None:
            return JsonResponse(
                {"error": "Tab with id_locator '{0}' does not exist.".format(tab_id_locator)}, status=400
            )
        new_tab_list.append(tab)

    # the old_tab_list may contain additional tabs that were not rendered in the UI because of
    # global or course settings.  so add those to the end of the list.
    non_displayed_tabs = set(old_tab_list) - set(new_tab_list)
    new_tab_list.extend(non_displayed_tabs)

    # validate the tabs to make sure everything is Ok (e.g., did the client try to reorder unmovable tabs?)
    try:
        CourseTabList.validate_tabs(new_tab_list)
    except InvalidTabsException, exception:
        return JsonResponse(
            {"error": "New list of tabs is not valid: {0}.".format(str(exception))}, status=400
        )

    # persist the new order of the tabs
    course_item.tabs = new_tab_list
    modulestore('direct').update_item(course_item, request.user.id)

    return JsonResponse()

def edit_tab_handler(course_item, request):
    """
    Helper function for handling requests to edit settings of a single tab
    """

    # Tabs are identified by tab_id or locator
    tab_id_locator = request.json['tab_id_locator']

    # Find the given tab in the course
    tab = get_tab_by_tab_id_locator(course_item.tabs, tab_id_locator)
    if tab is None:
        return JsonResponse(
            {"error": "Tab with id_locator '{0}' does not exist.".format(tab_id_locator)}, status=400
        )

    if 'is_hidden' in request.json:
        # set the is_hidden attribute on the requested tab
        tab.is_hidden = request.json['is_hidden']
        modulestore('direct').update_item(course_item, request.user.id)
    else:
        raise NotImplementedError('Unsupported request to edit tab: {0}'.format(request.json))

    return JsonResponse()

def get_tab_by_tab_id_locator(tab_list, tab_id_locator):
    """
    Look for a tab with the specified tab_id or locator.  Returns the first matching tab.
    """
    if 'tab_id' in tab_id_locator:
        tab = CourseTabList.get_tab_by_id(tab_list, tab_id_locator['tab_id'])
    elif 'tab_locator' in tab_id_locator:
        tab = get_tab_by_locator(tab_list, tab_id_locator['tab_locator'])
    return tab

def get_tab_by_locator(tab_list, tab_locator):
    """
    Look for a tab with the specified locator.  Returns the first matching tab.
    """
    tab_location = loc_mapper().translate_locator_to_location(BlockUsageLocator(tab_locator))
    item = modulestore('direct').get_item(tab_location)
    static_tab = StaticTab(
        name=item.display_name,
        url_slug=item.location.name,
    )
    return CourseTabList.get_tab_by_id(tab_list, static_tab.tab_id)

# "primitive" tab edit functions driven by the command line.
# These should be replaced/deleted by a more capable GUI someday.
# Note that the command line UI identifies the tabs with 1-based
# indexing, but this implementation code is standard 0-based.

def validate_args(num, tab_type):
    "Throws for the disallowed cases."
    if num <= 1:
        raise ValueError('Tabs 1 and 2 cannot be edited')
    if tab_type == 'static_tab':
        raise ValueError('Tabs of type static_tab cannot be edited here (use Studio)')

def primitive_delete(course, num):
    "Deletes the given tab number (0 based)."
    tabs = course.tabs
    validate_args(num, tabs[num].get('type', ''))
    del tabs[num]
    # Note for future implementations: if you delete a static_tab, then Chris Dodge
    # points out that there's other stuff to delete beyond this element.
    # This code happens to not delete static_tab so it doesn't come up.
    modulestore('direct').update_item(course, '**replace_user**')

def primitive_insert(course, num, tab_type, name):
    "Inserts a new tab at the given number (0 based)."
    validate_args(num, tab_type)
    new_tab = CourseTab.from_json({u'type': unicode(tab_type), u'name': unicode(name)})
    tabs = course.tabs
    tabs.insert(num, new_tab)
    modulestore('direct').update_item(course, '**replace_user**')


Kelly: Oh! Oh! Can I pick the first question?
Jessica: Sure. Go for it!
Kelly: What's the scariest place you've been to!
Jessica: I'll start: Palermo in Italy.
Mickey: And what's so scary about that? Did you break your nail? :P
Jessica: Shut it, Mickey! No, there are the Capuchin Catacombs with 8000 corpses!
Kelly: Ewwww! Corpses? Rly?
Jessica: Yeah! And you can look at them like museum exhibits. I think they're divided somehow, but have no clue how!
Ollie: That's so cool! Do you get to see the bones or are they covered up?
Jessica: Well, partly. Most of them were exhibited in their clothes. Basically only skulls and hands.
Mickey: I'm writing this one down! That's so precious!
Ollie: Me too!

The scariest place for Jessica was the Capuchin Catacombs in Palermo.


Carrie: Just back from Fantastic Beast :)
Gina: and what do you think?
Carrie: generally good - as usual nice special effect and visuals, an ok plot, a glimpse of the wizarding community in the US.
Alex: Sounds cool. I was thinking of going this weekend with Lane, but I've seen some bad reviews.
Carrie: Depends on what you expect really - I have a lot of sentiment towards Harry Potter so, I'm gonna like everything the do. But seriously the movie was decent. However, if you're expecting to have your mind blown, then no, it's not THAT good.
Gina: I agree. I saw it last week and basically I'm satisfied.
Alex: No spoilers, girls.
Carrie: no worries ;)
Carrie: And Gina, what do you think about Eddie Redmayne as Newt?
Gina: I loved him <3 I loved how introverted and awkward he was and how caring he was towards the animals. And with all that he showed a lot of confidence in his beliefs and was a genuinely compassionate character
Carrie: not your standard protagonist, that's for sure
Gina: and that's what I liked about him
Alex: Maybe I'll go and see it sooner so we can all talk about it.
Carrie: go see it. If' you're not expecting god-knows-what you're going to enjoy it ;)

Carrie and Gina saw "Fantastic Beast" and liked it. Ginna loved Eddie Redmayne as Newt.


Samantha: How are you doing today?
Robyn: better, but I really exaggerated with bier last night
Samantha: was it really only bier?
Robyn: sure, why?
Samantha: I don't know, your eyes, behaviour
Robyn: you want to say I took drugs?
Samantha: I'm only asking, I don't have anything against drugs
Robyn: but I have and I never take them
Samantha: ok, sorry, I didn't intend to offend you
Robyn: I just drank too much, that's eat
Samantha: much too much
Robyn: yes, I lost control a bit
Robyn: I am sorry for that
Samantha: important that you feel better today

Robyn drank too much beer last night and lost control. She is feeling better today.


Peyton: I have been asking you to bring that video game for me
Cameron: Honey, I am not having enough time to come home
Peyton: When would you come home?
Cameron: I will have to stay out of town for another week i guess
Peyton: Cant you just deliver that game through the courier? :P
Cameron: Dont be mean :/
Peyton: Get the job done and come to home then. ASAP :P

Peyton is expecting Cameron to bring the video game. Cameron will probably be out for another week.


Gene: Did you get the package I sent you
Jack: No, when did you send it?
Gene: on Friday
Jack: shit I should have gotten it by now
Jack: send me the tracking umber I;ll check whats up
Gene: 12345678900

Jack has not received yet the package Gene had sent him on Friday. She sent him the tracking number, so he could check the status of the shipment.


Russ: Hi Gurdun, are you feeling better?
Gurdun: Hi Ross, a little bit better, yes, thank you.
Russ: Do you think you'll be back at the uni this week?
Gurdun: Not tomorrow for sure, but I hope Wednesday maybe.
Russ: Oh, that's fine.
Gurdun: Yeah. I'm feeling a bit weak still
Russ: I guess that's pretty normal at this stage.
Gurdun: I believe so. And the muscle pain.
Russ: I know what you mean. I had flu like that three months ago.
Gurdun: Luckily the headache's gone. It was absolutely awful.
Russ: True enough. I had the same.
Gurdun: Anyway, how are things with you?
Russ: Same old, same old, you know. Not much happening in the middle of term.
Gurdun: And the team?
Russ: Oh yeah, we won the last match. It was a good game.
Gurdun: Great. Listen Russ, I need to run. Catch up later.
Russ: OK, talk to you later.

Gurdun has the flu. He is feeling better. Gurdun hopes he'll be back at the uni on Wednesday. Russ and his team won the last match.


Susan: Will you be home tomorrow?
Rob: Why do you ask?
Susan: We could have dinner together if you have time after work
Rob: Sure! Sounds great
Susan: Fantastic! I will cook something special then!

Rob will be home tomorrow. Rob and Susan will have dinner together after Rob's work. Susan will cook something special.


Evan: Hi Dennis, I need to cancel my lesson tomorrow, sorry.
Dennis: Fine, what's up?
Evan: Oh, got the flu, been off college since Tuesday. Should be ok for next Thurs.
Dennis: OK, just tell me in good time if you can't make it. Hope you feel better soon.
Evan: Bye, Den! Thanks.

Evan can't come to his lesson tomorrow, because he's got the flu.


Lorena: Hi, can you help me with something?
Martin: Well, I can try.
Martin: Depends what it is?
Lorena: I got a new desk and it comes with assembly instructions but I give up, I just can't do it.
Lorena: I'm illiterate when it comes to instructions, haha.
Lorena: So I could really use some help...
Martin: Hmm, I can't today, but how about tomorrow? Shouldn't take long anyway.
Lorena: Yeah, it's fine! I just need it for the weekend, but tomorrow's great! Sorry for troubling you again.
Martin: Don't mention it, we've known each other for so long it's almost like we're siblings, haha.
Lorena: Thanks a lot! I should be home by 6, so let me know when you can.

Martin is going to help Lorena assemble a new desk. He is coming to her house tomorrow.


Joanna: They are sending emails about Lewandowska.
Merve: What happened?
Joanna: <file_photo>
Merve: Wooow!
Joanna: She is hospitalized because she has measles.
Merve: She had what?
Joanna: Anyone who had contact with her within the last couple of days must get vaccinated.
Merve: Luckily I didn't see her since the last semester...
Joanna: I did, she is my thesis mentor :(
Merve: What will you do?
Joanna: They are organizing vaccinations in the main building from 17th until 19th.
Merve: You have to go!
Joanna: I know... And I just started working so I really don't have a lot of time.
Merve: Come on, this is really important.
Joanna: I will try to do it before work on 18th, hopefully I won't lose the entire day...

Lewandowska has measles. There are vaccinations in the main building from 17th until 19th for everyone who had contact with her.


sunwing five two zero three climb to flight level three six zero


delta echo bravo turn left one zero degrees climb flight level three seven zero


lufthansa four three seven six good afternoon maintain level two nine zero direct to st prex


belgian airforce three three four contact reims one three four decimal four au revoir


alitalia one five zero climb to flight level three hundred


french air force four two three four contact reims one three four decimal four bye bye


condor triple six geneva one two eigh sorry one three three one five


lufthansa four five eight two rhein do you read me


By . Daily Mail Reporter . PUBLISHED: . 08:45 EST, 3 February 2014 . | . UPDATED: . 11:28 EST, 3 February 2014 . A British oil worker is believed to have been abducted by gunmen in Sanaa - just hours after three explosions shook the Yemeni capital, underscoring the transitional government's feeble grip on security. The kidnapping followed that of a German by Yemeni tribesmen, who said on Sunday they had seized him two days earlier to press the authorities to free jailed relatives. Meanwhile, two roadside bombs have exploded near the Defence Ministry and Central Bank - while a mortar bomb landed in a district that houses the French embassy and the home of former president Ali Abdullah Saleh on Sunday night, according to a police source. Gunmen abducted a Westerner identified by a police source as a British oil worker in Sanaa (pictured) on Monday - just hours after three explosions shook the Yemeni capital. Above, the site of one of the explosions . Two roadside bombs exploded near the Defence Ministry and Central Bank on Sunday, said a police source . Meanwhile, a mortar bomb landed in a district that houses the French embassy and the home of former president Ali Abdullah Saleh. It damaged two cars - including the one above - and three buildings . Four people were injured in the mortar blast, which damaged three buildings and destroyed two cars, witnesses said. One resident reported hearing gunfire after the explosions, but details were sketchy. It follows a suicide bomb and gun attack that took place near the Defence Ministry in December last year - killing 52 people. The mortar bomb struck the home district of former president Ali Abdullah Saleh (pictured) Yemen, which neighbours oil giant Saudi Arabia and is home to an ambitious al Qaeda offshoot, has long wrestled with instability, internal conflicts and poor governance. Mass protests in 2011 eventually forced Saleh to end his more than three decades in power, but a political transition process has yet to calm a rebellion by Shi'ite Muslims in the north and a secessionist movement in the south. The Shi'ite Houthi rebels who had carved out a northern fiefdom before Saleh's fall have clashed in recent months with hardline Sunni Muslim Salafis and Hashid tribal rivals. Elsewhere, attacks blamed on al Qaeda-linked militants have grown bolder, raising fears of a total security breakdown in Yemen, a nation mired in corruption that has aggravated poverty. In Monday's kidnapping, four armed men forced the Westerner out of his car and into a waiting vehicle in Sanaa's upscale Hadda district, witnesses said. A police source said a report of the abduction identified the victim as a Briton. The source said the man worked for an oil services company. The British embassy in Sanaa and the Foreign Office in London had no immediate comment. It was not immediately clear if Islamist militants or tribesmen, who often use foreign hostages as bargaining chips to pursue demands against the government, were behind the attack. Efforts to stabilise Yemen hang on the post-Saleh transition and a national reconciliation conference that ended last month. In Monday's kidnapping, four armed men forced the Westerner out of his car and into a waiting vehicle in Sanaa (pictured) A police source said a report of the abduction identified the victim as a British oil worker . In December, a suicide bomb and gun attack near the Defence Ministry killed 52 people. Above, the explosion . Political factions have extended interim President Abd-Rabbu Mansour Hadi's term by another year to give him more time to turn Yemen into a federal state as agreed at the reconciliation talks to try to accommodate southern demands for more autonomy. Hadi will also oversee the drafting of a new constitution that will form the basis of elections slated for next year.

British oil worker believed to have been abducted in Yemeni capital Sanaa .
Reportedly forced out of car and into waiting vehicle by four armed men .
Follows seizure of German by tribesmen hoping to free jailed relatives .
Two bombs exploded near Defence Ministry and Central Bank on Sunday .
And nearby mortar bomb injured four people and destroyed buildings .


(CNN) -- If you view a tablet as a guilty pleasure, like I do, then buying the Kindle Fire should make you feel a little less guilty. Amazon's new device doesn't replace a computer for doing e-mail or composing documents, but it's a fun hub for personal entertainment. And at $199, Amazon has managed to greatly undercut the price of Apple's iPad, the dominant tablet, and still churn out a good product. Apple calls its iPad "a magical and revolutionary product at an unbelievable price." Consider now that for the iPad's $499 price tag, I could buy two Kindle Fire tablets and still have cash left over for downloading apps and movies. However, except for price the Kindle Fire falls short of the iPad in just about every category. The iPad's processor is faster; its software is more abundant, capable and polished; its storage space is larger; its screen is bigger; and its body is more slender. Still, the Kindle Fire is a good Wi-Fi tablet, and the price is fantastic. After testing the device this week, I found the Kindle Fire is the most impressive iPad rival among the dozens of tablets that have flooded the market this year. Other iPad competitors have not sold well, but the new Kindle will likely have a different fate. The Nook Tablet, which also came out this week but which I have not tested at length, costs $50 more and has weaker multimedia offerings. Amazon and Barnes & Noble are squaring off with a new line of inexpensive black-and-white e-readers, too. Yes, those are still around, and bookworms love them. Size, components and features . Many tablets are much faster and have more bells and whistles than the Kindle Fire, which doesn't have cameras, GPS or a microphone. (The latter is especially strange because even the year-old black-and-white Kindle has a microphone.) Unlike other tablets and e-readers, there also is no version of the Kindle Fire with cellular-data connectivity, meaning that would-be Web surfers are limited to areas with Wi-Fi. Forgetting for a moment about the guts inside, the Kindle Fire does not feel cheap. The back is rubbery and doesn't slip out of my hands. It's not ultra thin, but it's girth and weight makes it comfortable to hold for long periods of time, like a paperback book. Because the Kindle is significantly smaller than the iPad -- with a 7-inch-wide screen versus the iPad's 9.7-inch more boxy display -- it weighs about a third less. The built-in speakers sound OK and get about as loud as an alarm clock. There is also a place to plug in headphones. But the Kindle's battery loses a charger much faster than the iPad. I was able to surf the Web and play videos for several hours, but I found myself frequently searching for a charger after that. That Amazon skimped on some of the components becomes evident when swiping through menus, switching the screen's orientation or playing games, which can all be jerky at times. The split-second delays are even present when turning pages on a Kindle e-book, which should be the pride of an Amazon device. The lack of a microphone means no Skype or other Internet telephony programs. Browser and OS . Amazon's Silk Web browser has the features I'd expect and can play most videos found online. Amazon touts the browser's unique speed enhancements, but probably due to the device's lower-end components, it doesn't show. Web pages generally take a few seconds longer to load than on computers or other tablets. Also, I am somewhat uncomfortable with the idea that Silk, as a means of speeding up load times, sends information from every page I visit to Amazon's servers. This Kindle's operating system is based on Google's Android, but Amazon has changed it so extensively that I barely noticed the similarities. A setback to this approach is that Amazon did not include some basic features, like the ability to copy and paste text, or to quickly switch between running applications. But overall, the interface is attractive and neatly laid out. On the home screen, the top bar allows me to search for content on the device or search the Web with Google. Below that is a list of categories like news, books, music and apps. In the main area, I have a bookshelf that includes recently opened items or apps organized in a carousel, plus other shelves full of my favorites. Movies and e-books . Amazon's multimedia offerings are pretty extensive and have been available on other platforms for some time. The company runs the biggest e-bookstore and the second-biggest music download store. Many publishers offer their newspapers and magazines in the Kindle newsstand, but the Kindle Fire's small screen size is not ideal for reading, say, an issue of Bloomberg Businessweek or the New York Times front page. The built-in Amazon shopping app is well designed. Each Kindle Fire comes with a free 30-day subscription to Amazon Prime, whose primary perk (for $79 a year) is free two-day shipping on every item the company sells. The Prime membership also gives new Kindle Fire owners a taste of its Instant Videos service, which has 13,000 movies and TV shows available for streaming on demand. Tens of thousands more are available for purchase. For those who prefer Netflix, that company released a new version this week for the Kindle Fire and other Android tablets. But overall, Amazon's Appstore carries far fewer apps than Apple's online store and even Google's own Android Market. Developers are required to list their Android apps separately with Amazon. (Yes, the Kindle Fire does have "Angry Birds.") A few bugs . The bare-bones e-mail client that comes with the Kindle Fire does not support Microsoft Exchange, which many companies use for their e-mail system. The app encourages users to download another e-mail program from the Appstore, but it doesn't specify which one to get. Holding the tablet upright and typing with my thumbs is fairly efficient, but the system occasionally doesn't register my taps right away if I type fast. I also ran into several bugs throughout the Kindle's software. Sometimes my Fire would crash for no reason, and other times, images would not show up in the gallery. Some third-party developers apparently did not account for Amazon not including volume buttons on the hardware, and so I had to adjust the volume from the settings menu activated by tapping the menu bar. These are issues that I expect will get fixed over time through software updates. The bottom line . The overall software experience is pleasant and integrated from top to bottom. I am never asked to punch in my credit card to buy things, which is convenient. When I first turned on the Kindle Fire, the software recognized who I am because it was already tied to my Amazon account. After a few clicks, I was set up without ever connecting to a computer to synchronize anything. The music I bought through the Amazon MP3 store and the books I've gotten through the Kindle Store were all ready to go. The iPad remains the superior tablet, and it's the closest I've found to replacing a laptop. But I wouldn't discount a less capable competitor. The Kindle Fire is a good entertainment device at a price that's truly unbelievable.

Amazon's Kindle Fire is a multimedia-heavy touchscreen tablet computer .
It's significantly cheaper than the iPad, the undisputed leader in the tablet market .
The Kindle Fire first went on sale this week .
Reviewer: Kindle Fire is a good entertainment device at a price that's truly unbelievable .


(CNN) -- The engineer who was operating the Metro-North train that derailed last year, killing four passengers and injuring dozens more, was suffering from a sleep disorder, according to documents released Monday by the National Transportation Safety Board. The NTSB's investigation discovered during a post-accident sleep evaluation that William Rockefeller Jr. had "severe obstructive sleep apnea." In a Metro-North medical history form from 1999, Rockefeller specifically answered "no" to a question asking whether he had difficulty sleeping, and at no point before the accident did any of his health care providers document a discussion with him regarding sleep problems, according to the NTSB's medical factual report of the investigation. However, after the derailment, a sleep study was ordered for Rockefeller because he "did not exactly recall events leading up to the accident," the report said. The sleep specialist noted that Rockefeller's recent work schedule change from late night to early morning shifts "might have contributed to the accident," according to an additional statement in the specialist's report. Sleep apnea is a disruptive sleep disorder in which a person's breathing repeatedly stops and starts. This can result in an individual feeling tired even after a full night's sleep. As a result, the sleep specialist prescribed Rockefeller continuous positive airway pressure (CPAP) as treatment. Rockefeller reported feeling more energetic after 30 days of treatment. "My client was fully cooperative with the NTSB investigation, including giving them access to his medical records and doctors," Rockefeller's attorney, Jeffrey Chartier, said Monday. "I believe these reports support that there was no criminality in regards to my client." The accident happened on December 1 when the train of seven cars derailed while traveling from Poughkeepsie, New York, to Grand Central Terminal in New York City. The train was hurtling along at 82 mph, far above the speed limit of 30 mph for that section of track as it approached a sharp bend in the Bronx. The cars tumbled off the track, killing four passengers and leaving dozens more hospitalized. The lead car came to rest inches from water at the intersection of the Hudson and Harlem rivers. At the time of the accident, the train was in "push mode," meaning that the locomotive was in the rear of the train pushing it along the tracks, with Rockefeller in a cabin at the front operating it remotely. His cabin was equipped with a "dead man pedal" that required constant downward pressure with the foot to keep the train moving, MTA spokesman Aaron Donovan told CNN last year. "Should you lose consciousness or die, and the foot is taken off, a whistle sounds and the train begins to slow immediately to a stop," Donovan said. "It's a pressure you have to keep -- your foot actively engaged." But it is unclear whether the "dead man pedal" mechanism was activated when Rockefeller allegedly nodded off at the controls. "That is unknown," Donovan said. "MTA Metro-North Railroad is reviewing the documents released today by the NTSB," Donovan said Monday. "The investigation is still ongoing, and Metro-North will continue to work with the NTSB on addressing their recommendations." A safety review from the Federal Railroad Administration said Metro-North's focus on punctuality "had a detrimental effect on safety, adversely affecting the inspection and maintenance of track and negatively impacting train operations," according to the report released in March. CNN's Lawrence Crook III and Haimy Assefa contributed to this report.

Engineer of Metro-North train that derailed was suffering from sleep apnea, NTSB report says .
William Rockefeller Jr. had no record of sleep disorder before December accident, it says .
"There was no criminality in regards to my client," Rockefeller's attorney says .
Four people were killed and dozens were injured in the accident in the Bronx .


Eli -- a sweet, active, blonde-haired preschooler -- had gone to sleep feeling fine, perhaps dreaming of playing with his sisters or having a fun day at school. He didn't make it through the night. While the young boy died sometime between the night of Wednesday, September 24, and the following morning, it wasn't until Friday night that authorities figured out why: enterovirus D68, a particularly pernicious strain of an otherwise common virus that has been particularly widespread this year. While it's been detected in at least four people who died, Eli's case is the first in which authorities have definitively cited enterovirus D68 as the cause of death. Jeff Plunkett, the health officer in Eli's hometown of Hamilton Township, New Jersey, explained Saturday that, while the boy was born premature, "he had no other existing condition" and his parents no reason to believe he was direly ill before the virus took his life. Eli was 4. "He was asymptomatic and fine, and the next morning he had passed," Plunkett told reporters. "So the onset was very rapid, very sudden. And that's clearly the big difference (between enterovirus D68 and other enterovirus strains)." Authorities are testing one other child who attended preschool at Eli's school, Yardville Elementary, albeit in a different class, for enterovirus D68. That boy has been treated at  Robert Wood Johnson University Hospital and is now recovering at home, according to Plunkett. There are no other suspected cases in the town of 90,000 residents. Nor is there any sign of pervasive sickness at Yardville Elementary or other town schools, with attendance levels around normal. This speaks to the deadliness, the randomness and, in a sense, the pervasiveness of enterovirus D68. Hamilton Township Mayor Kelly Yaede pointed out that his parents "nor anyone will ever be able to determine where Eli may have contracted this virus." "The virus is out in the community, there is nothing we can do about that," the health officer said. "The way to prevent it is from your own personal hygiene and be vigilant with your own children and yourself." Officials did not disclose Eli's last name during a Saturday press briefing. More enterovirus cases are likely . Just last week, the U.S. Centers for Disease Control and Prevention or state public health laboratories had confirmed 277 cases of enterovirus D68. That figure has skyrocketed in recent days, to 538 confirmed cases in 43 states and the District of Columbia as of Friday. And there's no reason to think it won't get even worse. As the CDC points out, "Enteroviruses commonly circulate in summer and fall. We're currently in middle of the enterovirus season." Not including Eli's cases, tests showed enterovirus D68 in four people who had died. The CDC, though, reported then that "the role that EV-D68 infection played in these deaths is unclear at this time." Mercer County's medical examiner, Dr. Raafat Ahmad, was unequivocal about it's part in Eli's death. "The child had some brain swelling, it had some lymph node swelling," Plunkett said. "But Ahmad attributed that to the virus as the cause of death." Enterovirus is very common, with the CDC estimating 10 million to 15 million infections each year in the United States. But it has about 100 strains, with D68 among the most dangerous. Authorities say this strain has sent more children than usual to the hospital with severe respiratory illnesses. It seems to be most affecting children with a history of asthma or breathing problems. Enterovirus may also be linked to a small number of cases of a mysterious neurologic illness in Colorado, Boston and Michigan. Doctors in Colorado spotted it first -- a group of 10 children hospitalized with limb weakness, cranial nerve dysfunction and abnormalities in their spinal gray matter . Staff at Boston Children's Hospital have since identified four patients with the same symptoms. And a child in Washtenaw County, Michigan, has also developed partial paralysis in the lower limbs after being hospitalized with the virus, according to the Michigan Department of Community Health. As Plunkett, the Hamilton Township health officer, explained: "The D68 strain is a very virulent strain of entire that would attack young children, preschoolers, toddlers who have for the most part compromised immune systems. It has a certain target in our population." Hygiene education, cleaning ramped up in schools . It's not clear, though, whether Eli should have been any more susceptible than anyone else, beyond his age. That and the suddenness of his death makes it especially difficult to fathom or fully understand. People in Hamilton Township, at least, are doing something about it. While officials say they're being careful not to overly alarm students, they are stressing things like hand washing, sneezing into your sleeves, staying home if you're sick and the like to students, teachers and parents to try to prevent the spread of enterovirus D68 and other viruses. Superintendent Jim Parla also said "we have ramped up cleaning in all of our schools," devoting extra staff and hours to "do cleaning that goes above and beyond what we normally do." Then there's the matter of taking care of Eli's family, namely his parents -- both educators -- and two young sisters. Yardville Elementary Principal Elena Manning said that blue-and-yellow bows, her school's colors, are being put up around the community in Eli's honor. The late boy's preschool teacher and an assistant bought a girlish bedroom set and rug to decorate his sisters' room at home. And the school will soon have a "Proud of Me" wall to display students' work, because Eli would regularly "ask Daddy if Daddy was proud of him," according to Manning. Eli's parents are working with school officials on other things. But their focus now is more on grieving, taking care of their daughters and sending a message to the community. According to Principal Manning, "They are most concerned about giving thanks, which is incredible."

Official: A preschooler went to bed "asymptomatic," was dead the next morning .
A medical examiner now says the boy died suddenly from enterovirus D68 .
There's no way of telling how the boy contracted the virus, official says .
CDC confirms 538 people in 43 states have respiratory illnesses caused by enterovirus D68 .


By . Daniel Miller . PUBLISHED: . 12:41 EST, 13 August 2013 . | . UPDATED: . 13:55 EST, 13 August 2013 . Collapse: Lieutenant Colonel Michael McErlain, 45, died . during a D-Day run on the clifftops of the Normandy beaches in France . An army surgeon, who treated injured children in Afghanistan, died while competing in a charity D-Day run along the Normandy beaches in France. Lieutenant Colonel Michael McErlain, 45, was one of around 30 runners and was bringing up the rear when he collapsed around two miles into the 44-mile race. Another competitor, an American fireman, tried desperately to revive him but he died at the scene on the morning of June 6. The father-of-three, who worked as a spinal surgeon at Frimley Park Hospital, Surrey, had co-founded the event with wife Joanna and brother-in-law Giles Barnes and had competed in it six times before. Mr Barnes, who was also competing, heard about the collapse and ran four miles to the scene but arrived to find Lt Col McErlain grey and cold. He had died about 20 minutes previously. The event, held in aid of the British Limbless ex-Services Men's Association, aims to raise awareness of the sacrifices made by allied soldiers in World War Two. A post-mortem examination revealed Lt Col McErlain, from Hindhead, Surrey, died from ischemic heart disease. At an inquest into the death held in Alton, Hampshire, Mr Barnes described his brother-in-law as an extremely talented man who was very 'humble' about his achievements in life. Recalling the day he died he said: 'It was about 16 degrees outside. A lovely temperature to be doing it. It was perfect conditions. 'I was going to be doing the support part of the run. Every seven miles giving them painkillers, something to eat and drink and be on their way. 'Mike was used to doing the run. He was the slowest person on the run, but made a point of being the slowest so he could literally bring up the rear. 'I would imagine he was not even running. More of a shuffle. Certainly the runner who was with him was more interested in sightseeing and taking photographs. Lt Col McErlain, who worked as a spinal surgeon at Frimley Park Hospital, Surrey, had co-founded the event with wife Joanna and brother-in-law Giles Barnes and had competed in it six times before . 'He was American and with Mike when he collapsed. They were stop starting. They had been having a conversation about the beautiful weather. 'Some of Mike's last words were that he said it was such a historically wonderful thing to do and the setting of the run itself would be enough to get people to do it. 'It was such a beautiful run. To have that conversation suggests it he wasn't really going for it. 'He did not complain about having to stop and was chatting away and suddenly he collapsed.' The fireman, known as Brian from Colorado, said Michael was gasping for breath and lost consciousness. Despite his best efforts to perform CPR he died in his arms during the race aimed at raising awareness of the sacrifices made by allied soldiers. Recording a verdict of natural death, Hampshire Coroner Andrew Bradley said: 'I would expect this disease in the heart of a 65-year-old, not someone who is 45. 'If your heart is going downhill and you use it more the worse it is going to get. 'This is a degeneration and progressive change. 'He had constant medical check ups with the Army, which showed he was fine. 'It is clearly an ongoing condition. It was not a heart attack this was a degeneration rather than a single event. 'It is sad and very unexpected.'

Lt Col Michael McErlain, 45, collapsed around 2 miles into the 44-mile race .
He had co-founded the event and had competed in it six times before .
Father-of-three worked as a spinal surgeon at Frimley Park Hospital, Surrey .
Post-mortem revealed he had died from ischemic heart disease .


(CNN) -- The eldest daughter of Walt Disney, Diane Disney Miller, has died at 79, a statement from the museum dedicated to the legendary animated filmmaker said Tuesday. "She went through life with a determination to inspire and entertain. She was her father's daughter, a creative force with the perseverance to follow dreams and make a difference," the news release said. Miller died in Napa, California, the result of injuries sustained in a fall. The statement didn't say what day she died and said funeral services will be private. Miller married Ron Miller in 1954, a year after they met at the University of Southern California. Ron Miller went to work for Walt Disney Studios and later was the CEO of the Walt Disney Company until 1984. Current Disney CEO Robert Iger said: "(Diane) holds a special place in the history of The Walt Disney Company and in the hearts of fans everywhere. She will be remembered for her grace and generosity and tireless work to preserve her father's legacy, and she will be greatly missed by all who knew her." Miller was one of the co-founders of the Walt Disney Family Museum in San Francisco. At the time of her death, she was the president of the board of directors of the Walt Disney Family Foundation, which owns the 4-year-old museum. She and her husband also operated Silverado Vineyards in Napa. She is survived by her husband, seven children, 13 grandchildren and one great-granddaughter. Her adopted sister, Sharon Mae Disney, died in 1993. People we've lost in 2013 .

Diane Disney Miller was Walt Disney's eldest daughter .
She helped start a museum to remember her father .
Her husband was once the CEO of the Walt Disney Company .


(CNN) -- Travis Mills has no arms or legs. He is an American hero who served three tours in Afghanistan and lost all his limbs when a bomb exploded under him. "How I survived, I have no idea," he said. "I was yelling at the medic, 'Get away from me,' because I thought I was done." The retired United States Army staff sergeant spent months recuperating at Walter Reed National Military Medical Center, but don't dare call him a wounded warrior. "I'm not wounded any more," he said. "I'm just a guy living life." Recalling comrades killed in combat, he asks: "How selfish would it be if I gave up?" He snowboards, bikes and recently jumped out of an airplane with the U.S. Army Golden Knights parachute team. And now, he has a new admirer in Mike Rowe, the star of "Dirty Jobs" and the upcoming CNN series "Somebody's Gotta Do It." He met Mills a few weeks ago at a conference in Washington and wrote a Facebook post about their exchange to honor him this Memorial Day. As of Monday night, the post had more than 90,000 shares on Facebook. "He has a motto: Never give up - never quit. He has a Foundation. He's featured in a new documentary. He also has a wife and a kid, and a deeply personal commitment to help other wounded vets cope with their injuries." Rowe wrote. "But when I asked why I hadn't seen him in any of the typical commercials and PSA's for wounded veterans, his answer was stunning. He said he didn't consider himself to be wounded. 'I'm not a victim, Mike. And I refuse to be portrayed that way. Case closed.'" Rowe ended his candid post by reflecting on the holiday meant to honor America's military fallen. "That's called a gut-check, and I could use one from time to time. Especially on Memorial Day, when the biggest decisions I face are what to grill and which type of frosty beverage to enjoy. This year, as I resolve these and other important issues, I'll think of Travis Mills." The toll of war now includes more amputees . CNN's Barbara Starr contributed to this report.

Mike Rowe meets Mills at conference in Washington .
Mills' motto is "Never give up - never quit"
Rowe posts on Facebook about Mills to mark Memorial Day .