# Optimize.py
# Created:  Feb 2016, M. Vegh
# Modified: Aug 2017, E. Botero
#           Aug 2018, T. MacDonald

# ----------------------------------------------------------------------
#   Imports
# ----------------------------------------------------------------------

import SUAVE
from SUAVE.Core import Units, Data
import numpy as np
import Vehicles
import Analyses
import Missions
import Procedure
import Plot_Mission
import matplotlib.pyplot as plt
from SUAVE.Optimization import Nexus, carpet_plot
import SUAVE.Optimization.Package_Setups.scipy_setup as scipy_setup
import SUAVE.Optimization.Package_Setups.pyopt_setup as pyopt_setup

# ----------------------------------------------------------------------
#   Run the whole thing
# ----------------------------------------------------------------------
def main():

    problem = setup()
    output  = scipy_setup.SciPy_Solve(problem,sense_step=0.0005)

    ## Uncomment these lines when you want to start an optimization problem from a different initial guess
    #inputs                                   = [1.28, 1.38]
    #scaling                                  = problem.optimization_problem.inputs[:,3] #have to rescale inputs to start problem from here
    #scaled_inputs                            = np.multiply(inputs,scaling)
    #problem.optimization_problem.inputs[:,1] = scaled_inputs
    #output = scipy_setup.SciPy_Solve(problem,solver='SLSQP')

    problem.translate(output)

    Plot_Mission.plot_mission(problem)

    return

# ----------------------------------------------------------------------
#   Inputs, Objective, & Constraints
# ----------------------------------------------------------------------

def setup():

    nexus = Nexus()
    problem = Data()
    nexus.optimization_problem = problem

    # -------------------------------------------------------------------
    # Inputs
    # -------------------------------------------------------------------

    #   [ tag                            , initial, (lb,ub)             , scaling , units ]
    problem.inputs = np.array([
        #[ 'wing_span'      ,  9.4   , (   8.0 ,   15.   ) ,   9.4 , Units.meter],
        #[ 'wing_root_chord'  ,  2.0    , (   1.  ,    4.   ) ,   2.0  , Units.meter],
        #[ 'wing_thickness_to_chord'  ,  0.15    , (   0.1  ,    0.5   ) ,   0.15  , Units.less],
        #[ 'wing_taper_ratio'  ,  0.9    , (   0.55  ,    1.0   ) ,   0.9  , Units.less],
        [ 'cruise_distance'        ,  150.    , (   50.  ,    500.   ) ,   150.  , Units.nautical_miles],
        [ 'cruise_airspeed'        ,  200.   , (   90.  ,    280.   ) ,   200.  , Units['m/s']],
        [ 'climb1_airspeed'        , 125.0   , (   50.0  ,  230.0      ) ,  125.0   , Units['m/s']],
        [ 'climb2_airspeed'        ,  190.0   , ( 70.0    ,  250.0     ) ,   190.0  , Units['m/s']],
        [ 'descent1_airspeed'      ,  180.0  , ( 100.    ,  250.     ) ,  180.0   , Units['m/s']],
        [ 'descent2_airspeed'      ,   145.0   , ( 50.    ,  180.0     ) ,  145.0   , Units['m/s']],
        [ 'climb1_altitude'        ,   3.  , (  1.   ,  5.     ) ,  3.   , Units.km],
        [ 'climb2_altitude'        ,   8.0   , (   7.  ,  15.     ) , 8.0    , Units.km],
        [ 'descent1_altitude'      ,  3.0    , (  2.   ,  7.     ) ,   3.0  , Units.km],
        [ 'climb1_rate'        ,    6.0  , (   3.  ,  13.     ) ,  6.0   , Units['m/s']],
        [ 'climb2_rate'        ,    3.0  , (  2.   ,   9.    ) ,   3.0  , Units['m/s']],
        [ 'descent1_rate'      ,   4.5   , (  3.   ,   10.    ) ,  4.5   , Units['m/s']],
        [ 'descent2_rate'      ,    3.0  , (  2.   ,   8.    ) ,  3.0   , Units['m/s']],
        #[ 'voltage'      ,   470.   , (  100.   ,   10000.    ) ,  470.   , Units['volt']],
        #[ 'motor_kv_cruise'      ,   181.   , (  10.   ,   500.    ) ,  181.   , Units['rpm/volt']],
        #[ 'motor_kv_HL'      ,   91.   , (  5.   ,   300.    ) ,  91.   , Units['rpm/volt']],
        #[ 'bat_spec_energy'      ,   6.1  , (  3.   ,   10000.    ) ,  6.1  , Units.Wh/Units.kg],
        #[ 'bat_spec_power'      ,   0.833   , (  0.5   ,   1000.    ) ,  0.833   , Units.kW/Units.kg],
        #[ 'bat_max_voltage'      ,   60.1   , (  0.5   ,   100000.    ) ,  60.1   , Units['volt']],
        #[ 'bat_resistance'      ,   0.0151   , (  0.0001   ,   100.    ) ,  0.0151   , Units['ohm']],
        #[ 'payload_draw'      ,   50.1   , (  5.   ,   50000.    ) ,  50.1   , Units.watts],
        #[ 'avionics_draw'      ,   50.1   , (  5.   ,   50000.    ) ,  50.1   , Units.watts],
    ])

    # -------------------------------------------------------------------
    # Objective
    # -------------------------------------------------------------------

    # throw an error if the user isn't specific about wildcards
    # [ tag, scaling, units ]
    problem.objective = np.array([
        [ 'range', -540.9079921321364, Units.nautical_miles ],
        #[ 'battery_energy_max', 8476560.0, Units.Wh ],
    ])

    # -------------------------------------------------------------------
    # Constraints
    # -------------------------------------------------------------------

    # [ tag, sense, edge, scaling, units ]
    problem.constraints = np.array([
        #[ 'energy_constraint', '=', 0.0, 1.0, Units.less],
        [ 'battery_energy_min'     , '>', -0.01, 10000000.0, Units.Wh  ],
        #[ 'battery_draw'     , '>', -0.1, 1.0, Units.kW  ],
        #[ 'CL'               , '>', 0.0, 1.0, Units.less],
        #[ 'Throttle_cruise'     , '>', -0.01, 1.0, Units.less],
        #[ 'Throttle_HL'     , '>', -0.01, 1.0, Units.less],
        #[ 'Throttle_cruise'     , '<', 1.5, 1.0, Units.less],
        #[ 'Throttle_HL'     , '<', 1.5, 1.0, Units.less],
        [ 'HL_rpm_min'           , '>', -0.01, 100000.0, Units['rpm']],
        [ 'HL_rpm_max'           , '<', 50000, 1.0, Units['rpm']],
        [ 'cruise_rpm_min'       , '>', -0.01, 100000.0, Units['rpm']],
        [ 'cruise_rpm_max'       , '<', 80000, 1.0, Units['rpm']],
        #[ 'lift_coefficient_min'       , '>', -0.1, 1.0, Units.less],
        [ 'mach_number_max'       , '<', 1.5, 1.0, Units.less],
        [ 'AoA_min'       , '>', -0.1, 1.0, Units.deg],
        #[ 'AoA_max'       , '<', 40.0, 1.0, Units.deg]
    ])

    # -------------------------------------------------------------------
    #  Aliases
    # -------------------------------------------------------------------

    # [ 'alias' , ['data.path1.name','data.path2.name'] ]

    problem.aliases = [
        #[ 'wing_span'          ,    'vehicle_configurations.*.wings.main_wing.spans.projected'],
        #[ 'wing_root_chord'                  ,     'vehicle_configurations.*.wings.main_wing.chords.root'         ],
        #[ 'wing_thickness_to_chord'          ,     'vehicle_configurations.*.wings.main_wing.thickness_to_chord'         ],
        #[ 'wing_taper_ratio'          ,     'vehicle_configurations.*.wings.main_wing.taper'         ],
        [ 'cruise_distance'            ,   'missions.mission.segments.cruise.distance'              ],
        [ 'cruise_airspeed'            ,   'missions.mission.segments.cruise.air_speed'              ],
        [ 'climb1_airspeed'            ,   'missions.mission.segments.climb_1.air_speed'             ],
        [ 'climb2_airspeed'            ,   'missions.mission.segments.climb_2.air_speed'              ],
        [ 'descent1_airspeed'            ,  'missions.mission.segments.descent_1.air_speed'               ],
        [ 'descent2_airspeed'            ,  'missions.mission.segments.descent_2.air_speed'               ],
        [ 'climb1_altitude'            ,   'missions.mission.segments.climb_1.altitude_end'              ],
        [ 'climb2_altitude'            ,   'missions.mission.segments.climb_2.altitude_end'              ],
        [ 'descent1_altitude'            , 'missions.mission.segments.descent_1.altitude_end'                ],
        [ 'climb1_rate'            ,   'missions.mission.segments.climb_1.climb_rate'              ],
        [ 'climb2_rate'            ,   'missions.mission.segments.climb_2.climb_rate'              ],
        [ 'descent1_rate'            ,  'missions.mission.segments.descent_1.descent_rate'               ],
        [ 'descent2_rate'            ,  'missions.mission.segments.descent_2.descent_rate'               ],
        #[ 'voltage'            ,  'vehicle_configurations.*.propulsors.propulsor.voltage'               ],
        #[ 'motor_kv_cruise'            ,  'vehicle_configurations.*.propulsors.propulsor.motor_forward.speed_constant'               ],
        #[ 'motor_kv_HL'            ,  'vehicle_configurations.*.propulsors.propulsor.motor_lift.speed_constant'               ],
        #[ 'bat_spec_energy'            ,  'vehicle_configurations.*.propulsors.propulsor.battery.specific_energy'               ],
        #[ 'bat_spec_power'            ,  'vehicle_configurations.*.propulsors.propulsor.battery.specific_power'               ],
        #[ 'bat_max_voltage'            ,  'vehicle_configurations.*.propulsors.propulsor.battery.max_voltage'               ],
        #[ 'bat_resistance'            ,  'vehicle_configurations.*.propulsors.propulsor.battery.resistance'               ],
        #[ 'payload_draw'            ,  'vehicle_configurations.*.propulsors.propulsor.payload.power_draw'               ],
        #[ 'avionics_draw'            ,  'vehicle_configurations.*.propulsors.propulsor.avionics.power_draw'               ],
        [ 'range'            ,    'summary.total_range'            ],
        #[ 'max_lift'            ,    'summary.max_lift_coefficient_all_segments'            ],
        #[ 'battery_energy_max'            ,    'summary.max_battery_energy_all_segments'            ],
        [ 'battery_energy_min'            , 'summary.min_battery_energy_all_segments'                ],
        #[ 'battery_draw'            , 'summary.battery_charging_power_all_segments'                ],
        #[ 'Throttle_cruise_min'            ,   'summary.min_throttle_all_segments'              ],
        [ 'Throttle_cruise'            ,   'summary.throttle_all_segments'              ],
        #[ 'Throttle_HL_min'            ,   'summary.min_lift_throttle_all_segments'              ],
        [ 'Throttle_HL'            ,   'summary.lift_throttle_all_segments'              ],
        [ 'HL_rpm_min'            ,  'summary.min_rpm_lift_all_segments'           ],
        [ 'HL_rpm_max'            ,  'summary.max_rpm_lift_all_segments'           ],
        [ 'cruise_rpm_min'            ,  'summary.min_rpm_forward_all_segments'             ],
        [ 'cruise_rpm_max'            ,  'summary.max_rpm_forward_all_segments'             ],
        [ 'lift_coefficient_min'            ,  'summary.min_lift_coefficient_all_segments'             ],
        [ 'AoA_min'       , 'summary.min_aoa_all_segments'        ],
        [ 'AoA_max'       , 'summary.max_aoa_all_segments'  ],
        [ 'mach_number_max'            ,  'summary.max_mach_number_all_segments'             ],
    ]

    # -------------------------------------------------------------------
    #  Vehicles
    # -------------------------------------------------------------------
    nexus.vehicle_configurations = Vehicles.setup()

    # -------------------------------------------------------------------
    #  Analyses
    # -------------------------------------------------------------------
    nexus.analyses = Analyses.setup(nexus.vehicle_configurations)

    # -------------------------------------------------------------------
    #  Missions
    # -------------------------------------------------------------------
    nexus.missions = Missions.setup(nexus.analyses,nexus.vehicle_configurations)

    # -------------------------------------------------------------------
    #  Procedure
    # -------------------------------------------------------------------
    nexus.procedure = Procedure.setup()

    # -------------------------------------------------------------------
    #  Summary
    # -------------------------------------------------------------------
    #nexus.summary = Data()

    nexus.total_number_of_iterations = 0

    return nexus

if __name__ == '__main__':
    main()


from __future__ import absolute_import

import responses

from exam import fixture
from sentry.models import Rule
from sentry.plugins import Notification
from sentry.testutils import TestCase
from sentry.utils import json
from urlparse import parse_qs

from sentry_zulip.plugin import ZulipPlugin

class ZulipPluginTest(TestCase):
    @fixture
    def plugin(self):
        return ZulipPlugin()

    @responses.activate
    def test_simple_notification(self):
        responses.add('POST', 'http://example.com/zulip')
        self.plugin.set_option('apiurl', 'http://example.com/zulip', self.project)
        self.plugin.set_option('username', 'bot@example.com', self.project)
        self.plugin.set_option('apikey', 'testkey', self.project)
        self.plugin.set_option('stream', 'Sentry', self.project)

        group = self.create_group(message='Hello world', culprit='foo.bar')
        event = self.create_event(group=group, message='Hello world')

        rule = Rule.objects.create(project=self.project, label='my rule')

        notification = Notification(event=event, rule=rule)

        with self.options({'system.url-prefix': 'http://example.com'}):
            self.plugin.notify(notification)

        req = responses.calls[0].request
        assert req.url == 'http://example.com/zulip'
        data = parse_qs(req.body)
        assert data['content'][0] == '[ERROR] **foo Bar** Hello world [view](http://example.com/baz/bar/issues/1/)'
        assert data['to'][0] == 'Sentry'
        assert data['subject'][0] == 'Hello world'
        assert data['type'][0] == 'stream'


#"a"のasciiコード
base = ord("a")

#αの候補, (1 <= α <= 25)
alst = [i for i in range(1, 26, 2) if i % 13]

#α, βの全候補を試す(1 <= α <=25,  0 <= β <= 25)
def restore(s):
  for a in alst:
    for b in range(26):
      new = "".join([chr((a * (ord(x) - base) + b) % 26 + base) if x != " " else " " for x in s])
      if "that" in new or "this" in new:
        return new

n = int(input())

for _ in range(n):
  print(restore(input()))


'''
measure time comlexity
BFS model self-defined ll function,
speeded version, prepared for BADS in MATLAB,
python3 or py27
'''
import random, copy, pickle, os, sys, time
from operator import attrgetter
import multiprocessing as mp
import numpy as np
from numpy import recfromcsv
import pandas as pd
from datetime import datetime
from scipy.optimize import minimize
from scipy.optimize import differential_evolution
import scipy.stats as stats
from sklearn.model_selection import KFold
from Car import *
from Board import *
from Node import *

######################################## BFS MODEL ##############

class Params:
	def __init__(self, w1, w2, w3, w4, w5, w6, w7,
					stopping_probability,
					pruning_threshold,
					lapse_rate,
					feature_dropping_rate=0.0,
					mu=0.0, sigma=1.0):
		self.w0 = 0.0
		self.w1 = w1
		self.w2 = w2
		self.w3 = w3
		self.w4 = w4
		self.w5 = w5
		self.w6 = w6
		self.w7 = w7
		self.weights = [self.w0, self.w1, self.w2, self.w3, self.w4, self.w5, self.w6, self.w7]
		self.num_weights = len(self.weights)
		self.mu = mu
		self.sigma = sigma
		self.feature_dropping_rate = feature_dropping_rate
		self.stopping_probability = stopping_probability
		self.pruning_threshold = pruning_threshold
		self.lapse_rate = lapse_rate

def DropFeatures(probability):
	pass

def Lapse(probability):
	''' return true with a probability '''
	return random.random() < probability

def Stop(probability):
	''' return true with a probability '''
	return random.random() < probability

def RandomMove(node, params):
	''' make a random move and return the resulted node '''
	assert not is_solved(node.board, node.red), "RandomMove input node is already solved."
	InitializeChildren(node, params)
	return random.choice(node.children)

def InitializeChildren(node, params):
	'''
		initialize the list of children nodes
		(using all legal moves)
	'''
	InitializeChildren_start = time.time()

	# find all legal moves
	all_moves = all_legal_moves(node.car_list, node.board)
	# print('len(all_legal_moves)='+str(len(all_moves)))
	time_dict['all_legal_moves'].append(time.time() - InitializeChildren_start)

	for (tag, pos) in all_moves:

		move_xy_start = time.time()
		# move board position to simulate possible move
		new_list, _ = move_xy(node.car_list, tag, pos[0], pos[1])
		time_dict['move_xy'].append(time.time() - move_xy_start)

		childNode_start = time.time()
		# create child node
		child = Node(new_list, params)
		child.parent = node
		node.children.append(child)
		time_dict['create_Node'].append(time.time() - childNode_start)
		time_dict['Node_board_time'].append(child.board_time)
		time_dict['Node_find_red_time'].append(child.find_red_time)
		time_dict['Node_construct_mag_time'].append(child.construct_mag_time)
		time_dict['Node_assign_level_time'].append(child.assign_level_time)
		time_dict['Node_value_time'].append(child.value_time)

	time_dict['InitializeChildren'].append(time.time() - InitializeChildren_start)

def SelectNode(root_node):
	''' return the child with max value '''
	n = root_node
	while len(n.children) != 0:
		n = ArgmaxChild(n)
	return n, is_solved(n.board, n.red)

def ExpandNode(node, params):
	'''
	create all possible nodes under input node,
	cut the ones below threshold
	'''
	InitializeChildren(node, params)
	Vmaxchild = ArgmaxChild(node)
	for child_idx in range(len(node.children))[::-1]: # iterate in reverse order
		if abs(node.children[child_idx].value - Vmaxchild.value) > params.pruning_threshold:
			node.remove_child(child_idx)

def Backpropagate(this_node, root_node):
	''' update value back until root node '''
	this_node.value = ArgmaxChild(this_node).value
	if this_node != root_node:
		Backpropagate(this_node.parent, root_node)

def ArgmaxChild(node):
	'''
		return the child with max value
	'''
	ArgmaxChild_start = time.time()
	result = max(node.children, key=attrgetter('value'))
	time_dict['ArgmaxChild'].append(time.time() - ArgmaxChild_start)
	return result

def MakeMove(root, params, hit=False, verbose=False):
	'''
	`	returns an optimal move to make next
		according to value function and current board position
	'''
	MakeMove_start = time.time()
	beforewhile_start = time.time()
	# print('[[[[[[[[[[ MakeMove start')
	if hit: # for ibs, if matches human decision, return root node
		time_dict['MakeMove'].append(time.time()- MakeMove_start)
		return root
	assert len(root.children) == 0
	# check if root node is already a winning position
	if is_solved(root.board, root.red):
		# move red car to position 16 if rootis a winning position
		new_carlist, _ = move(root.car_list, 'r', 16)
		result = Node(new_carlist, params)
		return result
	if Lapse(params.lapse_rate): # random move
		RandomMove_start = time.time()
		result = RandomMove(root, params)
		time_dict['beforewhile'].append(time.time() - beforewhile_start)
		time_dict['MakeMove'].append(time.time()- MakeMove_start)
		return result
	else:
		DropFeatures(params.feature_dropping_rate)
		Stop_start = time.time()
		should_stop = Stop(probability=params.stopping_probability)
		time_dict['Stop'].append(time.time() - Stop_start)
		time_dict['beforewhile'].append(time.time() - beforewhile_start)
		while_start = time.time()
		while not should_stop:
			SelectNode_start = time.time()
			leaf, leaf_is_solution = SelectNode(root)
			time_dict['SelectNode'].append(time.time()- SelectNode_start)
			if leaf_is_solution:
				Backpropagate_start = time.time()
				Backpropagate(leaf.parent, root)
				time_dict['Backpropagate'].append(time.time() - Backpropagate_start)
				Stop_start = time.time()
				should_stop = Stop(probability=params.stopping_probability)
				time_dict['Stop'].append(time.time() - Stop_start)
				continue
			ExpandNode_start = time.time()
			ExpandNode(leaf, params)
			time_dict['ExpandNode'].append(time.time() - ExpandNode_start)
			Backpropagate_start = time.time()
			Backpropagate(leaf, root)
			time_dict['Backpropagate'].append(time.time() - Backpropagate_start)
			Stop_start = time.time()
			should_stop = Stop(probability=params.stopping_probability)
			time_dict['Stop'].append(time.time() - Stop_start)
		time_dict['insidewhile'].append(time.time() - while_start)
		afterwhile_start = time.time()
	if root.children == []: # if did not enter while loop at all
		ExpandNode_start = time.time()
		ExpandNode(root, params)
		time_dict['ExpandNode'].append(time.time() - ExpandNode_start)
	result = ArgmaxChild(root)
	time_dict['afterwhile'].append(time.time() - afterwhile_start)
	time_dict['MakeMove'].append(time.time()- MakeMove_start)
	# print('end MakeMove ]]]]]]]')
	return result

if __name__ == '__main__':
	# data path definitions
	all_datapath = '/Users/chloe/Desktop/trialdata_valid_true_dist7_processed.csv'
	outputpath = '/Users/chloe/Desktop/timedict.csv'
	instancepath='/Users/chloe/Documents/RushHour/exp_data/data_adopted/'
	subject_path = '/Users/chloe/Desktop/subjects/' + random.choice(os.listdir('/Users/chloe/Desktop/subjects/'))
	df = pd.read_csv(subject_path)
	print('subject '+str(subject_path)+'\nsample size: '+str(df.shape[0]))

	# initialize parameters
	inparams = [0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1,
				0.01, 10, 0.01]
	all_time_dict = {'MakeMove':[],
					'insidewhile':[], 'beforewhile':[], 'afterwhile':[],
					'Stop':[], 'SelectNode':[], 'Backpropagate':[], 'ArgmaxChild':[],
					'ExpandNode':[],
						'InitializeChildren':[],
							'all_legal_moves':[], 'move_xy':[],
							'create_Node': [],
								'Node_board_time':[], 'Node_find_red_time':[], 'Node_construct_mag_time':[], 'Node_assign_level_time':[], 'Node_value_time':[],
					}

	params = Params(w1=inparams[0], w2=inparams[1], w3=inparams[2],
					w4=inparams[3], w5=inparams[4], w6=inparams[5],
					w7=inparams[6],
					stopping_probability=inparams[7],
					pruning_threshold=inparams[8],
					lapse_rate=inparams[9])

	# iterate over each move
	for idx, row in df.iterrows():
		print(idx, subject_path)
		# initialize record for current move
		time_dict = {}
		for key in all_time_dict.keys():
			time_dict[key] = []
		# read current move data
		if row['event'] == 'start':
			# load new instance data
			instance = row['instance']
			ins_file = instancepath+instance+'.json'
			cur_carlist = json_to_car_list(ins_file)
			continue
		if row['piece']=='r' and row['move']==16 and row['optlen']==1: # win
			# skip the winning moves
			continue

		# call makemove and record time data
		MakeMove(Node(cur_carlist, params), params)

		# change the board and perform the current move
		piece = str(row['piece'])
		move_to = int(row['move'])
		cur_carlist, _ = move(cur_carlist, piece, move_to)

		# summarize all records from current move
		for key in all_time_dict.keys():
			all_time_dict[key].append(sum(time_dict[key]))

	# all moves completed, convert to dataframe
	all_time_df = pd.DataFrame.from_dict(all_time_dict)
	# save files as csv and calculate summary statistics
	all_time_df.to_csv(outputpath, index = False, header=True)
	# calculate proportion wrt MakeMove, except MakeMove itself
	df = pd.read_csv(outputpath)
	for col in df.columns[1:]:
		df[col] = df[col]/df['MakeMove']
	print('\n\nwrt MakeMove')
	print(df.mean())
	# calculate proportion again wrt create_Node
	df = pd.read_csv(outputpath)
	for col in df.columns[-5:]:
		df[col] = df[col]/df['create_Node']
	print('\n\nwrt create_Node')
	print(df.mean()[-6:])


class UnboundedIndex(object):

    """
    A generic loop iteration index that can be used in a :class:`Iteration` to
    add a non-linear traversal of the iteration space.
    """

    def __init__(self, index, start=0, step=None):
        self.index = index
        self.start = start
        self.step = index + 1 if step is None else step


import unittest
import json
from apay import app, db
from apay.models import Bank
from tests import fixtures, utils
from flask import jsonify

class BankTestCase(unittest.TestCase):
    def setUp(self):
        app.config.from_object('apay.config.test')
        db.session.close()
        db.drop_all()
        db.create_all()

        self.app = app.test_client()

    def test_create_bank_success(self):
        data = fixtures.bank

        with app.test_request_context():
            rv = self.app.post('/banks', data=json.dumps(data), content_type='application/json')
            self.assertEqual(200, rv.status_code)
            self.assertEqual(1, Bank.query.count())

    def test_create_bank_fail(self):
        with app.test_request_context():
            rv = self.app.post('/banks', data=json.dumps({'name': None, 'active': 'on'}), content_type='application/json')
            self.assertEqual(400, rv.status_code)
            self.assertEqual(0, Bank.query.count())

    def test_read_bank_success(self):
        utils.create_bank()

        with app.test_request_context():
            rv = self.app.get('/bank/1')
            self.assertEqual(jsonify(Bank.query.first().serialize()).data, rv.data)

    def test_read_bank_fail(self):
        with app.test_request_context():
            rv = self.app.get('/bank/1')
            self.assertEqual(404, rv.status_code)

    def test_update_bank_success(self):
        utils.create_bank()

        with app.test_request_context():
            rv = self.app.put('/bank/1', data=json.dumps({'name': 'another bank'}), content_type='application/json')
            self.assertEqual(200, rv.status_code)
            self.assertEqual('another bank', Bank.query.first().name)

    def test_update_bank_fail(self):
        with app.test_request_context():
            rv = self.app.put('/bank/1', data=json.dumps({'name': 'pewpew'}), content_type='application/json')
            self.assertEqual(404, rv.status_code)

            utils.create_bank()

            rv_2 = self.app.put('/bank/1', data={'name': 'bank 2'}, content_type='application/json')
            self.assertEqual(400, rv_2.status_code)

            rv_3 = self.app.put('/bank/1', data=json.dumps({'name': None}), content_type='application/json')
            self.assertEqual(400, rv_3.status_code)

    def test_delete_bank_success(self):
        utils.create_bank()

        with app.test_request_context():
            rv = self.app.delete('/bank/1')
            self.assertEqual(200, rv.status_code)
            self.assertEqual(0, Bank.query.count())


from setuptools import setup, find_packages

template_patterns = [
    'templates/*.html',
    'templates/*/*.html',
]

packages = find_packages('.')

setup(
    name='django-podcast',
    version='0.5.0',
    description='Django podcast app',
    packages=packages,
    package_data=dict((package_name, template_patterns) for package_name in packages),
    url='https://github.com/jefftriplett/django-podcast',
    classifiers=[
        'Development Status :: 4 - Beta',
        'Environment :: Web Environment',
        'Intended Audience :: Developers',
        'License :: OSI Approved :: BSD License',
        'Operating System :: OS Independent',
        'Programming Language :: Python',
        'Framework :: Django',
    ],
)


from simulation_1 import main
import random
import matplotlib
matplotlib.use('Agg')
from matplotlib import pyplot as plt
import numpy as np
import matplotlib.mlab as mlab
import matplotlib.gridspec as gridspec
import matplotlib.transforms as mtransforms

############ Helper functions ################

def getHigherMean(list1, list2):
    avg1 = float(sum(list1))/len(list1)
    avg2 = float(sum(list2))/len(list2)

    if avg1 > avg2:
        return list1
    else:
        return list2

def getLowerMean(list1, list2):
    avg1 = float(sum(list1))/len(list1)
    avg2 = float(sum(list2))/len(list2)

    if avg1 <= avg2:
        return list1
    else:
        return list2

def calculateFee(list1, list2):
    lower = getLowerMean(list1, list2)
    higher = getHigherMean(list1, list2)

    ans = []
    for i in range(len(lower)):
        ans.append(higher[i] -lower[i])
    return ans

def chargeFee(bob, fee):
    ans = []
    for i in range(len(fee)):
        ans.append(bob[i] - fee[i])
    return ans

def payFee(alice, fee):
    ans = []
    for i in range(len(fee)):
        ans.append(alice[i] + fee[i])
    return ans

def getIntersections(list1, list2, ps):
    points = []

    for i in range(1, len(list1)):
        if list1[i] == list2[i]:
            points.append((i, list2[i]))
        elif ((list1[i-1] > list2[i-1]) and (list1[i] < list2[i])):
            # or ((list1[i-1] < list2[i-1]) and (list1[i] > list2[i]))):
            points.append((ps[i], (list1[i-1]+list1[i])/2))

    return points

def transform(points):
    xs = []
    ys = []

    for i in points:
        xs.append(i[0])
        ys.append(i[1])

    return (xs, ys)

############## Constants and global variables ################

alice0, bob0, alice1, bob1, alice2, bob2 = [], [], [], [], [], []

num_trial = 500

time = 50

givenP = 0.5

freqMean = 0.10

freqSigma = 0.001

############# Main functions #####################

def runWithPayment(time):
    ps = [x* 1.0 /100 for x in range(1, 150)]

    f = np.random.lognormal(freqMean, freqSigma)
    # random.expovariate(givenP)
    # ps = np.arange(0.0, 1.0 + 0.01, 0.01)

    for i in range(len(ps)):
        # trial
        print(str(i))
        res = [0, 0, 0, 0, 0, 0]
        temp = []
        for k in range(num_trial):
            temp = main(p=ps[i], freq=f, timeRun = time)
            for j in range(len(temp)):
                res[j] += temp[j]
        for j in range(len(res)):
            res[j] = res[j]/float(num_trial)

        alice0.append(res[0])
        bob0.append(res[1])
        alice1.append(res[2])
        bob1.append(res[3])
        alice2.append(res[4])
        bob2.append(res[5])

    # if Bob is taking the lowest fee he can, it would be the difference between
    # if he transfer for Alice (bob2) and if he does not (bob0=bob1)
    minFee = calculateFee(bob2, bob0)

    # Alice's cost increase while Bob's cost decrease by the fee charged
    aliceAfter = payFee(alice0, minFee)
    bobAfter = chargeFee(bob2, minFee)

    alicePoints = transform(getIntersections(alice1, aliceAfter, ps))
    bobPoints = transform(getIntersections(bob0, bobAfter, ps))

    bobxs = bobPoints[0]
    bobys = bobPoints[1]
    alicexs = alicePoints[0]
    aliceys = alicePoints[1]

    # get the benefit by analyzing the costs in different networks
    aliceBenefit = chargeFee(alice1, aliceAfter)
    bobBenefit = chargeFee(bob0, bobAfter)

    fig = plt.figure(figsize=plt.figaspect(0.5))

    ax = fig.add_subplot(1, 1, 1)

    ax.plot(ps, bob0, "k")
    ax.plot(ps, alice1, "r")
    # ax.plot(ps, bob2, "m")
    # ax.plot(ps, bob1, "k--")
    # ax.plot(ps, alice2, "c--")
    ax.plot(ps, aliceAfter, "b-")
    ax.plot(ps, bobAfter, "g-")
    # ax.plot(bobxs, bobys, "go")

    ax.plot(ps, aliceBenefit)
    ax.plot(ps, bobBenefit)
    ax.plot(ps, [0 for x in range(len(ps))], "k--")
    ax.plot(alicexs, aliceys, "bo")

    trans_offset = mtransforms.offset_copy(ax.transData, fig=fig,
                                       x=0.01, y=-0.30, units='inches')

    for x, y in zip(bobxs, bobys):
        plt.plot(x, y, 'go')
        # plt.text(x, y, '%02f, %02f' % (x, y), transform=trans_offset)

    fig.text(0, 0, 'Alice Points %s; Bob Points %s\n Number of trials: %d; Time of each network: %d; Freq mean: %f' % (str(alicePoints), str(bobPoints), num_trial, time, freqMean))

    ax.set_title('Transferred payment size vs Cost differences after Min Fee')
    ax.set_xlabel('Payment size')
    ax.set_ylabel('Cost differences')

    # plt.axis([0, 6, 0, 100])
    fig.legend(["bob", "alice", "alice' ", "bob'", "alice benefit", "bob benefit"])
    fig.savefig('paysFeeBenefit_Min.png')

################ Call #####################

runWithPayment(time)
# runWithFreq()


from mpl_toolkits import mplot3d
import matplotlib.pyplot as plt
import numpy as np
import csv as csv
import math
import scipy.interpolate as spin
#Function to train a perceptron
def PerceptronTrain(X, Y):
 d = np.shape(X)[1]
 n = np.shape(X)[0]
 theta = np.zeros([1, d])
 alltheta=[]
 allError=[]
 allError.append(1)
 alltheta.append(theta[0])
 firstItr=0
 k = 0
 i = 0
 while True:
  for row in X:
   mu = Y[i]*np.dot(theta, row)
   if mu < 0 or firstItr==0:
    tempRow=[]
    for elm in row:
        multip=float(Y[i])
        tempRow.append(elm*multip)
    theta=theta+tempRow
    alltheta.append(theta[0])
    allError.append(perceptron_test(theta,X,Y))
    firstItr=firstItr+1
    k = k+1
   if i==n-1:
    i=-1
   i = i+1
  if allError[k]==0:
   break
 if d==2:
  errorSurfacePlot(alltheta,allError)
 return theta, k
#plot the error surface for 2-dim inputs only
def errorSurfacePlot(alltheta,allError):
 xaxis=[]
 yaxis=[]
 zaxis=allError
 for elm in alltheta:
  xaxis.append(elm[0])
  yaxis.append(elm[1])
 old_indicesX = np.arange(0,len(xaxis))
 old_indicesy = np.arange(0,len(yaxis))
 old_indicesz = np.arange(0,len(zaxis))
 new_indicesX = np.linspace(0,len(xaxis)-1,10000)
 new_indicesy = np.linspace(0,len(yaxis)-1,10000)
 new_indicesz = np.linspace(0,len(zaxis)-1,10000)
 splx = spin.UnivariateSpline(old_indicesX,xaxis,k=3,s=0)
 sply = spin.UnivariateSpline(old_indicesy,yaxis,k=3,s=0)
 splz = spin.UnivariateSpline(old_indicesz,zaxis,k=3,s=0)
 newX = splx(new_indicesX)
 newy = sply(new_indicesy)
 newZ = splz(new_indicesz)
 fig = plt.figure()
 ax = plt.axes(projection='3d')
 surf=ax.plot_trisurf(np.array(newy), np.array(newX), np.array(newZ), cmap='plasma',antialiased=True,shade=True)
 ax.set_xlabel('Theta(i)', fontsize=10, rotation=150)
 ax.set_ylabel('Theta(J)', fontsize=10, rotation=130)
 ax.set_zlabel('||Error||', fontsize=10, rotation=-60)
 fig.colorbar(surf, shrink=0.5, aspect=10)
 plt.show()
#Function to Count errors
def perceptron_test(theta, X_test, y_test):
 theta=theta[0]
 y=[]
 for row in X_test:
     y.append(math.copysign(1,np.dot(row,theta)))
 error = []
 zip_object = zip(y, y_test)
 for list1_i, list2_i in zip_object:
       if list1_i==list2_i:
         error.append(0)
       if list1_i!=list2_i:
         error.append(1)
 magOferror=sum(error)/len(error)
 return magOferror
#Decision boundary plot
def Decision_boundary_Plot(theta,X):
 theta=theta[0]
 y=[]
 plt.figure(figsize=(10,6))
 plt.grid(True)
 for row in X:
  y.append(math.copysign(1,np.dot(row,theta)))
 for X,Y in zip(X,y):
  plt.plot(X[0],X[1],'r*' if (Y == 1.0) else 'b*',)
 slope=-1*theta[1]/theta[0]
 i = np.linspace(-100*np.amin(X),100*np.amax(X))
 z=slope*i
 plt.plot(i, z,)
 plt.show()
#Test Script
with open('p1_b_X.dat') as f:
 datax = f.readlines()
 X = csv.reader(datax, delimiter=' ')
 xd = []
 floatRow=[]
for row in X:
 while '' in row:
        row.remove('')
 for item in row:
        floatRow.append(float(item))
 xd.append(floatRow)
 floatRow=[]
with open('p1_b_y.dat') as z:
 datay = z.readlines()
 Y = csv.reader(datay, delimiter=' ')
 yd = []
for row in Y:
 while '' in row:
  row.remove('')
 for item in row:
        floatRow.append(float(item))
 yd.append(floatRow[0])
 floatRow=[]
out=PerceptronTrain(xd,yd)
Decision_boundary_Plot(out[0],xd)


#!/usr/bin/env python

from elasticsearch import Elasticsearch
from MaltegoTransform import *
import os

phrase = sys.argv[1]
m = MaltegoTransform()

try:
 es = Elasticsearch('http://127.0.0.1:9200')

 res = es.search(index="crawl", doc_type="tor", body={"query": {"match": {"url": phrase}}})
 for doc in res['hits']['hits']:
  m.addEntity('maltego.Location', ', '.join(doc['_source']['entities']['locations']).decode('utf-8', 'ignore'))

except Exception as e:
 m.addUIMessage(str(e))

m.returnOutput()


# -*- coding: UTF-8 -*-
'''
    nereid.static_file

    Static file

    :copyright: (c) 2011-2012 Openlabs Technologies & Consulting (P) Limited
    :copyright: (c) 2010 by Sharoon Thomas.
    :license: GPLv3, see LICENSE for more details
'''
import os
import urllib

from nereid.helpers import slugify, send_file, url_for
from nereid.globals import _request_ctx_stack
from werkzeug import abort

from trytond.model import ModelSQL, ModelView, fields
from trytond.config import CONFIG
from trytond.transaction import Transaction
from trytond.pyson import Eval, Not, Equal

# pylint: disable-msg=E1101

class NereidStaticFolder(ModelSQL, ModelView):
    "Static folder for Nereid"
    _name = "nereid.static.folder"
    _description = __doc__
    _rec_name = 'folder_name'

    folder_name = fields.Char(
        'Folder Name', required=True, select=1,
        on_change_with=['name', 'folder_name']
    )
    description = fields.Char('Description', select=1)
    files = fields.One2Many('nereid.static.file', 'folder', 'Files')

    def __init__(self):
        super(NereidStaticFolder, self).__init__()
        self._constraints += [
            ('check_folder_name', 'invalid_folder_name'),
        ]
        self._sql_constraints += [
            ('unique_folder', 'UNIQUE(folder_name)',
             'Folder name needs to be unique')
        ]
        self._error_messages.update({
            'invalid_folder_name': """Invalid folder name:
                (1) '.' in folder name (OR)
                (2) folder name begins with '/'""",
            'folder_cannot_change': "Folder name cannot be changed"
        })

    def on_change_with_folder_name(self, vals):
        """
        Fills the name field with a slugified name
        """
        if vals.get('name'):
            if not vals.get('folder_name'):
                vals['folder_name'] = slugify(vals['name'])
            return vals['folder_name']

    def check_folder_name(self, ids):
        '''
        Check the validity of folder name
        Allowing the use of / or . will be risky as that could
        eventually lead to previlege escalation

        :param ids: ID of current record.
        '''
        folder = self.browse(ids[0])
        if ('.' in folder.folder_name) or (folder.folder_name.startswith('/')):
            return False
        return True

    def write(self, ids, vals):
        """
        Check if the folder_name has been modified.
        If yes, raise an error.

        :param vals: values of the current record
        """
        if vals.get('folder_name'):
            # TODO: Support this feature in future versions
            self.raise_user_error('folder_cannot_change')
        return super(NereidStaticFolder, self).write(ids, vals)

NereidStaticFolder()

class NereidStaticFile(ModelSQL, ModelView):
    "Static files for Nereid"
    _name = "nereid.static.file"
    _description = __doc__

    name = fields.Char('File Name', select=True, required=True)
    folder = fields.Many2One(
        'nereid.static.folder', 'Folder', select=True, required=True
    )
    type = fields.Selection([
        ('local', 'Local File'),
        ('remote', 'Remote File'),
    ], 'File Type')

    #: URL of the remote file if the :attr:`type` is remote
    remote_path = fields.Char('Remote File', select=True, translate=True,
        states = {
            'required': Equal(Eval('type'), 'remote'),
            'invisible': Not(Equal(Eval('type'), 'remote'))
        }
    )

    #: This function field returns the field contents. This is useful if the
    #: field is going to be displayed on the clients.
    file_binary = fields.Function(
        fields.Binary('File'), 'get_file_binary', 'set_file_binary',
    )

    #: Full path to the file in the filesystem
    file_path = fields.Function(fields.Char('File Path'), 'get_file_path')

    #: URL that can be used to idenfity the resource. Note that the value
    #: of this field is available only when called within a request context.
    #: In other words the URL is valid only when called in a nereid request.
    url = fields.Function(fields.Char('URL'), 'get_url')

    def __init__(self):
        super(NereidStaticFile, self).__init__()
        self._constraints += [
            ('check_file_name', 'invalid_file_name'),
        ]
        self._sql_constraints += [
            ('name_folder_uniq', 'UNIQUE(name, folder)',
                'The Name of the Static File must be unique in a folder.!'),
        ]
        self._error_messages.update({
            'invalid_file_name': """Invalid file name:
                (1) '..' in file name (OR)
                (2) file name contains '/'""",
        })

    def default_type(self):
        return 'local'

    def get_url(self, ids, name):
        """Return the url if within an active request context or return
        False values
        """
        res = {}.fromkeys(ids, False)
        if _request_ctx_stack.top is None:
            return res

        for f in self.browse(ids):
            if f.type == 'local':
                res[f.id] = url_for(
                    'nereid.static.file.send_static_file',
                    folder=f.folder.folder_name, name=f.name
                )
            elif f.type == 'remote':
                res[f.id] = f.remote_path
        return res

    def get_nereid_base_path(self):
        """
        Returns base path for nereid, where all the static files would be
        stored.

        By Default it is:

        <Tryton Data Path>/<Database Name>/nereid
        """
        cursor = Transaction().cursor
        return os.path.join(
            CONFIG['data_path'], cursor.database_name, "nereid"
        )

    def set_file_binary(self, ids, name, value):
        """
        Setter for the functional binary field.

        :param ids: List of ids. But usually has just one
        :param name: Ignored
        :param value: The file buffer
        """
        for f in self.browse(ids):
            if f.type == 'local':
                file_binary = buffer(value)
                # If the folder does not exist, create it recursively
                directory = os.path.dirname(f.file_path)
                if not os.path.isdir(directory):
                    os.makedirs(directory)
                with open(f.file_path, 'wb') as file_writer:
                    file_writer.write(file_binary)

    def get_file_binary(self, ids, name):
        '''
        Getter for the binary_file field. This fetches the file from the
        file system, coverts it to buffer and returns it.

        :param ids: the ids of the sales
        :return: Dictionary with ID as key and file buffer as value
        '''
        res = {}
        for f in self.browse(ids):
            location = f.file_path if f.type == 'local' \
                else urllib.urlretrieve(f.remote_path)[0]
            with open(location, 'rb') as file_reader:
                res[f.id] = buffer(file_reader.read())
        return res

    def get_file_path(self, ids, name):
        """
        Returns the full path to the file in the file system

        :param ids: the ids of the sales
        :return: Dictionary with ID as key and binary
        """
        res = {}
        for f in self.browse(ids):

            res[f.id] = os.path.abspath(
                os.path.join(
                    self.get_nereid_base_path(), f.folder.folder_name, f.name
                )) \
            if f.type == 'local' else f.remote_path
        return res

    def check_file_name(self, ids):
        '''
        Check the validity of folder name
        Allowing the use of / or . will be risky as that could
        eventually lead to previlege escalation

        :param ids: ID of current record.
        '''
        file_ = self.browse(ids[0])
        if ('..' in file_.name) or ('/' in file_.name):
            return False
        return True

    def send_static_file(self, folder, name):
        """
        Invokes the send_file method in nereid.helpers to send a file as the
        response to the reuqest. The file is sent in a way which is as
        efficient as possible. For example nereid will use the X-Send_file
        header to make nginx send the file if possible.

        :param folder: folder_name of the folder
        :param name: name of the file
        """
        #TODO: Separate this search and find into separate cached method

        ids = self.search([
            ('folder.folder_name', '=', folder),
            ('name', '=', name)
            ])
        if not ids:
            abort(404)
        file_ = self.browse(ids[0])
        return send_file(file_.file_path)

NereidStaticFile()


# Program name: atomic1D/json_database/build_json.py
# Author: Thomas Body
# Author email: tajb500@york.ac.uk
# Date of creation: 12 July 2017
#

import numpy as np
import os

# Supported adf11 data classes.  See src/xxdata_11/xxdata_11.for for all the
# twelve classes.
# TBody: added charge exchange reccombination (15/7/15) in addition to classes supported by cfe316/atomic
adf11_classes = {
    'acd' : 1, # recombination coefficients
    'scd' : 2, # ionisation coefficients
    'ccd' : 3, # charge-exchange reccombination
    'prb' : 4, # continuum radiation power
    'plt' : 8, # line radiation power
    'prc' : 5, # charge-exchange recombination radiation
    'ecd' : 12 # effective ionisation potential
}

datatype_abbrevs = {
        'ionisation'           : 'scd',
        'recombination'        : 'acd',
        'cx_recc'              : 'ccd',
        'continuum_power'      : 'prb',
        'line_power'           : 'plt',
        'cx_power'             : 'prc',
        'ionisation_potential' : 'ecd',
}

# Invert the mapping of datatype_abbrevs
inv_datatype_abbrevs = {v: k for k, v in datatype_abbrevs.items()}

def check_cwd():
    # Checks that current working directory or its parent contains adas_data. If not, raises FileNotFoundError
    # If adas_data folder found, returns the contents as a list
    print('Current working directory is: {}'.format(os.getcwd()))
    if os.path.isdir('adas_data'):
        print('adas_data/ sub-directory found - proceeding')
    else:
        if os.path.isdir('../adas_data'):
            print('adas_data/ sub-directory found in parent directory')
            os.chdir("..")
            print('changing directory to {}'.format(os.getcwd()))
            print(' - proceeding')
        else:
            print('adas_data not found - check adas_data/ is a subdirectory of current working directory')
            raise(FileNotFoundError)

    return os.listdir(os.getcwd()+"/adas_data")

class Sniffer(object):
    """Inspector for a filename.
    << From cfe316/atomic-master/atomic/adf11.py >>

    Holds a split-apart adf11 filename.

    Attributes:
        file_ (str): full filename
        name (str): file's basename 'scd96r_li.dat'
        element (str): short element name 'li'
        year (str): short year name '96'
        class_ (str): file type 'scd'
        extension (str): should always be 'dat'
        resolved (bool): true for this example, but should always be False.
    """
    def __init__(self, file_):
        self.file_ = file_
        self.name = os.path.basename(file_)

        self._sniff_name()
        self._check()

    def _sniff_name(self):
        name, extension = self.name.split(os.path.extsep)

        type_, element = name.split('_')
        class_ = type_[:3]
        year = type_[3:]
        resolved = year.endswith('r')

        self.element = element
        self.year = year
        self.class_ = class_
        self.extension = extension
        self.resolved = resolved

    def _check(self):
        assert self.extension == 'dat'
        assert self.resolved == False, 'Metastable resolved data not supported.'

def read_xxdata_11(file_full_path,file_class):
    # Use fortran helper functions to read .dat file into a python-readable raw_return_value
    # Inputs: file_full_path -> the absolute path of the .dat file
    #         file_class    -> the adf11 class (i.e. 'acd', 'scd', etc)

    # <<will need to find the correct path for _xxdata_11 - may be either the version in atomic or in src>>

    from src import _xxdata_11

    # Some hard coded parameters to run xxdata_11.for routine.  The values have
    # been take from src/xxdata_11/test.for, and should be OK for all files.
    parameters = {
        'isdimd' : 200,
        'iddimd' : 40,
        'itdimd' : 50,
        'ndptnl' : 4,
        'ndptn' : 128,
        'ndptnc' : 256,
        'ndcnct' : 100
    }
    # Key to inputs (from xxdata_11.pdf)
    # type  | name   | description
    # (i*4) | iunit  | unit to which input file is allocated
    # (i*4) | iclass | class of data (numerical code) - see table below
    # ----------------------------------------------------------
    # use defaults (set in parameters) for everything below this
    # ----------------------------------------------------------
    # (i*4) | isdimd | maximum number of (sstage, parent, base)
    #       |        | blocks in isonuclear master files
    # (i*4) | iddimd | maximum number of dens values in
    #       |        | isonuclear master files
    # (i*4) | itdimd | maximum number of temp values in
    #       |        | isonuclear master files
    # (i*4) | ndptnl | maximum level of partitions
    # (i*4) | ndptn  | maximum no. of partitions in one level
    # (i*4) | ndptnc | maximum no. of components in a partition
    # (i*4) | ndcnct | maximum number of elements in connection vector

    iclass = adf11_classes[file_class]
    iunit = _xxdata_11.helper_open_file(file_full_path)
    raw_return_value =  _xxdata_11.xxdata_11(iunit, iclass, **parameters)
    _xxdata_11.helper_close_file(iunit)

    return raw_return_value

def extract_data_dict(raw_return_value,file_class,file_element,file_full_path):
    # Based on _convert_to_dictionary method of adf11.py
    # Extract information from ret.
    iz0, is1min, is1max, nptnl, nptn, nptnc, iptnla, iptna, iptnca, ncnct,\
    icnctv, iblmx, ismax, dnr_ele, dnr_ams, isppr, ispbr, isstgr, idmax,\
    itmax, ddens, dtev, drcof, lres, lstan, lptn = raw_return_value

    # Key to outputs (from xxdata_11.pdf)
        # type   | name       | description
        # (i*4)  | iz0        | nuclear charge
        # (i*4)  | is1min     | minimum ion charge + 1
        #        |            | (generalised to connection vector index)
        # (i*4)  | is1max     | maximum ion charge + 1
        #        |            | (note excludes the bare nucleus)
        #        |            | (generalised to connection vector index and excludes
        #        |            | last one which always remains the bare nucleus)
        # (i*4)  | nptnl      | number of partition levels in block
        # (i*4)  | nptn()     | number of partitions in partition level
        #        |            | 1st dim: partition level
        # (i*4)  | nptnc(,)   | number of components in partition
        #        |            | 1st dim: partition level
        #        |            | 2nd dim: member partition in partition level
        # (i*4)  | iptnla()   | partition level label (0=resolved root,1=
        #        |            | unresolved root)
        #        |            | 1st dim: partition level index
        # (i*4)  | iptna(,)   | partition member label (labelling starts at 0)
        #        |            | 1st dim: partition level index
        #        |            | 2nd dim: member partition index in partition level
        # (i*4)  | iptnca(,,) | component label (labelling starts at 0)
        #        |            | 1st dim: partition level index
        #        |            | 2nd dim: member partition index in partition level
        #        |            | 3rd dim: component index of member partition
        # (i*4)  | ncnct      | number of elements in connection vector
        # (i*4)  | icnctv()   | connection vector of number of partitions
        #        |            | of each superstage in resolved case
        #        |            | including the bare nucleus
        #        |            | 1st dim: connection vector index
        # (i*4)  | iblmx      | number of (sstage, parent, base)
        #        |            | blocks in isonuclear master file
        # (i*4)  | ismax      | number of charge states
        #        |            | in isonuclear master file
        #        |            | (generalises to number of elements in
        #        |            |  connection vector)
        # (c*12) | dnr_ele    | CX donor element name for iclass = 3 or 5
        #        |            | (blank if unset)
        # (r*8)  | dnr_ams    | CX donor element mass for iclass = 3 or 5
        #        |            | (0.0d0 if unset)
        # (i*4)  | isppr()    | 1st (parent) index for each partition block
        #        |            | 1st dim: index of (sstage, parent, base)
        #        |            |          block in isonuclear master file
        # (i*4)  | ispbr()    | 2nd (base) index for each partition block
        #        |            | 1st dim: index of (sstage, parent, base)
        #        |            |          block in isonuclear master file
        # (i*4)  | isstgr()   | s1 for each resolved data block
        #        |            | (generalises to connection vector index)
        #        |            | 1st dim: index of (sstage, parent, base)
        #        |            |          block in isonuclear master file
        # (i*4)  | idmax      | number of dens values in
        #        |            | isonuclear master files
        # (i*4)  | itmax      | number of temp values in
        #        |            | isonuclear master files
        # (r*8)  | ddens()    | log10(electron density(cm-3)) from adf11
        # (r*8)  | dtev()     | log10(electron temperature (eV) from adf11
        # (r*8)  | drcof(,,)  | if(iclass <=9):
        #        |            | 	log10(coll.-rad. coefft.) from
        #        |            | 	isonuclear master file
        #        |            | if(iclass >=10):
        #        |            | 	coll.-rad. coefft. from
        #        |            | 	isonuclear master file
        #        |            | 1st dim: index of (sstage, parent, base)
        #        |            | 		 block in isonuclear master file
        #        |            | 2nd dim: electron temperature index
        #        |            | 3rd dim: electron density index
        # (l*4)  | lres       | = .true. => partial file
        #        |            | = .false. => not partial file
        # (l*4)  | lstan      | = .true. => standard file
        #        |            | = .false. => not standard file
        # (l*4)  | lptn       | = .true. => partition block present
        #        |            | = .false. => partition block not present

    # Make a new blank dictionary, data_dict
    data_dict = {}
    # Save data to data_dict
    data_dict['charge']                  = iz0                            # nuclear charge
    data_dict['log_density']             = ddens[:idmax]                  # log10(electron density(cm-3)) from adf11
    data_dict['log_temperature']         = dtev[:itmax]                   # log10(electron temperature (eV) from adf11
    data_dict['number_of_charge_states'] = ismax                          # number of charge states in isonuclear master file (generalises to number of elements in connection vector)
    data_dict['log_coeff']               = drcof[:ismax, :itmax, :idmax]  # if(iclass <=9):
                                                                          #     log10(coll.-rad. coefft.) from isonuclear master file
                                                                          # if(iclass >=10):
                                                                          #     coll.-rad. coefft. from isonuclear master file
                                                                          # 1st dim: index of (sstage, parent, base) block in isonuclear master file
                                                                          # 2nd dim: electron temperature index
                                                                          # 3rd dim: electron density index

    data_dict['class']   = file_class                                     # adf11 class (i.e. 'acd', 'scd', ...)
    data_dict['element'] = file_element                                   # element symbol (i.e. 'c' for carbon, ...)
    data_dict['name']    = file_full_path                                 # full path to the data file

    # convert everything to SI + eV units
    data_dict['log_density'] += 6 # log(cm^-3) = log(10^6 m^-3) = 6 + log(m^-3)
    # N.b. the ecd (ionisation potential) class is already in eV units.
    if data_dict['class'] != 'ecd':
        data_dict['log_coeff'] -= 6 # log(m^3/s) = log(10^-6 m^3/s) = -6 + log(m^3/s)
    else:
        data_dict['log_coeff'] = np.log10(data_dict['log_coeff'][1:])

    return data_dict

def data_dict_types(data_dict):
    # Print out the type of each element in data_dict (helps to identify which ones need to be jsonified)
    for key, element in data_dict.items():
        print("data key: {:30} data type: {:30}".format(key,str(type(element))))

def store_as_JSON(data_dict,file_basename):
    from copy import deepcopy
    import json

    # Need to 'jsonify' the numpy arrays (i.e. convert to nested lists) so that they can be stored in plain-text
    # Deep-copy data to a new dictionary and then edit that one (i.e. break the data pointer association - keep data_dict unchanged in case you want to run a copy-verify on it)

    data_dict_jsonified = deepcopy(data_dict)

    numpy_ndarrays = [];
    for key, element in data_dict.items():
        if type(element) == np.ndarray:
            # Store which keys correspond to numpy.ndarray, so that you can de-jsonify the arrays when reading
            numpy_ndarrays.append(key)
            data_dict_jsonified[key] = data_dict_jsonified[key].tolist()

    data_dict_jsonified['numpy_ndarrays'] = numpy_ndarrays

    # Encode help
    data_dict_jsonified["help"] = "JSON file corresponding to an OpenADAS data file\nCreated by TBody/atomic1D/build_json.py/store_as_JSON\nDocumentation at https://github.com/TBody/atomic1D"

    # <<Use original filename, except with .json instead of .dat extension>>
    with open('json_data/{}.json'.format(file_basename),'w') as fp:
        json.dump(data_dict_jsonified, fp, sort_keys=True, indent=4)

def retrive_from_JSON(file_name):
    # Inputs - a JSON file corresponding to an OpenADAS .dat file
    # file_name can be either relative or absolute path to JSON file
    # Must have .json extension and match keys of creation
    # Not need for the .dat -> .json conversion, but included for reference
    import json
    from warnings import warn
    from copy import deepcopy
    import numpy as np

    file_extension  = file_name.split('.')[-1] #Look at the extension only (last element of split on '.')
    if file_extension != 'json':
        raise NotImplementedError('File extension (.{}) is not .json'.format(file_extension))

    with open(file_name,'r') as fp:
        data_dict = json.load(fp)

    if set(data_dict.keys()) != {'charge','class','element', 'help','log_coeff','log_density','log_temperature','name','number_of_charge_states'}:
        warn('Imported JSON file {} does not have the expected set of keys - could result in an error'.format(file_name))

    # Convert jsonified numpy.ndarrays back from nested lists
    data_dict_dejsonified = deepcopy(data_dict)

    for key in data_dict['numpy_ndarrays']:
        data_dict_dejsonified[key] = np.array(data_dict_dejsonified[key])

    # print(data_dict['help'])

    return data_dict_dejsonified

if __name__ == '__main__':
    print('>> build_json.py called')
    print('\nConverting .dat files to .json files\n')

    # Check that adas_data can be found relative to current working directory
    # If adas_data folder found, returns the contents as a list
    adas_data_files = check_cwd()

    # Iterate over each file in the directory
    for adas_data_file in adas_data_files:
        file_basename  = adas_data_file.split('.')[0] #remove the .dat extension
        file_full_path = os.path.realpath("adas_data/"+adas_data_file)

        # Use Sniffer object to break apart filename to extract information. Also performs basic checks.
        s = Sniffer(file_full_path)
        if s.class_ not in adf11_classes:
            print('{} has class {} - not recognised as ADF11 class'.format(adas_data_file,s.class_))
            print('Skipping - will not produce a JSON file for this data')
            continue
            # raise NotImplementedError('Unknown adf11 class: %s' % s.class_) #If you make sure every file in adas_data gets a JSON made for it by this program
        else:
            # Extract the data from the Sniffer class
            file_element   = s.element
            file_year      = s.year
            file_class     = s.class_
            file_extension = s.extension
            file_resolved  = s.resolved
            # Could add a check here to see if the filename can be recreated

        # Read the fortran-formatted data file with the fortran helper functions
        raw_return_value = read_xxdata_11(file_full_path,file_class)

        # Extract a dictionary of useful data from
        data_dict = extract_data_dict(raw_return_value,file_class,file_element,file_full_path)

        store_as_JSON(data_dict,file_basename)

    print('\n>> setup_fortran_programs.py exited')

# Full table of ADF11 types (for reference)
    # class index | type | GCR data content
    # ------------\------\--------------------------------
    # 1           | acd  |  recombination coeffts
    # 2           | scd  |  ionisation coeffts
    # 3           | ccd  |  CX recombination coeffts
    # 4           | prb  |  recomb/brems power coeffts
    # 5           | prc  |  CX power coeffts
    # 6           | qcd  |  base meta. coupl. coeffts
    # 7           | xcd  |  parent meta. coupl. coeffts
    # 8           | plt  |  low level line power coeffts
    # 9           | pls  |  represent. line power coefft
    # 10          | zcd  |  effective charge
    # 11          | ycd  |  effective squared charge
    # 12          | ecd  |  effective ionisation potential