Email me at<EMAIL_ADDRESS>Senior at the University of Massachusetts - Amherst studying computer systems engineering and pursuing a minor in computer science. Here you will find information about my experience and skillset as well as information on how to contact me. Feel free to reach out to me for employment opportunities or questions about my work!
| Course Title | Semester Taken | Topics |
|---|---|---|
| Intro. to Electrical and Computer Engin. | Fall 2013 | Intro to CMOS design, covered from logic gates to RAM |
| Engineering Career Seminar | Fall 2013 | Basics of career networking and career fair preparation |
| Calculus II | Fall 2013 | Derivitices, integration, sequences, series, and power series. Taylor and MacLaurin series. |
| General Physics I | Fall 2013 | Analysis of classical motion, including kinematics, force, energy, and linear momentum. |
| Intro Problem Solving W/Comp | Spring 2014 | Programming course using Java covering data types to data abstraction to inheritance. |
| ST-ECE Systems Appreciation | Spring 2014 | Seminar for understanding how modern systems operate |
| Intro Linear Algebra | Spring 2014 | Linear algebra course covering up to eigenvalues and orthogonalization |
| General Physics II | Spring 2014 | Heat, kinetic theory, first and second laws of thermodynamics. Comprehensive study of electricity and magnetism from Coulomb's law to AmpEre's law. Applications to basic circuits and ending with AC circuits. |
| Circuit Analysis I | Fall 2014 | Mathematical models for analog circuit elements. Basic circuit laws and network theorems applied to dc, transient, and steady-state response of first- and second-order circuits. Modeling circuit responses using differential equations and the Laplace transform. Solving RLC networks in both the time and frequency domains. Computer projects and circuit simulations using MATLAB, Excel, and PSpice. |
| Data Structures & Algorithms | Fall 2014 | Data structures course using the Java programming language. Basic mathematical, logical, and programming concepts relevant to description and manipulation of information structures such as arrays, lists, trees, graphs, and files; the underlying principles of algorithm design and analysis applied to sorting and searching problems. |
| Multivariate Calculus | Fall 2014 | Techniques of calculus in two and three dimensions. Vectors, partial derivatives, multiple integrals, line integrals |
| Ordinary Differential Equation | Fall 2014 | Ordinary differential equations.First and second order linear differential equations, systems of linear differential equations, Laplace transform, numerical methods, applications. |
| Intro. to Computation | Spring 2015 | Discrete mathematics with logic, elementary number theory, proof by induction, recursion on trees, search algorithms, finite state machines, and a bit of computability. |
| Circuit Analysis II | Spring 2015 | Analysis techniques for ac circuits, frequency response, resonance, Bode plots, phasor representation of sinusoidal steady-state systems, complex frequency domain, transfer functions. MOSFETs as amplifiers; operational amplifiers. Transformers, two-port networks, Fourier series. Lab includes circuit hardware and PSPICE simulation experiments. |
| Hardware Organization & Design | Spring 2015 | Computer abstractions and technology, performance evaluation, instruction set architectures, computer arithmetic, pipelining, memory systems, and interfacing. Laboratory assignments will include the use of hardware description languages, machine languages and assembly languages. |
| Signals and Systems | Fall 2015 | Basic theory behind a further study of communication theory and systems, control theory and systems, signal processing, microwave and radar systems, networking and almost all disciplines of electrical and computer systems engineering. |
| Electronics I | Fall 2015 | Use of nonlinear devices such as diodes, field effect transistors (FETs), and bipolar junction transistors (BJTs) in the design of simple analog and digital circuits. Design projects make use of PSPICE. |
| Computer Syst Lab I | Fall 2015 | Design and analysis of digital computer (sub)systems, including sequential controllers, asynchronous system interfacing, bus arbitration, static and dynamic memory design, and microprogrammed microprocessor design. Use of hardware description languages and programmable logic. Breadboarding and use of diagnostic equipment. |
| Software Intensive Engineering | Fall 2015 | Theoretical and practical foundations for engineering the production of contemporary and future software intensive systems. Advanced engineering problem solving concepts and skills enabled by means of state of the art modeling and testing tools. Provides the basis for the analysis and co-design of complex hardware and software systems. |
| ECE Junior Seminar | Spring 2016 | Overview of the electrical and computer engineering field, including introduction to various subdisciplines and the corresponding upper-level ECE courses. |
| Intro. Probability & Random Proccesses | Spring 2016 | Probability space, conditional probability, Bayes theorem. Combinatorial analysis. Random variables (r.v.'s), distribution and density functions. Expected value, moments, characteristic function. Function of r.v.'s, Multiple r.v.'s, conditional distributions, independent r.v.'s. Multivariate Gaussian r.v.'s. Parameter estimation, confidence intervals, hypothesis testing. Introduction to random processes: mean, autocorrelation, power spectral density. |
| Computer Syst Lab II | Spring 2016 | Advanced computer systems engineering. CISC and RISC microprocessors, microcontrollers and their role in embedded systems. Integration of hardware and software, assembly language, memory systems, programmable logic, and I/O systems. Design methodologies. Manufacturing issues. Advanced diagnostic techniques. Project management. |
| Computer Networks & Internet | Spring 2016 | Explores the principles of computer networking and how the theoretical principles are implemented in practice. Introduction to concepts, principles, and practice of computer communication networks and the Internet with examples from existing architectures, protocols and standards. Emphasis on physical layer communication, data link layer protocols, routing protocols, transport layer protocols, application layer programming, network management, network security and wireless networks. |
| Senior Design Project I | Fall 2016 | The course requires students to work in small design teams to solve a significant engineering problem. Students develop, design, and implement a solution to the engineering problem in conjunction with a faculty advisor. The course reinforces principles of the engineering design process and serves as a capstone for electrical and computer engineering knowledge obtained in the ECE curriculum. The consideration of the ethical and social implications of technology and the basic concepts of business are also aspects of the course. Each student design team is expected to present information related to their project in both written and oral formats. Preliminary paper design is followed by implementation in the lab using digital and analog hardware design techniques and through software engineering. It is expected that a complete or partially working system will be demonstrated at the end of the course. |
| Trustworthy Computing | Fall 2016 | Introduces the fundamentals of network security as well as provides a practical survey of network security applications and standards as implemented on the Internet and for corporate networks. |
| Feedback Control Systems | Fall 2016 | With lab. Time domain and frequency domain analysis and synthesis techniques for linear continuous-time feedback control systems. Topics include benefits and costs of feedback, modeling of dynamic systems,steady-state and transient performance, stability, PID control, root locus, frequency response, Nyquist stability cri-terion, and introduction to loop-shaping. |
| Image Processing | Fall 2016 | 2D and 3D image acquisition and display, color representations, image sampling, point operations, linear image filtering and correlation, image transforms, image enhancement, image restoration and denoising, and image analysis. |
During the summer of 2016 I worked at ViaSat Inc. Where two other interns and I worked on BaaS (Builds as a Service). We used Python, Bash, Ansible, Docker, and Openstack to create a CLI and API that developers could use to quickly deploy Jenkins CI servers to the cloud. The service allowed developers to store configuration in version control and migrate non-BaaS servers to our service. All of this was done with an Agile Scrum developement process and all of our work had documentation written by us to allow users to continue our work when we left.
During the Summer of 2015, I participated in an REU (Research Experience for Undergraduates) where I worked under the guidance of Professor Qiangfei Xia and the Nanodevices and Integrated Systems Laboratory. My Research consited of creating MATLAB scripts to assist in the research of a graduate student attempting to show the possibilities of pattern recognition in memristor meshes. I presented my work to the group at the end of the summer.
Two classmates and I worked with Altera 2 developement boards to simulate a remote camera. We were tasked with linking the two boards through ethernet and sending instructions from a one to another using software-defined network layers that we created in C++ and Verilog. A 'master' board would sent commands to a 'slave' board to take an image, manipulate it in one of several ways, then compress and send the image back to the master. We designed the entirety of the system and the TCP protocol used to transmit and achknowledge the packets of data that the slave and master sent. We were judged by the effectiveness of our compression and the robustness of our system.
Our Computer Systems Lab was split into random groups of three with the task fo creating a general purpose MIDI explorer with an Atmel Atmega32 AVR chip and C code. Our team met frequently and divied the hardware, software and testing requirements among our members. By using the datasheet for the chip and our compression algorithm, we were able to store up to 1KB of audio on the chip's memory and play back the original recording. For extra credit, we added a photodiode that changed the way that the audio was played back depending on the light hitting it. The project involved debugging the code using gcc debugger, the hardware using a multimeter, and the signals using a logic analyzer.
Worked as a pair to create a UNIX shell in C++. Used fork() and exec() functions to execute the desired commands. Our end result was able to execute all UNIX commands in /bin, built-in commands (cd, jobs, and exit), I/O redirection, pipelining, and background processes in single or batch modes. We also wrote documentation to describe the functionality of our shell.
Worked indepenently in C++ on a TCP socket-based instant messenger. I wrote a multithreaded server that listened for clients and created a new thread to handle their requests. An arbitrary number of clients could connect and the clients could send messages to eachother and query the server to see who else is logged in. I finished the assignment by creating documentation to provide ease-of-use for using the messenger.
I led a team of four to create a simulation of a pipelined MIPS processor in C. The design of the code we wrote was based on the physical layout of a real processor and we used a collaborative coding environment to distribute the workload among the group. Together we created a program that maintained the correct register data at each stage of the instruction set. The simulator could be run in single step and batch modes and had the ability to handle hazards presented to it.
Worked in a team to create a C program to encrypt an ASCII text file based on a private seed key. Encryption algorithm was created to minimize repetition of encryption pattern to further prevent code cracking. Encrypted text was able to be fully decrypted using same private seed key. Algorithm passed test for encryption with various file sizes and different seed keys.
Utilized a large data set of pairs of names to link 'friends' in a network stored as a graph in Java. The goal of the project was to be able to perform a series of queries on the graph: to provide a suggestion of new friends to a given user based on the number of mutual friends they have and to give a path of friendships as 'degrees of separation' between any two nodes in the graph. I also created a small test script to do those operations on the graph and compare them directly to the data set.
Led a group of students in designing and proposing a speaker for Bose in Solidworks CAD. Bose 3D printed select designs and we soldered and assembled the amplifiers and speaker drivers into the final design and presented our work to Bose engineers at their headquarters.


{{currency.name}}
{% for exchange in exchanges %}
{{exchange.name}}
something else here
{% endfor %}


# set up
BASE_DIR = "/mnt/safran/TP2/data/"
import time
import glob
import matplotlib as mpl
import matplotlib.pylab as plt
%matplotlib inline
import matplotlib.dates as mdates
mpl.rcParams['axes.grid'] = True
import numpy as np
import scipy as sp
import pandas as pd
pd.options.display.max_columns = 23
from datetime import datetime
from sklearn import tree, linear_model, model_selection, preprocessing, decomposition
from sklearn.metrics import mean_squared_error
# read_pickle
dfs = []
files = glob.glob(BASE_DIR + "flights/*.pkl")
p = 0
for idx, file in enumerate(files):
if idx % int(len(files) / 10) == 0:
print(str(p * 10) + "%: [" + "#" * p + " " * (10 - p) + "]", end="\r")
p += 1
dfs.append(pd.read_pickle(file))
# load global values data, Summarising global values in a dataframe
file_features_df = BASE_DIR + "features_df.pkl"
file_output_df = BASE_DIR + "output_df.pkl"
features_df = pd.read_pickle(file_features_df)
output_df = pd.read_pickle(file_output_df)
# flight_phases
flight_phases = ['APPROACH', 'CLIMB', 'CRUISE', 'DESCENT', 'ENG START', 'FINAL APP',
'FLARE', 'INIT CLIMB', 'LANDING', 'TAKE OFF', 'TAXI IN', 'TAXI OUT', 'TOUCH N GO',
'LVL CHANGE', 'GO AROUND']
Context
You are provided with nearly 3000 flights operating different routes.
Each flight data is a collection of time series resumed in a dataframe, the sample rate is 1Hz, the columns variables are described in the schema below:
Schema
| VAR | DESCRIPTION | UNIT |
|---|---|---|
| ORIGIN | Flight departure airport | NA |
| RUNWAY_TO | Flight origin runway | NA |
| DESTINATION | Flight arrival airport | NA |
| RUNWAY_LD | Flight destination runway | NA |
| DATE_HF | High rate date computation | %d/%m/%y (UTC) |
| TIME_HF | High rate time computation | %H:%M:%S (UTC) |
| FLIGHT_PHASE | Current flight-phase | NA |
| ALT_STD_C | Standard altitude corrected | feet |
| HEAD_MAG | Magnetic heading | deg |
| IAS_C | Indicated air speed corrected | knot |
| RALTC | Radio altitude computed from different sources | feet |
| PITCH_C | Pitch attitude corrected | deg |
| ROLL_C | Bank angle corrected | deg |
| FOB | Fuel on board | kg |
| TORQ1_C | Torque corrected (engine 1) | % |
| TORQ2_C | Torque corrected (engine 2) | % |
| NH1_C | NH corrected (engine 1) | % |
| NH2_C | NH corrected (engine 2) | % |
| NL1 | NL Left from frequency input | % |
| NL2 | NL Right from frequency input (NL2) | % |
| GW_C | Gross weight corrected | kg |
Here are some links to get expertise on some variables:
df.describe()
Let's visualize all the numerical time series for one flight, for example dfs[0]
, to have a sense of how the time series vary.
# Give an alias to dfs[0] for convenience
df = dfs[0]
df.plot(kind="line", subplots=True, layout=(4, 4), figsize=(15, 12));
Comment this visualization of FOB for several flights.
# Create a figure and one subplot
fig, ax = plt.subplots(figsize=(20, 6))
for df in dfs[:500]:
df.FOB.plot(use_index=False, color="C0", ax=ax, title="FOB for several flights", alpha=0.5)
Observe how ALT_STD_C varies for each phase
# Create a figure and one subplot
fig, ax = plt.subplots(figsize=(15, 4))
# Give an alias to dfs[0]
df = dfs[0]
df.groupby("FLIGHT_PHASE").ALT_STD_C.plot(title="ALT_STD_C grouped by FLIGHT_PHASE", ax=ax);
ax.legend()
Typical chronology of cruise phases:
- ENG START
- TAXI OUT
- TAKE OFF
- INIT CLIMB
- CLIMB
- CRUISE
- DESCENT
- APPROACH
- FINAL APP
- FLARE
- LANDING
- TAXI IN
Phases that exist only for some flights:
- LVL CHANGE
- GO AROUND
- TOUCH N GO
MAX_FOB
: FOB at the beginning of the flightMIN_FOB
: FOB at the end of the flightDELTA_FOB
: MAX_FOB
- MIN_FOB
the amount of fuel consumed during the whole flight# Create a figure and one subplot
fig, ax = plt.subplots(figsize=(15, 4))
# Give an alias to dfs[0]
df = dfs[0]
df.FOB.plot(title="FOB")
plt.axhline(df.FOB.max(), color="C1")
plt.axhline(df.FOB.min(), color="C1")
plt.axvline(df.FOB.index[-200], linestyle=":", color="C3")
plt.text(df.FOB.index[-550], 2500, "DELTA_FOB", color="C3")
From this FOB signal we will only be interested in deltas, that is the amount of fuel consumed over a certain time period. The first approach will focus on predicting the delta of all the flight, the second approach will be predicting the deltas of each flight phase
The story
A company asks you to help them optimize the fuel consumption of their fleet. They've been collecting data from their flights for 2 years, operating on four different routes. They do not understand why sometimes the pilots consume 800 kilograms of fuel and sometimes 600 kg for the same route. The company provided you with all their flights.
Your objective is two-fold:
In this part we will only use some summarised features of each flight, not the whole time series. Here are the features we will be using:
features_df
| VAR | DESCRIPTION |
|---|---|
| DATE_HF | date |
| DESTINATION | destination airport |
| ORIGIN | origin airport |
| RUNWAY_LD | runway landing |
| RUNWAY_TO | runway take-off |
| MAX_FOB | FOB at origin |
| MAX_GW | Gross weigth at origin |
| TIME_APPROACH | Approach length |
| TIME_CLIMB | Climb length |
| TIME_CRUISE | Cruise length |
| TIME_DESCENT | Descent length |
| TIME_ENG START | Eng start length |
| TIME_FINAL APP | Final app length |
| TIME_FLARE | Flare length |
| TIME_GO AROUND | Go around length |
| TIME_INIT CLIMB | Init climb length |
| TIME_LANDING | Landing length |
| TIME_LVL CHANGE | Lvl change length |
| TIME_TAKE OFF | Take off length |
| TIME_TAXI IN | Taxi in length |
| TIME_TAXI OUT | Taxi out length |
| TIME_TOUCH N GO | Touch n go length |
| TIME_TOTAL | Total length |
From these features we want to predict the amount of fuel consumed during the whole flight, that is DELTA_FOB
. Imagine that at the end of flight the sensor that measures FOB broke and that we cannot know how much fuel we have left.
output_df
| VAR | DESCRIPTION |
|---|---|
| DELTA_FOB | FOB conso |
The features_df
containing all the features described above has been computed for you, as well as output_df
.
features_df = pd.read_pickle(file_features_df)
features_df.head()
output_df = pd.read_pickle(file_output_df)
output_df.head()
In this question we compute some statistics about the population of flights:
features_df['ORIGIN'].value_counts()
features_df['DESTINATION'].value_counts()
In this question we focus on the output we want to predict: DELTA_FOB
in dataframe output_df
output_df.DELTA_FOB.plot.hist(bins=30)
In this question we work on the distributions of DELTA_FOB
conditionned on DESTINATION
and (optional) RUNWAY_LD
DELTA_FOB
distribution conditionned on DESTINATION
airport and comment.DELTA_FOB
distribution conditionned on DESTINATION
airport and RUNWAY_LD
and comment.df2 = pd.concat([output_df.DELTA_FOB, features_df.DESTINATION], axis=1)
df2.groupby('DESTINATION').plot.hist(bins=30)
Finally let's work with two important features: the total duration of the flight TOTAL_TIME
and the quantity of fuel at the beginning of the flight MAX_FOB
.
MAX_FOB
TIME_TOTAL
features_df.MAX_FOB.plot.hist(bins=50)
features_df.MAX_FOB.quantile([0.1, 0.25, 0.5, 0.75, 0.9])
features_df.TIME_TOTAL.plot.hist(bins=30)
features_df.TIME_TOTAL.quantile([0.1, 0.25, 0.5, 0.75, 0.9])
TIME_TOTAL
against DELTA_FOB
.df3 = pd.concat([output_df.DELTA_FOB, features_df.TIME_TOTAL], axis=1)
df3.plot.scatter('TIME_TOTAL', 'DELTA_FOB')
Let's explore the predictive power of TIME_TOTAL
on DELTA_FOB
. Our first model is the following linear regression:
LinearRegression
from sklearn package linear_model
(reference)TIME_TOTAL
DELTA_FOB
Follow the code below, in the following questions you will extensively use this template code and adapt it.
Comment briefly the results, the following questions can help you:
# This is template code for setting up a sklearn regression model
def modelTraining(featureMtrx=["TIME_TOTAL"], featureMtrx2=["DELTA_FOB"], test_size = 0.2, random_state = 42,
estimator = linear_model.LinearRegression(), reg=False):
X = features_df[featureMtrx].as_matrix()
y = output_df[featureMtrx2].as_matrix()
# Split the features and output in training and test sets
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=test_size, random_state=random_state)
if(reg):
X_train, X_test = regularize(numeric_features)
# Train the model using the training sets
estimator.fit(X_train, y_train)
# Test the model on tests sets
print("score (R2)", estimator.score(X_test, y_test))
modelTraining()
Adapt the code above for the following model
LinearRegression
TIME_TOTAL
, MAX_FOB
DELTA_FOB
Compare the score with the results of the previous regression
TIME_TOTAL
and MAX_FOB
?modelTraining(featureMtrx=['TIME_TOTAL', 'MAX_FOB'])
modelTraining(featureMtrx=['MAX_FOB'])
Before moving on and adding more features to our models, let's compare our linear regressions to a simple non-linear model:
DecisionTreeRegressor
from sklearn package tree
(reference)TIME_TOTAL
, MAX_FOB
DELTA_FOB
Adapt the code for the model described above.
What is the default behavior for max_depth
parameter?
max_depth
parameter (you can use the template code below)max_depth
parameters against the scoremodelTraining(featureMtrx=['TIME_TOTAL', 'MAX_FOB'], estimator=tree.DecisionTreeRegressor())
max_depths = range(2,20)
kFold = model_selection.KFold(n_splits=10)
scores = []
for max_depth in max_depths:
estimator=tree.DecisionTreeRegressor()
estimator.set_params(max_depth=max_depth)
score = []
folds = kFold.split(X)
for fold in folds:
# Unpack train and test indices
train, test = fold
# Split in train and test sets
X_train, X_test, y_train, y_test = X[train], X[test], y[train], y[test]
estimator.fit(X_train, y_train)
score.append(estimator.score(X_test, y_test))
scores.append(np.mean(score))
print("NodeCount for tree %d: %d"%(max_depth, estimator.tree_.node_count))
plt.plot(max_depths, scores, marker="*")
plt.title("score against max_depth \n validated with 10-fold CV")
Let's add all the other numeric features.
numeric_features = ['MAX_FOB',
'MAX_GW',
'TIME_APPROACH',
'TIME_CLIMB',
'TIME_CRUISE',
'TIME_DESCENT',
'TIME_ENG START',
'TIME_FINAL APP',
'TIME_FLARE',
'TIME_GO AROUND',
'TIME_INIT CLIMB',
'TIME_LANDING',
'TIME_LVL CHANGE',
'TIME_TAKE OFF',
'TIME_TAXI IN',
'TIME_TAXI OUT',
'TIME_TOUCH N GO',
'TIME_TOTAL']
In Question 3.5 we will use regularized regression. In this question we take a preliminary step and rescale the features.
We use the StandardScaler
from sklearn preprocessing
package (reference).
X_test_transformed
does not have a std of 1?def regularize(num_features=numeric_features, out_features=["DELTA_FOB"], dataframex=features_df, dataframey=output_df):
X = dataframex[num_features].as_matrix()
y = dataframey[out_features].as_matrix()
test_size = 0.2
random_state = 42
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=test_size, random_state=random_state)
scaler = preprocessing.StandardScaler()
scaler.fit(X_train, y_train)
X_train_transformed = scaler.transform(X_train)
X_test_transformed = scaler.transform(X_test)
print("X_train_transformed first feature,", "mean:", X_train_transformed[:, 0].mean(), "std:", X_train_transformed[:, 0].std())
print("X_test_transformed first feature,", "mean:", X_test_transformed[:, 0].mean(), "std:", X_test_transformed[:, 0].std())
return X_train_transformed, X_test_transformed
X_train_transformed, X_test_transformed = regularize(numeric_features)
The last question of this part focus on regularized linear regression.
Ridge
for sklearn package linear_model
(reference)numeric_features
of features_df
DELTA_FOB
Use the previous template codes and adapt it to set up the models described above and rescale the features
Split in validation sets and optimize alpha
parameter
# INPUT
X_train_transformed, X_test_transformed = regularize(numeric_features)
# HYPERPARAMETER
alphas = [0.001, 0.01, 0.1, 1, 10, 20, 50, 100]
kFold = model_selection.KFold(n_splits=10)
scores = []
for alpha in alphas:
estimator=linear_model.Ridge(alpha=alpha)
score = []
folds = kFold.split(X_train_transformed)
for fold in folds:
# Unpack train and validation indices
train, val = fold
# Split in train and validation sets
X_train, X_val, y_train, y_val = X[train], X[val], y[train], y[val]
estimator.fit(X_train, y_train)
score.append(estimator.score(X_val, y_val))
scores.append(np.mean(score))
plt.plot(alphas, scores, marker="*")
plt.title("score against alphas \n validated with 10-fold CV")
modelTraining(numeric_features, estimator=linear_model.Ridge(alpha=1), reg=True)
We will add a lot of information with engine-related time series:
TORQ1_C
, TORQ2_C
NL1
, NL2
NH1_C
, NH2_C
# Five an alias to dfs[0]
df = dfs[0]
engine_features = ['TORQ1_C', 'TORQ2_C',
'NL1', 'NL2',
'NH1_C', 'NH2_C']
df[engine_features].plot(subplots=True, layout=(3, 2), figsize=(15, 12));
We will extract few numbers out of each phase for all engine variables (TORQ1_C
, TORQ2_C
, NL1
, NL2
, NH1_C
, NH2_C
)
TORQ1_C
of one phase of one flight, do a linear regression by index and plot the resultlen(y_train)
y = df[df.FLIGHT_PHASE=='DESCENT'].TORQ1_C.as_matrix()
X = np.arange(1, len(X)+1)
X = X.reshape(-1, 1)
test_size = 0.2
random_state = 42
estimator = linear_model.LinearRegression()
# Split the features and output in training and test sets
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=test_size, random_state=random_state)
# Train the model using the training sets
estimator.fit(X_train, y_train)
# Test the model on tests sets
print("score (R2)", estimator.score(X_test, y_test))
pred = estimator.predict(X)
plt.plot(X, y, 'r')
plt.plot(X, pred, 'b')
plt.show()
These features have been created for you in the features2_df
dataframe.
file_features2 = BASE_DIR + "features2_df.pkl"
features2_df = pd.read_pickle(file_features2)
numeric_features2 = list(features2_df.columns.values)
numeric_features2.remove("DATE_HF")
numeric_features2.remove("ORIGIN")
numeric_features2.remove("DESTINATION")
numeric_features2.remove("RUNWAY_TO")
numeric_features2.remove("RUNWAY_LD")
features2_df.describe()
Let's be more ambitious and predict the fuel consumed by each phase. It would help a lot more to model the fuel consumption behavior for each phase when it will come to interpretation. The dataframe output2_df
containing the fuel consumed by each phase for each flight has been created for you.
file_output2 = BASE_DIR + "output2_df.pkl"
output2_df = pd.read_pickle(file_output2)
output2_df.describe()
In this question we make use of output2_df
to determine the phase that consumes the most fuel per second in average.
# This is template code to extract the phases durations out of features_df and rename the columns to make them identical to output2_df
phases_durations_df = features2_df[["TIME_" + fp for fp in flight_phases]]
phases_durations_df.columns = flight_phases
phases_durations_df.head()
# FLIGHT CONSUMPTION PER PHASE
output2_df.mean()
# FLIGHT CONSUMPTION RATE PER PHASE
output2_df.mean()/phases_durations_df.mean()
This last question aims to let you work with features2_df
and output2_df
. You can make use of any pieces of code we have worked with so far: especially to set up your models, rescale the features, optimize and validate your models... The expected outcome is to explain to the company what parameters influence the most the fuel consumption of their fleet and give them advice to consume less.
The algorithm:
features2_df
, output: output2_df
Interprete the coefficients, explain the causes of fuel consumption for each phase, give adive to the company to consume less in their following flights
# This is template code for setting up a sklearn regression model
def modelTraining(featureMtrx=["TIME_TOTAL"], featureMtrx2=["DELTA_FOB"], test_size = 0.2, random_state = 42,
estimator = linear_model.Ridge(), reg=False):
X = features2_df[featureMtrx].as_matrix()
X = X.reshape(-1, 1)
y = output2_df[featureMtrx2].as_matrix()
# Split the features and output in training and test sets
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=test_size, random_state=random_state)
if(reg):
X_train, X_test = regularize(numeric_features)
# Train the model using the training sets
estimator.fit(X_train, y_train)
# Test the model on tests sets
# print("score (R2)", estimator.score(X_test, y_test))
return estimator.score(X_test, y_test)
mtrx = []
for col in output2_df.columns:
m=[]
for row in numeric_features2:
m.append(modelTraining(row, col))
mtrx.append(m)
Answer
Your answer goes here


Home
Division B
Division C
Circuit Lab B
Home
Division B
Division C
Circuit Lab B
Interactive Learning: Curtsey of
Phet Colorado
.
Static Electricity
Charges and Fields
Coulomb's Law
DC Circuits
Resistance in a wire
Capacitors
Faraday's Law


My name is Evan
This is my page
Devin Mccourtney the Saftey for the Patriots
Is a free agent this year
Great player


Objective
- Obtain a professional position in computer science utilizing skills in full-stack software
development
Education
- Rose-Hulman Institute of Technology
- Terre Haute, IN | Expected May 2022
- B.S. Computer Science
- Minor: Japanese
- Status: Junior
Related Courses
- Object Orientated Programming
- Introduction to Computer Systems
- Data Structures and Algorithms
- Computer Architecture I
- Introduction to Database Systems
- Programming Language Concepts
- Software Requirements Engineering
- Software Design
- Design and Analysis of Algorithms
- Operating Systems
- Introduction to Web Development
- Artificial Intelligence
Skills
- Programming
- Python
- Java
- C, C++
- SQL
- Verilog
- Scheme
- HTML, CSS, JavaScript/jQuery
- Operating systems
- Windows
- Mac
- Linux (Ubuntu, Centos)
- Technologies
- Xilinx
- Git (Hub, Lab)
- Kubernetes
- Docker
- Docker Swarm
- Jira
- Languages
Experience/Projects
- Software Engineering Platform Interface Intern | F5 Networks | Summer 2021
- Work with cloud scale systems and learned various hardware platforms
- Contributed to the development process work in systems engineering by using GITLAB, C, C++,
Linux,
Agile/Jira
- Developed new code for the company’s SDK
- Worked with Docker containers on Kubernetes
- CM2W Startup Project | Java, Eclipse | January 2021
- Worked in a 4-member team that created a new management platform to work with IoT
capabilities
- Used Attribute Driven Design to establish Software Architecture
- Created domain models and class diagrams to design system
- Implemented various design patterns in software
- SRE Client Project | Interviews, Client Communication | October 2020
- Managed a 4-member team that developed an extensive design for software to be used by Terre
Haute
Labs
- Held several elicitation interviews with stakeholders to gather needs and features of the
domain
- Created use cases and prototypes to cover the features for the system
- Multicycle Processor | Verilog, Xilinx | January 2020
- Worked in a 4 -member team to create a 16-bit multicycle processor.
- Created a unique instruction set, data path, RTL, and control diagram that allowed the
processor
to
compute various algorithms
Activities
- WOLFPAC | August 2018 – 2020 | Women CS Club
- RHIT Mentoring Program | August 2018 – 2020 | Mentor
Honors
- Rose-Hulman Commitment Scholarship: Scholarship earned based on academic performance, community
service, and leadership


|
| | getEditMemberParams () |
| |
| | getForm ($identifier, $instance) |
| | Returns the form for adding or modifying an object. More...
|
| |
| | getMemberForm ($identifier, $instance, $member, $td, $part) |
| | Returns a form for member editing. More...
|
| |
| | setFormFieldsComponent (DataForm $form, $fieldTypes) |
| | Sets the components for each field. More...
|
| |
| | setMemberFormFieldsComponent (DataForm $form, $fieldTypes) |
| | Sets the components for each field. More...
|
| |
| | onGenerateFormField ($field, $nb) |
| | For doing something when $field is generated in form. More...
|
| |
| | isModal ($objects, $model) |
| | Condition to determine if the edit or add form is modal for $model objects. More...
|
| |
| | getFormCaptions ($captions, $className, $instance) |
| | Returns the captions for form fields.  More...
|
| |
| | setFormFieldsComponent_ (DataForm $form, $fieldTypes) |
| |
Definition at line 26 of file FormModelViewerTrait.php.
◆ defaultEditMemberParams()
| defaultEditMemberParams |
( |
| ) |
|
|
protected |
◆ getEditMemberParams()
◆ getEditMemberParams_()
| getEditMemberParams_ |
( |
|
$part | ) |
|
|
protected |
◆ getForm()
| getForm |
( |
|
$identifier, |
|
|
|
$instance |
|
) |
| |
Returns the form for adding or modifying an object.
- Parameters
-
| string | $identifier | |
| object | $instance | the object to add or modify |
- Returns
Definition at line 130 of file FormModelViewerTrait.php.
◆ getFormCaptions()
| getFormCaptions |
( |
|
$captions, |
|
|
|
$className, |
|
|
|
$instance |
|
) |
| |
Returns the captions for form fields.
- Parameters
-
| array | $captions | |
| string | $className | |
Definition at line 325 of file FormModelViewerTrait.php.
◆ getFormTitle()
| getFormTitle |
( |
|
$form, |
|
|
|
$instance |
|
) |
| |
|
protected |
Returns an associative array defining form message title with keys "icon","message","subMessage".
- Parameters
-
| DataForm | $form | |
| object | $instance | |
- Returns
- array the message title
Definition at line 234 of file FormModelViewerTrait.php.
◆ getMemberForm()
| getMemberForm |
( |
|
$identifier, |
|
|
|
$instance, |
|
|
|
$member, |
|
|
|
$td, |
|
|
|
$part |
|
) |
| |
Returns a form for member editing.
- Parameters
-
| string | $identifier | |
| object | $instance | |
| string | $member | |
| string | $td | |
| string | $part | |
- Returns
Definition at line 165 of file FormModelViewerTrait.php.
◆ isModal()
| isModal |
( |
|
$objects, |
|
|
|
$model |
|
) |
| |
Condition to determine if the edit or add form is modal for $model objects.
- Parameters
-
| array | $objects | |
| string | $model | |
- Returns
- boolean
Definition at line 315 of file FormModelViewerTrait.php.
◆ manyToManyFormField()
| manyToManyFormField |
( |
DataForm |
$form, |
|
|
|
$member, |
|
|
|
$instance, |
|
|
|
$annot |
|
) |
| |
|
protected |
◆ manyToOneFormField()
| manyToOneFormField |
( |
DataForm |
$form, |
|
|
|
$member, |
|
|
|
$className, |
|
|
|
$instance |
|
) |
| |
|
protected |
◆ oneToManyFormField()
| oneToManyFormField |
( |
DataForm |
$form, |
|
|
|
$member, |
|
|
|
$instance, |
|
|
|
$annot |
|
) |
| |
|
protected |
◆ onGenerateFormField()
| onGenerateFormField |
( |
|
$field, |
|
|
|
$nb |
|
) |
| |
◆ relationMembersInForm()
| relationMembersInForm |
( |
|
$form, |
|
|
|
$instance, |
|
|
|
$className, |
|
|
|
$fields, |
|
|
|
$relations |
|
) |
| |
|
protected |
◆ setFormFields_()
| setFormFields_ |
( |
& |
$fields, |
|
|
|
$relFields |
|
) |
| |
|
private |
◆ setFormFieldsComponent()
| setFormFieldsComponent |
( |
DataForm |
$form, |
|
|
|
$fieldTypes |
|
) |
| |
Sets the components for each field.
- Parameters
-
| DataForm | $form | |
| array | $fieldTypes | associative array of field names (keys) and types (values) |
Definition at line 248 of file FormModelViewerTrait.php.
◆ setFormFieldsComponent_()
| setFormFieldsComponent_ |
( |
DataForm |
$form, |
|
|
|
$fieldTypes |
|
) |
| |
|
protected |
◆ setMemberFormFieldsComponent()
| setMemberFormFieldsComponent |
( |
DataForm |
$form, |
|
|
|
$fieldTypes |
|
) |
| |
Sets the components for each field.
- Parameters
-
| DataForm | $form | |
| array | $fieldTypes | associative array of field names (keys) and types (values) |
Definition at line 258 of file FormModelViewerTrait.php.
The documentation for this class was generated from the following file:


{% include "partials/header.html" %}
{% include "partials/lead.html" %} {% include "partials/projects.html" %} {% include "partials/experience.html" %} {% include "partials/about.html" %}
{% include "partials/footer.html" %}


Delhi Smog: Can a clear solution be found?
by T C A Srinivasa-Raghavan'You can't consume clean air if you won't pay for it just because it's a 30-day problem,' says T C A Srinivasa-Raghavan.
Photograph: Saumya Khandelwal/Reuters
Every year for the past 10 years, the National Capital Region, comprising about 55,000 square km, chokes at this time of the year because of severe pollution.
One of the many contributory factors is the burning of paddy stubble.
Paddy is harvested in early October each year.
The governments of Delhi, Punjab, and Haryana are trying to persuade farmers not to burn the stubble.
The farmers are not listening because they don't have an alternative.
As a result, an impasse has developed.
The impasse can be broken if the problem is diagnosed.
The diagnosis is that it's not the burning of stubble but the cultivation of paddy that is the problem.
Punjab and Haryana are not traditional paddy states because the crop needs a lot of water and they have less of it naturally than, say, south or east India.
But the two state governments, by making water and electricity free two decades ago, have inadvertently caused the farmers to grow paddy -- around 15 million tonnes.
This is a case of what economics calls negative externalities.
Mr A maximises his welfare at the cost of Mr B.
Mr A's actions constitute a negative externality for Mr B.
This is what the paddy stubble problem is.
One way to prevent the cultivation of paddy is to charge for the water and electricity the farmers use.
But that would reduce their incomes even further.
In a highly competitive democracy, this is not a practical solution.
So what's to be done? The Coase Theorem in economics offers a partial solution to the problem of negative externalities.
It is named after the late Ronald Coase, who was awarded the Nobel Prize for it in 1991.
Pay the polluter
The theorem rests on many ifs and buts, but its core message is that if you think it's worth your while, pay your tormentor to stop tormenting.
This, by the way, was what India and China demanded on a global scale for climate issues.
The world decided it wasn't worth its while.
So everyone is worse off now.
Anyway, to get a sense of it, consider, for example, three adjacent houses.
The middle house is richer than the two on either side.
Being much poorer, they have built their toilets along their respective compound walls, instead of indoors.
This causes a stink for the house in the middle.
The rich owner of the middle house has five options -- buy the two adjacent houses; sell his own house and move; pay the other two to build indoor toilets; persuade the government to ban toilets that are outside the house; or seek help from the courts... What should he do?
The answer depends on the cost of each option.
On the face of it, the 'build them the damn toilets' option appears cheaper, but it need not be so if the two owners turn extortionate.
This often happens.
Nor can he depend on the government because it will want their two votes against his one.
And the courts will hand down rulings that cannot be enforced.
That's why the core question: How much is it worth to the rich house-owner not to have his whole house stinking and his water supply contaminated?
No easy solutions
This is the question that the Delhi, UP, Punjab, and Haryana governments have to answer.
One way is to pay farmers not to grow paddy.
It's a lot of money for 15 million tonnes of paddy at Rs 36,000 per tonne.
This cost can be met only via a cess or a municipal tax on about 50 million people who live in the NCR.
That means about Rs 10,000 per person per year.
But questions can be asked: If you are going to pay farmers not to grow paddy, why not pay all polluters.
Thus, car owners could be paid not to drive, coal-based power plants paid to shut down, construction companies to stop construction, etc.
So we come back to the temporary cure rather than permanent prevention, namely, target the stubble.
This involves technological solutions, the equivalent of better fuel and better car engines, etc.
Some also suggest that we create a market for the stubble.
But how do you get it out in the first place? Indeed, that's why it is burnt as the cheapest form of disposal.
As you can see, there are no cheap solutions.
Someone will have to bear the cost, which has to be shared by everyone except the polluters.
But the stubble-burning problem is so temporary -- just about a month -- that no one will agree to pay.
Net net: You can't consume clean air if you won't pay for it just because it's a 30-day problem.


First Name
The name field should contain only characters and cannot start with space!
User Name
The username field can contain only alphanumeric characters "A-za-z0-9" and "-_".
Email
Please enter a valid email address!
Password
The password should be at least 8 characters long!
Confirm Password
The password should be at least 8 characters long and passwords must match!
Sign Up


Michael Patel advised by Dr. Fisher
PyCBC is a data analysis pipeline to search for Gravitational Waves within the LIGO/Virgo data.
Uses a process of Matched-Filtering
Identification of a signal using a set of templates.
Inject a known Gravitational Wave signal into our timeseries
Compare signal to first template
Compare signal to second template
Compare signal to third template
Waveforms defined by a set of 63 parameters
Used to find Gravitational Waves and then for Parameter Estimation
Set of Templates that cover a parameter space
Generated automatically by pyCBC given limits on the parameter space
Matched-Filtering done by computational jobs given a Template Bank and set of injections
Returns a Recovered SNR—how well the injected signal was recovered
Once entire Template Bank we can determine its overall sensitivity towards detection
This research will produce a Template Bank for use in the Medium Latency pyGRB analyses


ARRAY
FunctionCreates an array from the specified arguments. Arrays are represented using the SQLite "BLOB" data type. They can be stored in tables and variables and passed as arguments to functions, just like any other value. Large arrays should be avoided for performance reasons. For large amounts of data, consider using a dedicated table.
ARRAY([value], ...)
BLOB
value containing the encoded array.DECLARE @data = ARRAY(111, 222, 333);
PRINT ARRAY_GET(@data, 0); -- "111"
PRINT ARRAY_GET(@data, 2); -- "333"


Andrews scores 20 to lift FIU past Ave Maria 101-59
MIAMI (AP) - Devon Andrews had 20 points as Florida International easily defeated NAIA member Ave Maria 101-59 on Friday night.
Antonio Daye Jr. added 15 points for the Panthers (1-1). Cameron Corcoran and Osasumwen Osaghae both scored 14.
Leo Behrend had 17 points for the Gyrenes. Lucas Uzdavinis added 11 points.
Florida International matches up against North Carolina State on the road on Wednesday.
For more AP college basketball coverage: https://apnews.com/Collegebasketball and http://twitter.com/AP_Top25
This was generated by Automated Insights, http://www.automatedinsights.com/ap, using data from STATS LLC, https://www.stats.com
Sign up for Daily Newsletters
Copyright © 2019 The Washington Times, LLC.
Please read our comment policy before commenting.


Give a Gift!
Complete your skin type profile and set your subscription plan. Once we receive your order we will customize and ship your Pure Box out to you. Sign up and send a gift box to a friend!
What's inside
Each box comes with one hero (large) item along with 3 medium size cosmetics and 4 makeup products. Customers with annual subscriptions receive an additional hero unit each month.
How it Works
Complete your skin type profile and set your subscription plan. Once we receive your order we will customize and ship your Pure Box out to you. Sign up and send a gift box to a friend!
Choose a frequency
Receive your Pure Box!
Monthly surprise
All of our Pure Boxes come with a surprise gift that is not available for sale in store or on our website. Be the first try some of 100% Pure's newest products before they are released to the public!


Menu
The 30th Birthday Cupcake, $2.99
The Vanilla Killa, $3.49
Our best seller, Spaghetti and Meatballs, $12.99
Back to Main


WEDNESDAY AFTER EPIPHANY
(OR 9 JANUARY)
FIRST READING 1 John 4:11-18
A reading from the first Letter of Saint John
Beloved, if God so loved us, we also ought to love
one another. No man has ever seen God; if we love one another, God abides in us
and his love is perfected in us. By this we know that we abide in him and he in us, because he has given us of his own Spirit. And we
have seen and testify that the Father has sent his Son as the Saviour of the
world. Whoever confesses that Jesus is the Son of God, God abides in him, and
he in God. So we know and believe the love God has for us. God is love, and he
who abides in love abides in God, and God abides in him. In this is love
perfected with us, that we may have confidence for the day of judgement,
because as he is so are we in this world. There is no fear in love, but perfect
love casts out fear. For fear has to do with punishment, and he who fears is
not perfected in love.
The word of the Lord
RESPONSORIAL PSALM Psalm 72:1-2.10-11.12-13(R.see 11)
R. All nations on earth shall fall prostrate before you, O Lord.
O God, give your judgment to the king, to a king's son
your justice, that he may judge your people in justice, and your
poor in right judgment.
R. All nations on earth shall fall prostrate before
you, O Lord.
The kings of Tarshish and
the islands shall pay him tribute. The kings of
R. All nations on earth shall fall prostrate before
you, O Lord.
For he shall save the needy when they cry,
the poor, and those who are helpless. He will have pity on the
weak and the needy, and save the lives of the needy.
R. All nations on earth shall fall prostrate before
you, O Lord.
ALLELUIA See 1 Timothy 3:16
Alleluia.  Alleluia.
GOSPEL Mark 6:45-52
A reading from the holy Gospel according to Mark
[After the five thousand men were satisfied,] Jesus
immediately made his disciples get into the boat and go before him to the other
side, to
The Gospel of the Lord


{% extends "credoweb/base.html" %} {% block content %}
Yes, we hide detections from old versions of the app and ones that are too bright because they may be artifacts. We also try to detect "hot pixels" that are generating false positives. However, we still keep all of them and use them while analyzing data for science purposes.
You should contact CREDO Science Coordinator<EMAIL_ADDRESS>and describe why do you want access and what are you going to do with the data.
Remember to include your username and send the message from email address you used during
registration.
Documentation about data export is available on
GitHub.
You can find a collection of tools for exporting and working with data collected by CREDO in this GitHub repository.
If your work is concluded in some written or visual form please do not forget to acknowledge the
CREDO Collaboration properly, e.g. by citing our main publication:
"Cosmic Ray Extremely Distributed Observatory",
P. Homola, et al. (CREDO Collab.), Symmetry 2020, 12(11), 1835, 2020.
[arXiv:2010.08351, DOI:10.3390/sym12111835].


Hey guys, just wanted to share my blissful experience. My parents were out for the whole day, and I thought that it would be a great opportunity to get 'high'.
I was in a fairly good mood that day, I decided to invite my mate over and share a spliff or two. We smoked a joint around 12pm, and I was feeling great. Unfortunately my friend didn't feel so good, and later regurgitated most of his lunch into my basin.  I ripped the cone with ease, and felt the smooth smoke running through my body. I felt great.
My friend left at 3pm.  I was coming down, but I wanted to relax more, so at 3pm I poured myself a glass of Jim Beam. After finishing the glass I felt rather happy. I decided not to drink any more. I find that when I drink after smoking, the effects of the weed is less obvious.
I've always had a liking for diazepam, and I had some left over from a past injury. I popped two 2mg Valiums with water at 3:30pm and sat down at my computer. I was feeling great, and the familiar numbness and peacefulness of diazepam was kicking in. For no good reason (perhaps a suicidal urge?), I decided to take another 4 valiums and two pain killers (20mg codeine).
These 6 tablets were taken at relatively short intervals, 5 minutes between each Valium, and 10 minutes between the pain killers. I was in for quite a ride.
My whole body seemed to assimilate with my computer chair. I attempted to chat with my friend, but my fingers felt as heavy as lead. I didn't want to upset the equiliberum of my body. My mind started wandering and my eyes started to close. I tried to stay awake, because I had to make myself pasta for that night. My typing was absolutely incoherant, it took me multiple attempts to relay any messages. My friend continually told me to 'go to sleep', but I thought that would be boring. What's the point in doing drugs if you concsciously experience it? I decided to turn the computer off and make my way to the couch.
With great effort I walked to the lounge room, turned on the TV and slumped down onto the couch. I have no memory of what I was watching, but the sounds that I heard were comforting. I felt very relaxed and nearly fell asleep. I rolled off the couch, crawled to TV and turned it off. I slid across my cork floor, on my stomache, into the kitchen. I pulled my self up and almost collapsed when I stood up. I made a mental resolution to pull myself together. I managed, anazingly, to make myself pasta and a meat sauce. I ate this, then, in an absolute dreamlike state, made my way to my bedroom. I turned on my amp, started up a GoA Trance CD, and lay down on my bed. The music had new meaning, I felt it pulsating through my body. Then I think I passed out.
The next morning I woke up at 5 am in a slight state of confusion, I couldn't think what day it was, and I had difficulty remembering how I got to my bed. I went back to sleep, woke up at 10 and found myself in more sober state. The Valium was still in effect, but only mildly. I pieced together the last day with little trouble.
That same day I felt fantastic, I hadn't had such peacefull sleep in years, and I was filled with energy. I have never felt so good in all of my memory.
OK, diazepam seems to exaggurate the effects of alcohol greatly. The major effect of the diazepam though, was putting me to sleep. I don't believe that the cannibus had much effect in the long run, but who knows? Cannibus may have added to the experience, but the effect wasn't obvious.
I would reccomend this mix to anyone, but please be carefull about the amounts of the drug that one takes. It can't be stressed enough that drugs affect people in different ways. Please be very carefull.
Also note that these drugs were taking over a long period of time. Time is undoubtably a key factor in the outcome of a trip.
Thanks all, Peace
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


A lot of the places we visited during our port stop at Russell were important historical sites from New Zealand history, and I particularly enjoyed visiting the places we read about in our Maritime History and Culture class.
 To get on land, we used a small boat that could approach the shallower waters
The first day we were at Russell was an open and unstructured day. Russell is a really small town and accommodated tourists off of cruise ships (we saw a cruise ship also anchored nearby). I spent most of the day walking around Russell and visiting the flagstaff which we learned about in class.
During the second day, we took a ferry to Paihia, then walked over to the Waitangi treaty grounds from there. To put things into more context, I’ll share a bit of background as I go through the photos
Much of Maori history is based in stories being passed down generation to generation, which caused problems when modern-day historians documented much of New Zealand’s history - in today’s heavily text and document-based society, people had a hard time accepting oral histories as an equally valid source of truth when compared to history that had old written documents to validate events. As a result, New Zealand’s history has been written from a very colonial point of view, and only recently have there been efforts to try to incorporate the Maori perspective. Part of our goal when studying New Zealand’s history and visiting historic sites was to try to learn as much as we could about both perspectives.
As I mentioned in my post about Auckland, the first people to New Zealand were the Maori people, who are believed to have arrived to New Zealand sometime around 1200. New Zealand was one of the last places to be inhabited by humans, in part because the prevailing trade winds made it difficult to end up in New Zealand by accident. The Maori were expert navigators, and their oral histories tell of navigation by stars, clouds, birds, stick charts and even by taste of the ocean.
It wasn’t until 1642 when Abel Tasman reached New Zealand and became the first European to arrive. However, but his encounter was brief after the sound of his horn was misinterpreted as a war cry by the Maori. Following Tasman’s charts, Cook landed in Paihia Harbour in 1769. His visit was much more successful, and ultimately visited New Zealand on three separate occasions.
At times there was conflict, but the Maori understood how valuable trading was and often traded with the Europeans. As a symbol of peace, Hōne Heke, an influential Maori chief, gifted a flagstaff to James Busby, the first British Resident.
As more Europeans began to come through, some Maori tribes began to feel concerned about things like land use and security with multiple other European countries coming through, and so they signed the Treaty of Waitangi with the British in February 1840.
Two versions of the treaty were made - one written in English, and the other written in Maori. However, the two versions were not completely identical in meaning - in the English version the Maori would cede sovereignty of their land to the Queen, while in the Maori version, they believed they were only agreeing to British governorship. As a result, conflict erupted, especially when the Europeans began taxing the Maori people and putting restrictions on their land use when the land was supposed to belong to the Maori. Tensions between the two groups only escalated when the Europeans moved the capital from Russell to Auckland in 1841.
In rage at the Maori version of the treaty not being upheld, Te Haratua, an ally of Hōne Heke, cut down the flagstaff in 1844. The British put back up the flagstaff and sent troops to guard it, and it was cut down again by Hōne Heke in 1845. A week later, a flagstaff sheathed in iron was erected, and Hōne Heke cut it down a third the next morning. When the flagstaff was put back up, Hōne Heke and his warriors killed all the defenders and cut it down for the fourth and final time. This action marked the start of the Flagstaff War.
Eventually, after lots of conflict, the British finally decided to recognize and uphold the Maori version of the treaty, and there was once again peace. (Comment: I feel like this transition wasn’t explained thoroughly in any of the placards I read, which struck me as odd - how did they get from a place of such high tension to this?). To recognize this peace and welcome visitors, the Maori decided to put back up the flagstaff, where it still stands today.
Other things seen on the treaty grounds
Port stop dates: Feb 21st - 24th, 2020


| ID | Title | Duration (ms) |
|---|---|---|
| 1 | Client constructor throws if no state is given | 11 |
| 2 | Client request the url defaults to the serverUrl | 350 |
| 3 | Client request accepts url string | 545 |
| 4 | Client request accepts options object | 470 |
| 5 | Client request handles OperationOutcome errors | 187 |
| 6 | Client request handles other errors | 47 |
| 7 | Client request rejects invalid access tokens | 183 |
| 8 | Client request tries to use the refresh token on 401 | 253 |
| 9 | Client refresh rejects with no state.tokenResponse | 0 |
| 10 | Client refresh rejects with no state.tokenResponse.refresh_token | 1 |
| 11 | Client refresh deletes invalid refresh tokens | 124 |
| 12 | Client refresh handles other errors | 0 |
| 13 | Client refresh works as expected | 1003 |
| 14 | express adapter getStorage returns null if session is empty | 1 |
| 15 | express adapter getStorage can be set as option | 0 |
| 16 | express adapter getStorage uses session storage by default | 1 |
| 17 | express adapter authorize using options.serverUrl and an open server | 538 |
| 18 | express adapter authorize using options.serverUrl and an protected server | 521 |
| 19 | express adapter authorize using query.serverUrl and an open server | 536 |
| 20 | express adapter authorize using query.serverUrl and an protected server | 495 |
| 21 | express adapter authorize using query.iss and query.launch and an open server | 551 |
| 22 | express adapter authorize using query.iss and query.launch and protected server | 502 |
| 23 | express adapter authorize calls next if not enough arguments | 1 |
| 24 | express adapter completeAuth ends with error and error_description if provided | 1 |
| 25 | express adapter completeAuth handles internal errors | 1 |
| 26 | express adapter completeAuth handles errors | 128 |
| 27 | express adapter completeAuth calls next if not enough arguments provided | 0 |
| 28 | express adapter completeAuth works as expected | 883 |
| 29 | express adapter refreshAuth ends with error message if no client can be constructed | 1 |
| 30 | express adapter refreshAuth handles errors | 0 |
| 31 | hapi adapter getStorage returns null if session is empty | 0 |
| 32 | hapi adapter getStorage can be set as option | 1 |
| 33 | hapi adapter getStorage uses session storage by default | 0 |
| 34 | hapi adapter authorize using options.serverUrl and an open server | 525 |
| 35 | hapi adapter authorize using options.serverUrl and an protected server | 530 |
| 36 | hapi adapter authorize using query.serverUrl and an open server | 571 |
| 37 | hapi adapter authorize using query.serverUrl and an protected server | 578 |
| 38 | hapi adapter authorize using query.iss and query.launch and an open server | 534 |
| 39 | hapi adapter authorize using query.iss and query.launch and protected server | 615 |
| 40 | hapi adapter authorize calls next if not enough arguments | 0 |
| 41 | hapi adapter completeAuth ends with error and error_description if provided | 1 |
| 42 | hapi adapter completeAuth handles internal errors | 1 |
| 43 | hapi adapter completeAuth calls next if not enough arguments provided | 0 |
| 44 | hapi adapter completeAuth works as expected | 978 |
| 45 | hapi adapter refreshAuth ends with error message if no client can be constructed | 1 |
| 46 | hapi adapter refreshAuth handles errors | 1 |
| 47 | lib getPath returns the first arg if no path | 0 |
| 48 | lib getPath returns the first arg for empty path | 0 |
| 49 | lib getPath works as expected | 1 |
| 50 | lib printf works as expected | 1 |
| 51 | lib getErrorText works as expected | 1 |
| 52 | lib HttpError constructor The message defaults to 'Unknown error' | 1 |
| 53 | lib HttpError constructor The httpCode defaults to 500 | 0 |
| 54 | lib HttpError constructor The httpCode can be set | 0 |
| 55 | lib HttpError constructor Variable substitution works | 0 |
| 56 | lib getSecurityExtensions Works without arguments | 3 |
| 57 | lib getSecurityExtensions Works with HSPC | 1228 |
| 58 | lib getSecurityExtensions Works with R3 - Protected | 500 |
| 59 | lib getSecurityExtensions Works with R3 - Open | 697 |
| 60 | lib resolveUrl works as expected | 3 |
| 61 | lib buildAuthorizeUrl Rejects if no serverUrl can be found | 1 |
| 62 | lib buildAuthorizeUrl Works with open servers | 2 |
| 63 | lib buildAuthorizeUrl Works with query.fhirServiceUrl parameter | 2 |
| 64 | lib buildAuthorizeUrl Works with options.serverUrl parameter | 1 |
| 65 | lib buildAuthorizeUrl requires 'launch' param if 'iss' is used | 1 |
| 66 | lib buildAuthorizeUrl clears previous state | 4 |
| 67 | lib buildAuthorizeUrl Works with clientSecret | 2 |
| 68 | lib buildAuthorizeUrl Works with protected servers | 494 |
| 69 | lib buildAuthorizeUrl Works with protected servers standalone | 500 |
| 70 | lib authorize works as expected | 498 |
| 71 | lib buildTokenRequest rejects if no state is found | 1 |
| 72 | lib buildTokenRequest rejects if there is no redirectUri in state | 14 |
| 73 | lib buildTokenRequest rejects if there is no tokenUri in state | 1 |
| 74 | lib buildTokenRequest rejects if there is no clientId in state | 1 |
| 75 | lib buildTokenRequest works as expected | 1 |
| 76 | lib buildTokenRequest works with clientSecret | 1 |
| 77 | lib handleTokenError works as expected | 1 |
| 78 | lib handleTokenError message can be set | 0 |
| 79 | lib handleTokenError catches 'error' property in response payloads | 1 |
| 80 | lib handleTokenError catches 'error_description' property in response payloads | 1 |
| 81 | lib handleTokenError catches errors from string payloads | 0 |
| 82 | lib completeAuth handles errors | 130 |
| 83 | lib completeAuth works as expected | 748 |
| Line | Lint | Hits | Source |
|---|---|---|---|
| 1 | "use strict"; | ||
| 2 | 1 | Object.defineProperty(exports, "__esModule", { value: true }); | |
| 3 | 1 | const axios_1 = require("axios"); | |
| 4 | 1 | const querystring = require("querystring"); | |
| 5 | 1 | const _debug = require("debug"); | |
| 6 | 1 | const lib_1 = require("./lib"); | |
| 7 | 1 | const debug = _debug("smart"); | |
| 8 | /** | ||
| 9 | * A SMART Client instance will simplify some tasks for you. It will authorize | ||
| 10 | * requests automatically, use refresh tokens, handle errors and so on. | ||
| 11 | */ | ||
| 12 | class Client { | ||
| 13 | constructor(state) { | ||
| 14 | // This might happen if the state have been lost (for example the server | ||
| 15 | // was restarted and a memory storage was used). | ||
| 16 | if (!state) { | ||
| 17 | 1 | throw new Error("No state provided to the client"); | |
| 18 | } | ||
| 19 | 23 | this.state = state; | |
| 20 | } | ||
| 21 | /** | ||
| 22 | * Allows you to do the following: | ||
| 23 | * 1. Use relative URLs (treat them as relative to the "serverUrl" option) | ||
| 24 | * 2. Automatically authorize requests with your accessToken (if any) | ||
| 25 | * 3. Automatically re-authorize using the refreshToken (if available) | ||
| 26 | * 4. Automatically parse error operation outcomes and turn them into | ||
| 27 | * JavaScript Error objects with which the resulting promises are rejected | ||
| 28 | * @param {object|string} options URL or axios request options | ||
| 29 | */ | ||
| 30 | async request(options = {}) { | ||
| 31 | if (typeof options == "string") { | ||
| 32 | 6 | options = { url: options }; | |
| 33 | } | ||
| 34 | 9 | options.baseURL = this.state.serverUrl.replace(/\/?$/, "/"); | |
| 35 | 8 | const accessToken = lib_1.getPath(this.state, "tokenResponse.access_token"); | |
| 36 | 8 | if (accessToken) { | |
| 37 | 3 | options.headers = Object.assign({}, options.headers, { Authorization: `Bearer ${accessToken}` }); | |
| 38 | } | ||
| 39 | 8 | return axios_1.default(options).catch(error => { | |
| 40 | // The request was made and the server responded with a | ||
| 41 | // status code that falls out of the range of 2xx | ||
| 42 | if (error.response) { | ||
| 43 | 5 | if (error.response.status == 401) { | |
| 44 | 3 | debug("401 received"); | |
| 45 | 3 | if (lib_1.getPath(this.state, "tokenResponse.refresh_token")) { | |
| 46 | 1 | debug("Refreshing using the refresh token"); | |
| 47 | 1 | return this.refresh().then(() => this.request(options)); | |
| 48 | } | ||
| 49 | } | ||
| 50 | 4 | const resourceType = lib_1.getPath(error, "response.data.resourceType"); | |
| 51 | 4 | const issues = lib_1.getPath(error, "response.data.issue"); | |
| 52 | 4 | const body = error.response.data; | |
| 53 | 4 | if (resourceType == "OperationOutcome" && issues.length) { | |
| 54 | 2 | debug("OperationOutcome error response detected"); | |
| 55 | 2 | const errors = body.issue.map((o) => `${o.severity} ${o.code} ${o.diagnostics}`); | |
| 56 | 2 | throw new Error(errors.join("\n")); | |
| 57 | } | ||
| 58 | 2 | throw error; | |
| 59 | } | ||
| 60 | // The request was made but no response was received | ||
| 61 | // "error.request" is an instance of http.ClientRequest | ||
| 62 | 1 | throw new Error(lib_1.getErrorText("no_fhir_response")); | |
| 63 | }); | ||
| 64 | } | ||
| 65 | /** | ||
| 66 | * Use the refresh token to obtain new access token. | ||
| 67 | * If the refresh token is expired it will be deleted from the state, so | ||
| 68 | * that we don't enter into loops trying to re-authorize. | ||
| 69 | */ | ||
| 70 | async refresh() { | ||
| 71 | if (!this.state.tokenResponse || !this.state.tokenResponse.refresh_token) { | ||
| 72 | 4 | throw new Error("Trying to refresh but there is no refresh token"); | |
| 73 | } | ||
| 74 | 5 | const refreshToken = lib_1.getPath(this.state, "tokenResponse.refresh_token"); | |
| 75 | 5 | return axios_1.default({ | |
| 76 | method: "POST", | ||
| 77 | url: this.state.tokenUri, | ||
| 78 | headers: { | ||
| 79 | "content-type": "application/x-www-form-urlencoded" | ||
| 80 | }, | ||
| 81 | data: querystring.stringify({ | ||
| 82 | grant_type: "refresh_token", | ||
| 83 | refresh_token: refreshToken | ||
| 84 | }) | ||
| 85 | }).then(({ data }) => { | ||
| 86 | this.state.tokenResponse = Object.assign({}, this.state.tokenResponse, data); | ||
| 87 | 3 | return data; | |
| 88 | }) | ||
| 89 | .catch(error => { | ||
| 90 | if (error.response && error.response.status == 401) { | ||
| 91 | 1 | debug("401 received - refresh token expired or invalid"); | |
| 92 | 1 | debug("Deleting the expired or invalid refresh token"); | |
| 93 | 1 | delete this.state.tokenResponse.refresh_token; | |
| 94 | } | ||
| 95 | 2 | throw error; | |
| 96 | }); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | 1 | exports.default = Client; | |
| 100 |
| Line | Lint | Hits | Source |
|---|---|---|---|
| 1 | "use strict"; | ||
| 2 | 1 | Object.defineProperty(exports, "__esModule", { value: true }); | |
| 3 | 1 | exports.default = { | |
| 4 | "": "Unknown error", | ||
| 5 | unknown_error: "Unknown error", | ||
| 6 | missing_url_parameter: `Missing url parameter "%s"`, | ||
| 7 | missing_state_by_id: `No state found using the given id: "%s".`, | ||
| 8 | missing_state_redirectUri: "Missing state.redirectUri", | ||
| 9 | missing_state_tokenUri: "Missing state.tokenUri", | ||
| 10 | missing_state_clientId: "Missing state.clientId", | ||
| 11 | no_fhir_response: "No response received from the FHIR server", | ||
| 12 | no_server_url_provided: "Cannot detect which FHIR server to launch against. " + | ||
| 13 | "For EHR launch call your endpoint with 'launch' " + | ||
| 14 | "and 'iss' parameters. For standalone launch pass " + | ||
| 15 | "'fhirServiceUrl' parameter or set it as 'serverUrl'" + | ||
| 16 | "in your configuration." | ||
| 17 | }; | ||
| 18 |
| Line | Lint | Hits | Source |
|---|---|---|---|
| 1 | 1 | const smart = require("./lib"); | |
| 2 | |||
| 3 | |||
| 4 | 1 | module.exports = function(options) { | |
| 5 | const cfg = { getStorage: smart.getSessionStorage, ...options }; | ||
| 6 | |||
| 7 | // Return the Express-specific high-level API | ||
| 8 | 17 | return { | |
| 9 | |||
| 10 | /** | ||
| 11 | * Given a request object this function will return a Promise that will | ||
| 12 | * eventually be resolved with a Fhir Client object or with `null` if | ||
| 13 | * there is a problem. It will lookup the storage for stored SMART state. | ||
| 14 | * If such state is found, it will create and return a Fhir Client | ||
| 15 | * instance that knows how to use that (automatically authorize any | ||
| 16 | * requests made with `client.request`, use clientSecret and refresh | ||
| 17 | * tokens etc.). | ||
| 18 | * @param {Object} request | ||
| 19 | * @returns {Promise<Client|null>} | ||
| 20 | */ | ||
| 21 | async getClient(request) { | ||
| 22 | const storage = cfg.getStorage(request); | ||
| 23 | 7 | const id = await storage.get("smartId"); | |
| 24 | 7 | if (id) { | |
| 25 | 5 | const state = await storage.get(id); | |
| 26 | 5 | if (state) { | |
| 27 | 4 | return new smart.Client(state); | |
| 28 | } | ||
| 29 | } | ||
| 30 | 3 | return null; | |
| 31 | }, | ||
| 32 | |||
| 33 | /** | ||
| 34 | * If the fhir server base can be determined (from query.iss or | ||
| 35 | * query.fhirServiceUrl or options.serverUrl), then the user will be | ||
| 36 | * redirected to the authorization endpoint (or to your redirectUri if | ||
| 37 | * it happens to be an open server). Otherwise, the `next` callback | ||
| 38 | * will be called. | ||
| 39 | * @param {Object} req | ||
| 40 | * @param {Object} res | ||
| 41 | * @param {Function} next | ||
| 42 | */ | ||
| 43 | authorize(req, res, next) { | ||
| 44 | let { launch, iss, fhirServiceUrl } = req.query; | ||
| 45 | 8 | if ((launch && iss) || fhirServiceUrl || cfg.serverUrl) { | |
| 46 | 7 | return smart.authorize(req, res, cfg, cfg.getStorage(req)); | |
| 47 | } | ||
| 48 | 1 | next(); | |
| 49 | }, | ||
| 50 | |||
| 51 | /** | ||
| 52 | * The `authorize` function above will redirect the browser to the | ||
| 53 | * authorization endpoint of the SMART server. Depending on the requested | ||
| 54 | * scopes, the user might be asked to select a patient or practitioner, | ||
| 55 | * authorize the app and so on. Eventually, the user will be redirected | ||
| 56 | * back to your site at your `options.redirectUri`. At that point you | ||
| 57 | * should have received a code that needs to be exchanged for an access | ||
| 58 | * token. | ||
| 59 | * @param {Object} req | ||
| 60 | * @param {Object} res | ||
| 61 | * @param {Function} next | ||
| 62 | */ | ||
| 63 | completeAuth(req, res, next) { | ||
| 64 | let { code, state, error, error_description } = req.query; | ||
| 65 | 6 | if (error) { | |
| 66 | 2 | let msg = error + (error_description ? ":\n" + error_description : ""); | |
| 67 | 2 | return res.end(msg); | |
| 68 | } | ||
| 69 | 4 | if (code && state) { | |
| 70 | 3 | return smart.completeAuth(req, cfg.getStorage(req)) | |
| 71 | .then( | ||
| 72 | () => res.redirect(cfg.redirectUri), | ||
| 73 | e => { | ||
| 74 | res.writeHead(e.httpCode || 500, { 'Content-Type': 'text/plain' }); | ||
| 75 | 2 | res.end(e.message, "utf8"); | |
| 76 | } | ||
| 77 | ); | ||
| 78 | } | ||
| 79 | 1 | next(); | |
| 80 | }, | ||
| 81 | |||
| 82 | /** | ||
| 83 | * You don't typically need to use this because if you have a refresh | ||
| 84 | * token (which you should if your scope includes `offline_access`), | ||
| 85 | * then the request method will automatically use it when your access | ||
| 86 | * token expires. | ||
| 87 | * @param {Object} req | ||
| 88 | * @param {Object} res | ||
| 89 | * @param {Function} next | ||
| 90 | */ | ||
| 91 | async refreshAuth(req, res, next) { | ||
| 92 | const client = await this.getClient(req); | ||
| 93 | |||
| 94 | // Perhaps the server was restarted or lost it's session for some other reason | ||
| 95 | 3 | if (!client) { | |
| 96 | 1 | return res.end("No smart state found in session. Please re-authorize your app.") | |
| 97 | } | ||
| 98 | |||
| 99 | 2 | return client.refresh().then(() => next(), error => res.end(error.message)); | |
| 100 | } | ||
| 101 | } | ||
| 102 | }; | ||
| 103 |
| Line | Lint | Hits | Source |
|---|---|---|---|
| 1 | 1 | const smart = require("./lib"); | |
| 2 | |||
| 3 | |||
| 4 | 1 | module.exports = function(options) { | |
| 5 | const cfg = { getStorage: smart.getSessionStorage, ...options }; | ||
| 6 | |||
| 7 | // Return the HAPI-specific high-level API | ||
| 8 | 16 | return { | |
| 9 | |||
| 10 | /** | ||
| 11 | * Given a request object this function will return a Promise that will | ||
| 12 | * eventually be resolved with a Fhir Client object or with `null` if | ||
| 13 | * there is a problem. It will lookup the storage for stored SMART state. | ||
| 14 | * If such state is found, it will create and return a Fhir Client | ||
| 15 | * instance that knows how to use that (automatically authorize any | ||
| 16 | * requests made with `client.request`, use clientSecret and refresh | ||
| 17 | * tokens etc.). | ||
| 18 | * @param {Object} request | ||
| 19 | * @returns {Promise<Client|null>} | ||
| 20 | */ | ||
| 21 | async getClient(request) { | ||
| 22 | const storage = cfg.getStorage(request); | ||
| 23 | 7 | const id = await storage.get("smartId"); | |
| 24 | 7 | if (id) { | |
| 25 | 5 | const state = await storage.get(id); | |
| 26 | 5 | if (state) { | |
| 27 | 4 | return new smart.Client(state); | |
| 28 | } | ||
| 29 | } | ||
| 30 | 3 | return null; | |
| 31 | }, | ||
| 32 | |||
| 33 | /** | ||
| 34 | * If the fhir server base can be determined (from query.iss or | ||
| 35 | * query.fhirServiceUrl or options.serverUrl), then the user will be | ||
| 36 | * redirected to the authorization endpoint (or to your redirectUri if | ||
| 37 | * it happens to be an open server). Otherwise, the `next` callback | ||
| 38 | * will be called. | ||
| 39 | * @param {Object} req | ||
| 40 | * @param {Object} h | ||
| 41 | * @returns {Promise<any>|Symbol} | ||
| 42 | */ | ||
| 43 | authorize(req, h) { | ||
| 44 | let { launch, iss, fhirServiceUrl } = req.query; | ||
| 45 | 8 | if ((launch && iss) || fhirServiceUrl || cfg.serverUrl) { | |
| 46 | 7 | return smart.buildAuthorizeUrl(req.raw.req, cfg, cfg.getStorage(req)) | |
| 47 | .then(url => h.redirect(url)); | ||
| 48 | } | ||
| 49 | 1 | return h.continue; | |
| 50 | }, | ||
| 51 | |||
| 52 | /** | ||
| 53 | * The `authorize` function above will redirect the browser to the | ||
| 54 | * authorization endpoint of the SMART server. Depending on the requested | ||
| 55 | * scopes, the user might be asked to select a patient or practitioner, | ||
| 56 | * authorize the app and so on. Eventually, the user will be redirected | ||
| 57 | * back to your site at your `options.redirectUri`. At that point you | ||
| 58 | * should have received a code that needs to be exchanged for an access | ||
| 59 | * token. | ||
| 60 | * @param {Object} req | ||
| 61 | * @param {Object} h | ||
| 62 | * @returns {Promise<any>|Symbol} | ||
| 63 | */ | ||
| 64 | completeAuth(req, h) { | ||
| 65 | let { code, state, error, error_description } = req.query; | ||
| 66 | 5 | if (error) { | |
| 67 | 2 | throw new Error(error + (error_description ? ":\n" + error_description : "")); | |
| 68 | } | ||
| 69 | 3 | if (code && state) { | |
| 70 | 2 | return smart.completeAuth(req.raw.req, cfg.getStorage(req)) | |
| 71 | .then(() => h.redirect(cfg.redirectUri)); | ||
| 72 | } | ||
| 73 | 1 | return h.continue; | |
| 74 | }, | ||
| 75 | |||
| 76 | /** | ||
| 77 | * You don't typically need to use this because if you have a refresh | ||
| 78 | * token (which you should if your scope includes `offline_access`), | ||
| 79 | * then the request method will automatically use it when your access | ||
| 80 | * token expires. | ||
| 81 | * @param {Object} request | ||
| 82 | * @param {Object} h | ||
| 83 | */ | ||
| 84 | async refreshAuth(request, h) { | ||
| 85 | const client = await this.getClient(request); | ||
| 86 | |||
| 87 | // Perhaps the server was restarted or lost it's session for some other reason | ||
| 88 | 3 | if (!client) { | |
| 89 | 1 | throw new Error("No smart state found in session. Please re-authorize your app."); | |
| 90 | } | ||
| 91 | |||
| 92 | 2 | return client.refresh().then(() => h.continue, error => { throw error }); | |
| 93 | } | ||
| 94 | }; | ||
| 95 | } | ||
| 96 | |||
| 97 |
| Line | Lint | Hits | Source |
|---|---|---|---|
| 1 | "use strict"; | ||
| 2 | 1 | Object.defineProperty(exports, "__esModule", { value: true }); | |
| 3 | 1 | const axios_1 = require("axios"); | |
| 4 | 1 | const Crypto = require("crypto"); | |
| 5 | 1 | const Url = require("url"); | |
| 6 | 1 | const qs = require("querystring"); | |
| 7 | 1 | const _debug = require("debug"); | |
| 8 | 1 | const errors_1 = require("./errors"); | |
| 9 | 1 | const client_1 = require("./client"); | |
| 10 | 1 | exports.Client = client_1.default; | |
| 11 | 1 | const debug = _debug("smart"); | |
| 12 | /** | ||
| 13 | * Walks thru an object (or array) and returns the value found at the | ||
| 14 | * provided path. This function is very simple so it intentionally does not | ||
| 15 | * support any argument polymorphism, meaning that the path can only be a | ||
| 16 | * dot-separated string. If the path is invalid returns undefined. | ||
| 17 | * @param {Object} obj The object (or Array) to walk through | ||
| 18 | * @param {String} path The path (eg. "a.b.4.c") | ||
| 19 | * @returns {*} Whatever is found in the path or undefined | ||
| 20 | */ | ||
| 21 | function getPath(obj, path = "") { | ||
| 22 | 63 | path = path.trim(); | |
| 23 | 63 | if (!path) { | |
| 24 | 2 | return obj; | |
| 25 | } | ||
| 26 | 61 | return path.split(".").reduce((out, key) => out ? out[key] : undefined, obj); | |
| 27 | } | ||
| 28 | 1 | exports.getPath = getPath; | |
| 29 | /** | ||
| 30 | * Simplified version of printf. Just replaces all the occurrences of "%s" with | ||
| 31 | * whatever is supplied in the rest of the arguments. If no argument is supplied | ||
| 32 | * the "%s" token is replaced with an empty string. | ||
| 33 | * @param {String} s The string to format | ||
| 34 | * @param {*} ... The rest of the arguments are used for the replacements | ||
| 35 | * @return {String} | ||
| 36 | */ | ||
| 37 | function printf(s, ...args) { | ||
| 38 | 27 | const l = args.length; | |
| 39 | 27 | let i = 0; | |
| 40 | 27 | return String(s || "").replace(/(%s)/g, () => i >= l ? "" : args[i++]); | |
| 41 | } | ||
| 42 | 1 | exports.printf = printf; | |
| 43 | /** | ||
| 44 | * Returns the error message for the given error name, replacing any "%s" | ||
| 45 | * occurrences with the rest of the given arguments | ||
| 46 | * @param name The error name | ||
| 47 | * @param rest Any other arguments passed to printf | ||
| 48 | */ | ||
| 49 | function getErrorText(name = "", ...rest) { | ||
| 50 | 22 | return printf(errors_1.default[name], ...rest); | |
| 51 | } | ||
| 52 | 1 | exports.getErrorText = getErrorText; | |
| 53 | /** | ||
| 54 | * For custom error objects that also have an httpCode property | ||
| 55 | */ | ||
| 56 | class HttpError extends Error { | ||
| 57 | constructor(name = "", httpCode = 500, ...params) { | ||
| 58 | super(getErrorText(name, ...params) || name); | ||
| 59 | 15 | this.httpCode = httpCode; | |
| 60 | } | ||
| 61 | } | ||
| 62 | 1 | exports.HttpError = HttpError; | |
| 63 | /** | ||
| 64 | * Given a fhir server returns an object with it's Oauth security endpoints | ||
| 65 | * @param baseUrl Fhir server base URL | ||
| 66 | */ | ||
| 67 | async function getSecurityExtensions(baseUrl) { | ||
| 68 | 28 | const url = String(baseUrl || "").replace(/\/*$/, "/") + "metadata"; | |
| 69 | 28 | let metadata; | |
| 70 | 28 | try { | |
| 71 | 28 | metadata = await axios_1.default(url); | |
| 72 | } | ||
| 73 | catch (ex) { | ||
| 74 | 6 | metadata = {}; | |
| 75 | } | ||
| 76 | 28 | const nsUri = "http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris"; | |
| 77 | 28 | const extensions = (getPath(metadata, "data.rest.0.security.extension") || []) | |
| 78 | .filter((e) => e.url === nsUri) | ||
| 79 | .map((o) => o.extension)[0]; | ||
| 80 | 28 | const out = { | |
| 81 | registrationUri: "", | ||
| 82 | authorizeUri: "", | ||
| 83 | tokenUri: "" | ||
| 84 | }; | ||
| 85 | 28 | if (extensions) { | |
| 86 | 15 | extensions.forEach((ext) => { | |
| 87 | if (ext.url === "register") { | ||
| 88 | 1 | out.registrationUri = ext.valueUri; | |
| 89 | } | ||
| 90 | 31 | if (ext.url === "authorize") { | |
| 91 | 15 | out.authorizeUri = ext.valueUri; | |
| 92 | } | ||
| 93 | 31 | if (ext.url === "token") { | |
| 94 | 15 | out.tokenUri = ext.valueUri; | |
| 95 | } | ||
| 96 | }); | ||
| 97 | } | ||
| 98 | 28 | return out; | |
| 99 | } | ||
| 100 | 1 | exports.getSecurityExtensions = getSecurityExtensions; | |
| 101 | /** | ||
| 102 | * Converts the given relative URL to absolute based on the request origin | ||
| 103 | * @param req The http request object | ||
| 104 | * @param url The url to convert | ||
| 105 | */ | ||
| 106 | function resolveUrl(req, url) { | ||
| 107 | 48 | const protocol = req.connection.encrypted ? "https" : "http"; | |
| 108 | 48 | return Url.resolve(protocol + "://" + req.headers.host, url); | |
| 109 | } | ||
| 110 | 1 | exports.resolveUrl = resolveUrl; | |
| 111 | /** | ||
| 112 | * First discovers the fhir server base URL from query.iis or query.fhirServiceUrl | ||
| 113 | * or options.serverUrl. Then compiles the proper authorization URL for that server. | ||
| 114 | * For open server that URL is the options.redirectUri so that we can skip the | ||
| 115 | * authorization part. | ||
| 116 | */ | ||
| 117 | async function buildAuthorizeUrl(req, options, storage) { | ||
| 118 | 26 | const url = Url.parse(req.url, true); | |
| 119 | 26 | const { launch, iss, fhirServiceUrl } = url.query; | |
| 120 | 26 | const serverUrl = iss || fhirServiceUrl || options.serverUrl || ""; | |
| 121 | 26 | if (iss && !launch) { | |
| 122 | 1 | throw new Error(getErrorText("missing_url_parameter", "launch")); | |
| 123 | } | ||
| 124 | 25 | if (!serverUrl) { | |
| 125 | 1 | debug("No serverUrl found. It must be specified as query.iss or " + | |
| 126 | "query.fhirServiceUrl or options.serverUrl (in that order)"); | ||
| 127 | 1 | throw new Error(getErrorText("no_server_url_provided")); | |
| 128 | } | ||
| 129 | 24 | debug(`Looking up the authorization endpoint for "${serverUrl}"`); | |
| 130 | 24 | const extensions = await getSecurityExtensions(serverUrl); | |
| 131 | 24 | debug(`Found security extensions: `, extensions); | |
| 132 | // Prepare the object that will be stored in the session | ||
| 133 | 24 | const state = Object.assign({ serverUrl: serverUrl, clientId: options.clientId, redirectUri: resolveUrl(req, options.redirectUri), scope: options.scope || "" }, extensions); | |
| 134 | 24 | if (options.clientSecret) { | |
| 135 | 1 | debug(`Adding clientSecret to the state`); | |
| 136 | 1 | state.clientSecret = options.clientSecret; | |
| 137 | } | ||
| 138 | // Create an unique key. We could use the session ID for that but we | ||
| 139 | // don't want it to be visible in the browser URL bar (as the state | ||
| 140 | // parameter) while redirecting. | ||
| 141 | 24 | const id = "smart-" + Crypto.randomBytes(8).toString("hex"); | |
| 142 | 24 | const oldId = await storage.get("smartId"); | |
| 143 | 24 | if (oldId) { | |
| 144 | 15 | debug(`Deleting previous state by id ("${oldId}")`); | |
| 145 | 15 | await storage.unset(oldId); | |
| 146 | } | ||
| 147 | 24 | debug(`Saving new state by id ("${id}")`); | |
| 148 | 24 | await storage.set(id, state); | |
| 149 | 24 | await storage.set("smartId", id); | |
| 150 | 24 | let redirectUrl = state.redirectUri; | |
| 151 | 24 | if (state.authorizeUri) { | |
| 152 | 13 | debug(`authorizeUri: ${state.authorizeUri}`); | |
| 153 | 13 | const params = [ | |
| 154 | "response_type=code", | ||
| 155 | "client_id=" + encodeURIComponent(state.clientId), | ||
| 156 | "scope=" + encodeURIComponent(state.scope), | ||
| 157 | "redirect_uri=" + encodeURIComponent(state.redirectUri), | ||
| 158 | "aud=" + encodeURIComponent(state.serverUrl), | ||
| 159 | "state=" + id | ||
| 160 | ]; | ||
| 161 | // also pass this in case of EHR launch | ||
| 162 | 13 | if (launch) { | |
| 163 | 6 | params.push("launch=" + encodeURIComponent(launch)); | |
| 164 | } | ||
| 165 | 13 | redirectUrl = state.authorizeUri + "?" + params.join("&"); | |
| 166 | } | ||
| 167 | 24 | debug(`Making authorize redirect to ${redirectUrl}`); | |
| 168 | 24 | return redirectUrl; | |
| 169 | } | ||
| 170 | 1 | exports.buildAuthorizeUrl = buildAuthorizeUrl; | |
| 171 | /** | ||
| 172 | * Calls the buildAuthorizeUrl function to construct the redirect URL and then | ||
| 173 | * just redirects to it. | ||
| 174 | */ | ||
| 175 | async function authorize(req, res, options, storage) { | ||
| 176 | 8 | debug(`Authorizing...`); | |
| 177 | 8 | const location = await buildAuthorizeUrl(req, options, storage); | |
| 178 | 8 | debug(`Making authorize redirect to ${location}`); | |
| 179 | 8 | res.writeHead(302, { location }); | |
| 180 | 8 | res.end(); | |
| 181 | } | ||
| 182 | 1 | exports.authorize = authorize; | |
| 183 | /** | ||
| 184 | * Builds the token request options for axios. Does not make the request, just | ||
| 185 | * creates it's configuration and returns it in a Promise. | ||
| 186 | * NOTE that this function has side effects because it modifies the storage | ||
| 187 | * contents. | ||
| 188 | * @param req | ||
| 189 | * @param storage | ||
| 190 | */ | ||
| 191 | async function buildTokenRequest(req, storage) { | ||
| 192 | 12 | const { state, code } = Url.parse(req.url, true).query; | |
| 193 | 12 | const cached = await storage.get(state); | |
| 194 | // First make sure we have such state and it contains everything we need | ||
| 195 | 12 | if (!cached) { | |
| 196 | 1 | debug(`No state found by the given id (${state})`); | |
| 197 | 1 | throw new HttpError("missing_state_by_id", 400, state); | |
| 198 | } | ||
| 199 | 11 | if (!cached.redirectUri) { | |
| 200 | 1 | debug(`Missing state.redirectUri`); | |
| 201 | 1 | throw new HttpError("missing_state_redirectUri", 400); | |
| 202 | } | ||
| 203 | 10 | if (!cached.tokenUri) { | |
| 204 | 1 | debug(`Missing state.tokenUri`); | |
| 205 | 1 | throw new HttpError("missing_state_tokenUri", 400); | |
| 206 | } | ||
| 207 | 9 | if (!cached.clientId) { | |
| 208 | 1 | debug(`Missing state.clientId`); | |
| 209 | 1 | throw new HttpError("missing_state_clientId", 400); | |
| 210 | } | ||
| 211 | 8 | const requestOptions = { | |
| 212 | method: "POST", | ||
| 213 | url: cached.tokenUri, | ||
| 214 | headers: { | ||
| 215 | "content-type": "application/x-www-form-urlencoded" | ||
| 216 | }, | ||
| 217 | data: { | ||
| 218 | code, | ||
| 219 | grant_type: "authorization_code", | ||
| 220 | redirect_uri: cached.redirectUri | ||
| 221 | } | ||
| 222 | }; | ||
| 223 | // For public apps, authentication is not possible (and thus not | ||
| 224 | // required), since the app cannot be trusted to protect a secret. | ||
| 225 | // For confidential apps, an Authorization header using HTTP Basic | ||
| 226 | // authentication is required, where the username is the app’s client_id | ||
| 227 | // and the password is the app’s client_secret | ||
| 228 | 8 | if (cached.clientSecret) { | |
| 229 | 1 | requestOptions.headers.Authorization = "Basic " + Buffer.from(cached.clientId + ":" + cached.clientSecret).toString("base64"); | |
| 230 | 1 | debug(`Using state.clientSecret to construct the authorization header: "${requestOptions.headers.Authorization}"`); | |
| 231 | } | ||
| 232 | else { | ||
| 233 | 7 | debug(`No clientSecret found in state. Adding client_id to the POST body`); | |
| 234 | 7 | requestOptions.data.client_id = cached.clientId; | |
| 235 | } | ||
| 236 | 8 | return requestOptions; | |
| 237 | } | ||
| 238 | 1 | exports.buildTokenRequest = buildTokenRequest; | |
| 239 | /** | ||
| 240 | * Creates and returns an HttpError that should explain why the token request | ||
| 241 | * have failed | ||
| 242 | */ | ||
| 243 | function handleTokenError(result) { | ||
| 244 | 7 | let msg = result.message; | |
| 245 | // Some auth servers will respond with a payload that contains "error" and | ||
| 246 | // optionally an "error_description" properties | ||
| 247 | 7 | const body = getPath(result, "response.data"); | |
| 248 | 7 | if (body) { | |
| 249 | 5 | if (body.error) { | |
| 250 | 2 | msg += "\n" + body.error; | |
| 251 | 2 | if (body.error_description) { | |
| 252 | 1 | msg += ": " + body.error_description; | |
| 253 | } | ||
| 254 | } | ||
| 255 | else { | ||
| 256 | 3 | msg += "\n" + body; | |
| 257 | } | ||
| 258 | } | ||
| 259 | 7 | debug(msg + " - " + result.stack); | |
| 260 | 7 | return new HttpError(msg, result.status); | |
| 261 | } | ||
| 262 | 1 | exports.handleTokenError = handleTokenError; | |
| 263 | /** | ||
| 264 | * After successful authorization we have received a code and state parameters. | ||
| 265 | * Use this function to exchange that code for an access token and complete the | ||
| 266 | * authorization flow. | ||
| 267 | */ | ||
| 268 | async function completeAuth(req, storage) { | ||
| 269 | 7 | debug("Completing the code flow"); | |
| 270 | 7 | const { state } = Url.parse(req.url, true).query; | |
| 271 | 6 | const cached = await storage.get(state); | |
| 272 | 6 | const requestOptions = await buildTokenRequest(req, storage); | |
| 273 | 6 | requestOptions.data = qs.stringify(requestOptions.data); | |
| 274 | // The EHR authorization server SHALL return a JSON structure that | ||
| 275 | // includes an access token or a message indicating that the | ||
| 276 | // authorization request has been denied. | ||
| 277 | 6 | return axios_1.default(requestOptions) | |
| 278 | .then(async ({ data }) => { | ||
| 279 | debug(`Received tokenResponse. Saving it to the state...`); | ||
| 280 | 4 | cached.tokenResponse = data; | |
| 281 | 4 | return storage.set(state, cached); | |
| 282 | }) | ||
| 283 | .then(() => new client_1.default(cached)) | ||
| 284 | .catch(result => { | ||
| 285 | throw handleTokenError(result); | ||
| 286 | }); | ||
| 287 | } | ||
| 288 | 1 | exports.completeAuth = completeAuth; | |
| 289 | /** | ||
| 290 | * The default storage factory assumes that the request object has a session | ||
| 291 | * property which is an object that we are free to manipulate. This happens to | ||
| 292 | * be the case for Express using `express-session` and for Hapi using | ||
| 293 | * hapi-server-session`. | ||
| 294 | */ | ||
| 295 | function getSessionStorage(req) { | ||
| 296 | 30 | return { | |
| 297 | /** | ||
| 298 | * Sets (adds or updates) a value at the given key | ||
| 299 | * @param {String} key | ||
| 300 | * @param {any} value | ||
| 301 | * @returns {Promise<any>} A promise resolved with the stored value | ||
| 302 | */ | ||
| 303 | async set(key, value) { | ||
| 304 | req.session[key] = value; | ||
| 305 | 30 | return value; | |
| 306 | }, | ||
| 307 | /** | ||
| 308 | * Reads the value at the given key | ||
| 309 | * @param {String} key | ||
| 310 | * @returns {Promise<any>} A promise resolved with the stored value or undefined | ||
| 311 | */ | ||
| 312 | async get(key) { | ||
| 313 | return req.session[key]; | ||
| 314 | }, | ||
| 315 | /** | ||
| 316 | * Deletes the value at the given key (if one exists) | ||
| 317 | * @param {String} key | ||
| 318 | * @returns {Promise<Boolean>} A promise resolved with true if the value | ||
| 319 | * was removed or with false otherwise | ||
| 320 | */ | ||
| 321 | async unset(key) { | ||
| 322 | if (req.session.hasOwnProperty(key)) { | ||
| 323 | 12 | delete req.session[key]; | |
| 324 | 12 | return true; | |
| 325 | } | ||
| 326 | 2 | return false; | |
| 327 | } | ||
| 328 | }; | ||
| 329 | } | ||
| 330 | 1 | exports.getSessionStorage = getSessionStorage; | |
| 331 |


---
layout: post
title: Syntax highlighting in "Learning CFEngine 3"
permalink: /syntax-highlighting-in-learning-cfengine-3
date: 2012-03-16 17:16:44.000000000 -06:00
comments: true
categories:
- booknews
published: true
---
The electronic versions of the book contain full syntax highlighting and other useful features. I'm biased of course, but I think it is both functional and beautiful. Here's a sample from Chapter 4:
The syntax highlighting in my opinion greatly helps in reading the code. Additionally, each one of those numbered callouts in the code are in-document links that take you to the paragraph where that part of the code is described. Conversely, the callouts in the text take you back to the corresponding line in the code. And finally, most CFEngine keywords and concepts are links to the corresponding description in the CFEngine Reference Manual. In the PDF, clicking on that blue "files:" in the last paragraph will take you to
http://cf-learn.info/ref/files


I am a software developer located in Indianapolis Indiana.
Software Engineer - Brackets For Good Dates volunteeredSep 2017 – Present I work on any tickets I can and try to continuously push more features and fixes. While I get to contribute to an awesome organization, I am getting a ton of exposure to new things I can use and learn more about later. I recommend this to anyone that could afford a few hours a week.
Youth Hackathon Mentor - Got to hang out with a bunch of really awesome people and assist with getting people setup and answer any questions I could help with for both the Java group as well as the Scratch group. We also were asked to keep our eyes out for individuals that showed a strong drive to help their peers through the problems.


WITNESS LIST Public Safety Committee February 24, 1997-4:00P HB 797 For: Clift Price, M.D. (TX Pediatric Society) Hon. Bruce Todd (Mayor, City of Austin) Hon. Elliot Naishtat (Co-Author HB 797) John Sampson (Himself) Joseph H. Jackson, Jr. (Himself) Judy Padgett (Herself) Kim Davies (Dallas Area Safe Kids) Larry C. Driver, M.D. (TMA Foundation) Larry Swift (TX Brain Injury Assoc.) Linsey Oates (Herself) Robin Worthington (Tarrant Co. Safe Kids) Ronald M. Stewart, M.D. (Himself) Sam Sanchez (S.A. Metro Health Dist.) Sandy Silver (Herself) Shelby Oates Maddox (Herself) Susan M. Douglass (Emergency Nurses Assoc.) Against: Daniel Goldman,M.D, MPH (Himself) H.W. "Sputnik" Strain (TMRA) James Damon ("Bikes Not Bombs" of TX) Nick De La Cruz (TMRA) On: David Zane (TX Dept. of Health) Jack McGehee (TX Trial Lawyers Assn.) Johnny Humphreys (TX Dept. of Health) Shirley Ogletree,Ph. D. (Herself) Theresa Gross (DPS) Registering, but not testifying: For: Bill Lewis (MADD) Ed Berger (Seton Healthcare Netwrk) Harold Freeman (TX Medical Assoc.) Nancy Engman Holman (TEXNS Care for Children) Peggy Black (Herself) Robert K. Feather (Cook Children's Med Ctr) Robyn A. Shapiro (TX Osteopathic Medical) Against: A. Brownsword (TMRA) HB 1251 For: Kay Thurman (Herself) Meyer Kaplan, M.D. (Himself) Morris E. Futch (Himself) Registering, but not testifying: On: Pauline Denson (TX Dept. of Lic. & Reg.)


Transformation Wizard Avant-Garde:
This is not a path for every one. It is meaningless for me to even teach you Transformation until you have proven your ability.
Meet the great wizard who uses black magic, open the road of Transformation, and then return to me.


You wake up in a dimly lit room
There are two doors
Do you pick:
You open the door
You see giant tenticles reaching out to grab you!
The giant octopus pulls you into the toxic liquid
There is another door in this room guarded by zombies
Do you:
There is room with a door that is locked, and requires a code
It says: "Hello, "
"Guess a number between 1 and ten. You have tries"
There are two doors:
Behind the first one is a lion that hasn't eaten in months
Behind the second one is a venomous snake
Do you pick:
A wild Zach Fedor appears!
He says: "Hello . Convert the number 7 to binary."

How many will you take? (Hint: don't take more than you can handle.
You are very hungry.
The cost of food is one gold bar.
Will you:
Good job, you won!


Takalane Sesame - A South African NLP experiment
January 1, 2021
Takalane Sesame is a project that aims to promote the use of African languages in NLP, and in particular look at techniques for low-resource languages to equalise performance with larger languages around the world.