Browse Source

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	utils/renderBlogPost.js
pull/22/head
jrtechs 6 years ago
parent
commit
dff09ae4bb
26 changed files with 502 additions and 231 deletions
  1. +3
    -0
      README.md
  2. +1
    -1
      admin.js
  3. +1
    -0
      admin/admin.js
  4. +1
    -1
      admin/category/addCategory.js
  5. +1
    -1
      admin/downloads/manageDownloads.js
  6. +4
    -2
      admin/login/login.js
  7. +1
    -1
      admin/posts/newPost.js
  8. BIN
      blogContent/headerImages/ConstantTimeComplexity.png
  9. +12
    -12
      blogContent/posts/java/gremlin-in-10-minutes.md
  10. +8
    -8
      blogContent/posts/java/top-three-recommended-java-ides.md
  11. +9
    -10
      blogContent/posts/other/why-do-i-blog.md
  12. +16
    -16
      blogContent/posts/programming/c-to-c++-tutorial.md
  13. +395
    -0
      blogContent/posts/programming/everything-fibonacci.md
  14. BIN
      blogContent/posts/programming/media/fibonacci/ConstantTimeComplexity.png
  15. BIN
      blogContent/posts/programming/media/fibonacci/FibPower.png
  16. BIN
      blogContent/posts/programming/media/fibonacci/FibPowerBigPicture.png
  17. BIN
      blogContent/posts/programming/media/fibonacci/Iterative.png
  18. BIN
      blogContent/posts/programming/media/fibonacci/RecursiveDefinition.png
  19. +7
    -7
      blogContent/posts/projects/steam-friends-graph.md
  20. +5
    -8
      blogContent/posts/web-development/history-of-jrtechs.md
  21. +23
    -23
      blogContent/posts/web-development/node-website-optimization.md
  22. +2
    -0
      includes/html/contact.html
  23. +5
    -0
      includes/html/header.html
  24. +1
    -1
      package.json
  25. +3
    -136
      posts/singlePost.js
  26. +4
    -4
      utils/sql.js

+ 3
- 0
README.md View File

@ -110,6 +110,9 @@ npm install memory-cache --save
npm install request
npm install nodemailer
npm install nodemailer-smtp-transport
npm install node-pandoc
```

+ 1
- 1
admin.js View File

@ -67,7 +67,7 @@ app.use(function(request, result)
const file = "./admin/admin.js";
Promise.all([includes.printAdminHeader(),
require(file).main(filename, request),
require(file).main(request),
includes.printFooter()]).then(function(content)
{
result.write(content.join(''));

+ 1
- 0
admin/admin.js View File

@ -22,6 +22,7 @@ module.exports=
{
utils.getPostData(request).then(function (postData)
{
console.log(postData);
Promise.all([require("./posts/newPost.js").main(postData),
require("./category/addCategory.js").main(postData),
require("./posts/editPost.js").main(postData),

+ 1
- 1
admin/category/addCategory.js View File

@ -81,7 +81,7 @@ module.exports=
{
return new Promise(function(resolve, reject)
{
Promise.all([utils.include("./admin/addCategory.html"),
Promise.all([utils.include("./admin/category/addCategory.html"),
printCategories(),
processPost(postData)]).then(function(html)
{

+ 1
- 1
admin/downloads/manageDownloads.js View File

@ -57,7 +57,7 @@ const addDownload = function(postData)
return new Promise(function(resolve, reject)
{
Promise.all([addDownloadPostData(postData),
utils.include("./admin/addDownload.html")]).then(function(html)
utils.include("./admin/downloads/addDownload.html")]).then(function(html)
{
resolve("<div class=\"col-md-6\">" + html.join('') + "</div>");
}).catch(function(error)

+ 4
- 2
admin/login/login.js View File

@ -22,6 +22,7 @@ const processLogin = function(request)
return sql.checkLogin(postData);
}).then(function(loginResult)
{
if(loginResult.pass)
{
request.session.user = loginResult.user;
@ -30,7 +31,8 @@ const processLogin = function(request)
}
else
{
resolve("");
console.log("password incorrect");
resolve("Password incorrect");
}
}).catch(function(err)
{
@ -52,7 +54,7 @@ module.exports=
{
return new Promise(function(resolve, reject)
{
Promise.all([utils.include('./admin/login.html'),
Promise.all([utils.include("./admin/login/login.html"),
require("../../sidebar/sidebar.js").main(),
processLogin(request)]).then(function(html)
{

+ 1
- 1
admin/posts/newPost.js View File

@ -55,7 +55,7 @@ module.exports=
{
return new Promise(function(resolve, reject)
{
Promise.all([utils.include("./admin/newPost.html"), processPost(postData)]).then(function(html)
Promise.all([utils.include("./admin/posts/newPost.html"), processPost(postData)]).then(function(html)
{
resolve(html.join(''));
}).catch(function(error)

BIN
blogContent/headerImages/ConstantTimeComplexity.png View File

Before After
Width: 1284  |  Height: 480  |  Size: 44 KiB

+ 12
- 12
blogContent/posts/java/gremlin-in-10-minutes.md View File

@ -1,4 +1,4 @@
## What is Gremlin?
# What is Gremlin?
Gremlin is a graph traversal language: think of Gremlin as the SQL for graph databases. Gremlin is not
a graph database server, it is a language; but, there is a Gremlin Server and a Gremlin Console available for
@ -7,7 +7,7 @@ like [Titan](https://www.digitalocean.com/community/tutorials/how-to-set-up-the-
and [HBase](https://docs.janusgraph.org/latest/hbase.html).
## Graph Data Base Basics
# Graph Data Base Basics
A graph database is based on graph theory. A graph is composed of nodes, edges, and properties. A key
object/component in a graph database is stored as a node. Nodes are connected via edges representing
@ -54,11 +54,11 @@ gremlin> g = graph.traversal().withRemote(DriverRemoteConnection.using(cluster,
```
## Gremlin Syntax
# Gremlin Syntax
Now that you have your gremlin server and console set up, you are ready to start executing Gremlin queries.
### Adding a Vertex
## Adding a Vertex
In Gremlin nodes are referred to as "Vertexes". To add a node/vertex to the graph, you simply use the
command addV() on your graph traversal source. For consistency, most people
@ -70,7 +70,7 @@ EX:
g.addV('student').property('name', 'Jeffery').property('GPA', 4.0);
```
### Updating a Property
## Updating a Property
Unlike SQL, you are not limited to a specific schema in a graph database. If you want to add or change
a property on a vertex or edge, you simply use the property command again.
@ -81,7 +81,7 @@ You can replace "g.V(1)" with a command to select a specific vertex or edge.
g.V(1).property('name', 'Jeffery R');
```
### Selection
## Selection
Selecting nodes and edges is the most complicated part of Gremlin. The concept is not particularly hard, but, there
are dozens of ways to do graph traversals and selections. I will cover the most common aways to traverse a graph.
@ -111,7 +111,7 @@ g.V().hasLabel('student').order().by('gpa', decr).value('name')
```
### Adding Edges
## Adding Edges
The easiest way (my opinion) to add edges in Gremlin is by
using aliasing. In this example we select two nodes and assign them a name: in this case it is "a", and "b".
@ -124,14 +124,14 @@ g.V(0).as('a').V(1).as('b').addE('knows')
```
## Using Gremlin with Java
# Using Gremlin with Java
Now that you know the basic syntax of Gremlin, you are ready to use it somewhere other than the Gremlin console. If you
are trying to use Gremlin with Java, there is a great Maven dependency for TinkerPop and Gremlin. If you want to quickly
connect to your Gremlin server with Java, make sure your server is set up exactly as it was before this tutorial started discussing
Gremlin syntax.
#### Maven dependency for Java:
## Maven dependency for Java:
```html
<!-- https://mvnrepository.com/artifact/com.tinkerpop/gremlin-core -->
<dependency>
@ -187,7 +187,7 @@ public class GraphConnection
}
```
#### Basic GraphConnection.java Usage:
## Basic GraphConnection.java Usage:
```java
RemoteConnection con = new RemoteConnection()
String query = "g.V().hasLabel('player')" +
@ -201,7 +201,7 @@ String query = "g.V().hasLabel('player')" +
this.con.queryGraph(query);
```
#### Overly complex usage with a lambda statement
## Overly complex usage with a lambda statement
```java
/**
* Fetches the list of a player's friends.
@ -255,7 +255,7 @@ I highly suggest that you look at the tutorial [SQL 2 Gremlin](http://sql2gremli
If you plan on deploying this to production, it is recommended that you use HBase for a persistent back end storage
server.
## Resources
# Resources
- [SQL 2 Gremlin](http://sql2gremlin.com/)
- [Practical Gremlin](http://kelvinlawrence.net/book/Gremlin-Graph-Guide.html)

+ 8
- 8
blogContent/posts/java/top-three-recommended-java-ides.md View File

@ -7,8 +7,8 @@ highlighting which makes the code easier to read and error highlighting which
makes finding that missing semi colon easier. Here is a list of three IDEs that
work well for me.
NetBeans
--------
# NetBeans
NetBeans is the most productive IDE for large java projects. NetBeans is great
at detecting errors in your code. You can also have multiple projects open in
@ -19,8 +19,8 @@ JavaScript and C/C++.
![NetBeans IDE](media/2a20326e77c3f67aa3753401ba4bc612.png)
Eclipse
-------
# Eclipse
Eclipse is a very popular programming IDE; however, it is harder to use than
NetBeans. The largest benefit of Eclipse is that it has tons of templates for
@ -28,8 +28,8 @@ you to use. Eclipse also has a better GUI creation tool than NetBeans has.
![Eclipse](media/f5cb2682e219549cb07acd1d01c2ccb1.png)
JCreator
--------
# JCreator
I want to warn you that this is a old IDE. You hate yourself if you decide to
use this program. The only reason I am putting this on my list is because I
@ -43,8 +43,8 @@ Science students who have to memorize/learn what certain errors mean.
![JCreator](media/c1e712bdead908ebd72921ec2d1cbd5e.png)
Intellij
--------
# Intellij
\*Update 2018

+ 9
- 10
blogContent/posts/other/why-do-i-blog.md View File

@ -5,8 +5,8 @@ Different people may have different takes on this. There is an incentive to
start a website in the hopes that it will become popular and make add revenue.
However, I argue that there is a intrinsic value to a personal blog.
Organize Your thoughts
----------------------
# Organize Your thoughts
Being able to clearly articulate your ideas is beneficial. Having time to brew
over topics in a blog posts helps that process. Even though I worked with both
@ -14,22 +14,22 @@ Nodejs and PHP, I might not be able to a convincingly debate with somebody why
one is the better platform. Writing a blog posts allows me to fully flesh out my
own ideas.
Learn
-----
# Learn
When writing a blog post, you want to be complete. If there are any gaps in my
knowledge, I will look that information up. This is a great learning
opportunity; like taking notes in a class.
Stand Out
---------
# Stand Out
Out of everyone who uses the internet, only 1% of them contributes additional
content. Blogging can make you stand out in a competitive economy when looking
for jobs.
Relax
-----
# Relax
This may not be true of some bigger blogs, but, writing blog posts is very
relaxing. It gives you time to slow down relax and reflect. There are dozens of
@ -39,8 +39,7 @@ There are already millions of tutorials on the internet, I just want to share my
experience on topics that interest me. In this way writing blogs are relaxing
and don’t feel like work.
Become A Better Blogger
-----------------------
# Become A Better Blogger
There is no way to become better at something other than doing it a lot. Since
starting this website when I was middle school, my writing skills have increased

+ 16
- 16
blogContent/posts/programming/c-to-c++-tutorial.md View File

@ -4,7 +4,7 @@ enable people to use this as a quick reference to quickly jump into C++. This po
that you have prior knowledge of both C and object oriented-programming concepts. Each topic
is quickly covered in a code snippet and some additional explanation is provided if necessary.
## Input/Output
# Input/Output
Input and output in C++ is easy, you use "cout" and "cin". When printing with
"cout", you separate what your printing with "<<"; "endl" prints a new line.
@ -39,7 +39,7 @@ g++ helloWorld.cpp -o hello
```
## Namespaces
# Namespaces
Name spaces are used to enable you to have multiple functions/methods called the
same thing and not conflict with one another. You use "namespacename::function/variable"
@ -90,7 +90,7 @@ int main()
```
## Global Variable
# Global Variable
Global variables are similar to C, however, you can now reference a global members with the "::"
accessor.
@ -112,7 +112,7 @@ int main ()
}
```
## Multiple Names for a Variable/Aliasing
# Multiple Names for a Variable/Aliasing
This is NOT simply a pointer. In the following example pi, and x now are treated as
the same exact variable. You cannot later change the pointer destination for x.
@ -128,7 +128,7 @@ cout << "pi: " << pi << " x: " << x << endl; // prints pi: 2.1 x: 2.1
```
## Passing Variables by Reference
# Passing Variables by Reference
In C, everything was passed by value; C++ allows us to pass variables by reference. This is very powerful, in
languages like Java, only Objects are passed by reference. C++ lets you decide exactly
@ -178,7 +178,7 @@ int main()
```
## Functions Returning Variables References
# Functions Returning Variables References
A function can return a value reference which can be treated as a variable. In the following example, a function
returns the reference to the variable which is the smallest.
@ -211,7 +211,7 @@ int main ()
```
## Inline
# Inline
Inline can be used to replace a function which contains very simple logic -- no
for loops, etc. Like a macro, this will be inserted everywhere the code is used; a
@ -237,7 +237,7 @@ int main()
}
```
## Exceptions
# Exceptions
Exceptions might help you stop segmentation faulting. The important thing to notice
is that you can throw about any type in a try block.
@ -263,7 +263,7 @@ catch(int result)
```
## Default Parameters for Functions
# Default Parameters for Functions
This is exactly like default parameters in Python. If a function is called without
the parameter, it is assumed to be that value.
@ -284,7 +284,7 @@ int main()
```
## Function Overloading
# Function Overloading
Like Java and Python, you can overload methods in C++. Not only can you overload the
methods, but, the return type of the methods which are overloaded don't have to match.
@ -315,7 +315,7 @@ int main()
```
## Operator Overloading
# Operator Overloading
You can redefine basic operators like (+,/,-,<<,>>, +=) for certain data types by using
operator overloading.
@ -367,7 +367,7 @@ int main ()
}
```
## Functions with Generic Parameter Types
# Functions with Generic Parameter Types
In C++ you can use a template class to create a method which has generic
return and parameter types.
@ -400,7 +400,7 @@ type1 maximum (type1 a, type2 b)
```
## Replacement for malloc and free
# Replacement for malloc and free
Malloc and free still exists in C++, however, people typically
use "new" and "delete" instead because it is cleaner.
@ -416,7 +416,7 @@ delete i;
```
## Struct Functions
# Struct Functions
You can now add functions to structs.
@ -655,7 +655,7 @@ int Cat::fly()
}
```
## Strings
# Strings
Since C++ has classes, you can work with strings in a pleasant way.
@ -806,7 +806,7 @@ int main()
}
```
## Resources
# Resources
You now know enough C++ to start programming with it. If you want to take your
skills to the next level, I would recommend start working on a few projects in C++ and get

+ 395
- 0
blogContent/posts/programming/everything-fibonacci.md View File

@ -0,0 +1,395 @@
If you have ever taken a computer science class you probably
know what the fibonacci sequence is and how to calculate it.
For those who don't know: [Fibonacci](https://en.wikipedia.org/wiki/Fibonacci)
is a sequence of numbers starting with 0,1 whose next number is the sum
of the two previous numbers. After having multiple of my CS classes
give lectures and homeworks on the Fibonacci sequence; I decided
to write a blog post going over
the 4 main ways of calculating the nth term of the Fibonacci sequence.
In addition to providing the python code for calculating the nth perm of the sequence, a proof for their validity
and an analysis of their time complexities both mathematically and empirically will
be examined.
# Slow Recursive Definition
By the definition of the Fibonacci sequence, it is the most natural to write it as
a recursive definition.
```Python
def fib(n):
if n == 0 or n == 1:
return n
return fib(n-1) + fib(n-2)
```
##Time Complexity
Observing that each call has two recursive calls we can place an upper bound on this
function as $O(2^n)$. However, if we solve this recurrence we can place a tight bound for time complexity.
We can write a recurrence for the number of times fib is called:
$$
F(1) = 1\\
F(n) = F(n-1) + F(n-2)\\
$$
Next, we replace F(n) with $a^n$ since we want to find rate of exponential growth.
$$
a^n = a^{n-1} + a^{n-2}\\
\frac{a^n}{a^{n-2}} = \frac{a^{n-1} + a^{n-2}}{a^{n-2}}\\
a^2 = a + 1\\
a = \frac{1 \pm sqrt(5)}{2}\\
$$
From this calculation we can conclude that F(n) $\in \Theta 1.681^n$. We don't have to worry about
the negative root since it would not be asymptotically relevant by the definition of $\Theta$.
## Measured Performance
Here is a graph of the actual performance that I observed from this recursive definition of Fibonacci.
![Recursive Definition](media/fibonacci/RecursiveDefinition.png)
# Accumulation Solution
The problem with the previous recursive solution is that you had to recalculate certain
terms of fibonacci a ton of times. A summation variable would help us avoid this problem.
You could write this solution using a simple loop or dynamic programming
, however, I chose to use recursion to demonstrate that it's recursion which made the first
problem slow.
```Python
def fibHelper(n, a, b):
if n == 0:
return a
elif n == 1:
return b
return fibHelper(n-1, b, a+b)
def fibIterative(n):
return fibHelper(n, 0, 1)
```
In this code example, fibHelper is a method which accumulates the previous two terms.
The fibIterative is a wrapper method which sets the two initial terms equal to 0 and 1
representing the fibonacci sequence. At first it may not be obvious that fibIterative(n)
is equivalent to fib(n). To demonstrate that these two are in fact equivalent, I broke this
into two inductive proofs.
## Proof for Fib Helper
**Lemma:** For any n $\epsilon$ N if n $>$ 1 then
$fibHelper(n, a, b) = fibHelper(n - 1, a, b) + fibHelper(n - 2, a, b)$.
**Proof via Induction**
**Base Case**: n = 2:
$$
LHS = fibHelper(2, a, b)\\
= fibHelper(1, b, a + b) = a + b\\
RHS = fibHelper(2 -1, a, b) + fibHelper(2-2, a, b)\\
= a + b\\
$$
**Inductive Step:**
Assume proposition is true for all n and show n+1 follows.
$$
RHS=fibHelper(n+1;a,b)\\
= fibHelper(n;b,a+b)\\
=fibHelper(n-1;b,a+b) + fibHelper(n-2;b,a+b)\\
=fibHelper(n;a,b) + fibHelper(n-1;a,b)\\
=LHS\\
$$
$\Box$
## Proof That fibIterative = Fib
**Lemma:** For any n $\in$ N, $fib(n)$ = $fibIterative(n, 0, 1)$
**Proof via Strong Induction**
**Base Case**: n = 0:
$$
fibIterative(0, 0, 0) = 0\\
= fib(0)
$$
**Base Case**: n = 1:
$$
fibIterative(1, 0, 0) = 1\\
= fib(1)
$$
**Inductive Step:**
Assume proposition is true for all n and show n+1 follows.
$$
fib(n+1) = fib(n) + fib(n-1)\\
= fibHelper(n, 0, 1) + fibHelper(n+1, 0 ,1) \quad\text{I.H}\\
= fibHelper(n+1, 0, 1) \quad\text{from result in previous proof}\\
$$
$\Box$
## Time Complexity
Suppose that we wish to solve for the time complexity in terms of the number of additions needed to be
computed. Based on fibHelper we can see that it performs one addition every recursive call.
We can now form a recurrence for time complexity.
$$
T(0) = 0\\
T(1) = 0\\
T(n) = 1 + T(n-1)\\
T(n) = n-1\\
$$
From this recurrence we can say that fibHelper $\in \Theta(n)$.
## Measured Performance
Notice how much faster this solution is compared to the original recursive solution for
Fibonacci.
![Iterative Performance](media/fibonacci/Iterative.png)
# Matrix Solution
We can actually get better than linear for performance for Fibonacci while still using
recursion. However, to do so we need to know this fact:
$$
\begin{bmatrix}
1 & 1\\
1 & 0
\end{bmatrix}^n =
\begin{bmatrix}
F_{n+1} & F_n\\
F_n & F{n-1}
\end{bmatrix}^n
$$
Without any tricks, raising a matrix to a power n times would not get
us better than linear performance. However, if we use the [Exponentiation by Squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
method, we can expect to see logarithmic time. Since two spots in the matrix are always equal,
I represented the matrix as an array with only three elements to reduce the space and
computations required.
```Python
def multiply(a,b):
product = [0,0,0]
product[0] = a[0]*b[0] + a[1]*b[1]
product[1] = a[0]*b[1] + a[1]*b[2]
product[2] = a[1]*b[1] + a[2]*b[2]
return product
def power(l, k):
if k == 1:
return l
temp = power(l, k//2)
if k%2 == 0:
return multiply(temp, temp)
else:
return multiply(l, multiply(temp, temp))
def fibPower(n):
l = [1,1,0]
return power(l, n)[1]
```
## Time Complexity
For this algorithm, lets solve for the time complexity as the number of additions and multiplications required.
Since we are always multiplying two 2x2 matrices, that operation is constant time.
$$
T_{multiply} = 9
$$
Solving for the time complexity of fib power is slightly more complicated.
$$
T_{power}(1) = 0\\
T_{power}(n) = T(\left\lfloor\dfrac{n}{2}\right\rfloor) + T_{multiply}\\
= T(\left\lfloor\dfrac{n}{2}\right\rfloor) + 9\\
= T(\left\lfloor\dfrac{n}{2*2}\right\rfloor) + 9 + 9\\
= T(\left\lfloor\dfrac{n}{2*2*2}\right\rfloor) + 9+ 9 + 9\\
T_{power}(n) = T(\left\lfloor\dfrac{n}{2^k}\right\rfloor) + 9k\\
$$
let $k=k_0$ such that $\left\lfloor\dfrac{n}{2^{k_0}}\right\rfloor = 1$
$$
\left\lfloor\dfrac{n}{2^{k_0}}\right\rfloor = 1 \rightarrow 1 \leq \frac{n}{2^{k_0}} < 2\\
\rightarrow 2^{k_0} \leq n < 2^{k_0 +1}\\
\rightarrow k_0 \leq lg(n) < k_0+1\\
\rightarrow k_0 = \left\lfloor lg(n)\right\rfloor\\
T_{power}(n) = T(1) + 9*\left\lfloor lg(n)\right\rfloor\\
T_{power}(n) = 9*\left\lfloor\ lg(n)\right\rfloor\\
T_{fibPower}(n) = T_{power}(n)\\
$$
Now we can state that $fibPower(n) \in \Theta(log(n))$.
## Inductive Proof for Matrix Method
I would like to now prove that this matrix identity is valid since it is not at first obvious.
**Lemma:** For any n $\epsilon$ N if n $>$ 0 then
$$
\begin{bmatrix}
1 & 1\\
1 & 0
\end{bmatrix}^n =
\begin{bmatrix}
F_{n+1} & F_n\\
F_n & F{n-1}
\end{bmatrix}^n
$$
Let
$$
A=
\begin{bmatrix}
1 & 1\\
1 & 0
\end{bmatrix}^n
$$
**Base Case:** n = 1
$$
A^1=
\begin{bmatrix}
1 & 1\\
1 & 0
\end{bmatrix}^n =
\begin{bmatrix}
F_{2} & F_2\\
F_2 & F_{0}
\end{bmatrix}^n
$$
**Inductive Step:** Assume proposition is true for n, show n+1 follows
$$
A^{n+1}=
\begin{bmatrix}
1 & 1\\
1 & 0
\end{bmatrix}
\begin{bmatrix}
F_{n+1} & F_n\\
F_n & F{n-1}
\end{bmatrix}^n\\
= \begin{bmatrix}
F_{n+1} + F_n & F_n + F_{n-1}\\
F_{n+1} & F_{n}
\end{bmatrix}\\
= \begin{bmatrix}
F_{n+2} & F_{n+1}\\
F_{n+1} & F_{n}
\end{bmatrix}\\
$$
$\Box$
## Measured Performance
![FibPower Performance](media/fibonacci/FibPower.png)
As expected by our mathematical calculations, the algorithm appears to be running in
logarithmic time.
## Measured Performance With Large Numbers
![FibPower Performance](media/fibonacci/FibPowerBigPicture.png)
When calculating the fibonacci term for extremely large numbers despite having a polynomial
time complexity, the space required to compute each Fibonacci term grows exponentially. Since our
performance is only pseudo-polynomial we see a degrade in our performance when calculating
large terms of the fibonacci sequence.
The one amazing thing to point out here is that despite calculating the 10,000 term of Fibonacci,
this algorithm is nearly 400 times faster than the recursive algorithm when calculating
the 30th term of Fibonacci.
# Closed Form Definition
It is actually possible to calculate Fibonacci in constant time using Binet's Formula.
$$
F_n = \frac{(\frac{1+\sqrt{5}}{2})^n-(\frac{1-\sqrt{5}}{2})^n}{\sqrt{5}}
$$
```Python
def fibClosedFormula(n):
p = ((1+ math.sqrt(5))/2)**n
v = ((1-math.sqrt(5))/2)**n
return (p-v)/math.sqrt(5)
```
## Derivation of Binet's Formula
Similar to when we were calculating the time complexity of the basic recursive definition
, we want to start by finding the two roots of the equation in terms of exponents.
$$
a^n = a^{n-1} + a^{n-2}\\
\frac{a^n}{a^{n-2}} = \frac{a^{n-1} + a^{n-2}}{a^{n-2}}\\
a^2 = a + 1\\
0 = a^2 - a - 1\\
a = \frac{1 \pm sqrt(5)}{2}\\
$$
Since there are two roots to the equation, the solution of $F_n$ is going to be
a linear combination of the two roots.
$$
F_n = c_1(\frac{1 + \sqrt{5}}{2})^n + c_2(\frac{1 - \sqrt{5}}{2})^n
$$
Fact: $F_1$ = 1
$$
F_1 = 1\\
= c_1(\frac{1 + \sqrt{5}}{2}) + c_2(\frac{1 - \sqrt{5}}{2})\\
= \frac{c_1}{2} + \frac{c_2}{2} + \frac{c_1\sqrt{5}}{2} - \frac{c_2\sqrt{5}}{2}\\
$$
Let $c_1 = \frac{1}{\sqrt{5}}$,
Let $c_2 = \frac{-1}{\sqrt{5}}$
$$
F_n = \frac{1}{\sqrt(5)}((\frac{1+\sqrt{5}}{2})^n-(\frac{1-\sqrt{5}}{2})^n)\\
= \frac{(\frac{1+\sqrt{5}}{2})^n-(\frac{1-\sqrt{5}}{2})^n}{\sqrt{5}}
$$
## Time Complexity
Since we managed to find the closed form of the fibonacci sequence we can expect to see constant performance.
## Measured Performance
![FibPower Performance](media/fibonacci/ConstantTimeComplexity.png)

BIN
blogContent/posts/programming/media/fibonacci/ConstantTimeComplexity.png View File

Before After
Width: 860  |  Height: 480  |  Size: 38 KiB

BIN
blogContent/posts/programming/media/fibonacci/FibPower.png View File

Before After
Width: 640  |  Height: 480  |  Size: 38 KiB

BIN
blogContent/posts/programming/media/fibonacci/FibPowerBigPicture.png View File

Before After
Width: 640  |  Height: 480  |  Size: 31 KiB

BIN
blogContent/posts/programming/media/fibonacci/Iterative.png View File

Before After
Width: 640  |  Height: 480  |  Size: 26 KiB

BIN
blogContent/posts/programming/media/fibonacci/RecursiveDefinition.png View File

Before After
Width: 640  |  Height: 480  |  Size: 19 KiB

+ 7
- 7
blogContent/posts/projects/steam-friends-graph.md View File

@ -1,11 +1,11 @@
<iframe width="100%" height="315" src="https://www.youtube.com/embed/DoDaHmyIPvQ" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
### Links
# Links
- [GitHub](https://github.com/jrtechs/SteamFriendsGraph)
- [Live Site](http://steam.jrtechs.net/)
### Project Description
# Project Description
This project utilizes the steam API and graph databases to create friend graphs for clients in a
web browser. Currently there are two types of graphs available:
@ -15,7 +15,7 @@ web browser. Currently there are two types of graphs available:
This graph will only display your friends; however, it will draw edges between your friends’ if
they are friends with each other.
### Motivation
# Motivation
While learning about graph databases I thought that it would be awesome to create a massive graph
database with steam friends in it. After a quick google search, I realized that some other people have
@ -29,7 +29,7 @@ in the future.
![Lucid chart diagram](media/steam/diagram.png)
### Technical Details
# Technical Details
At the core of this project there is a java backend and a JavaScript frontend. I needed a backend for
this project because you cannot distribute your steam API key, plus, this allows me to cache everything
@ -47,7 +47,7 @@ start applying a force to shake the graph until all the nodes are added to the g
![Steam friends graph](media/steam/jrtechs1.png)
### Uses of Friends Graph Data Base
# Uses of Friends Graph Data Base
There are tons of [academic papers](http://infolab.stanford.edu/~ullman/mmds/ch10.pdf)
written on the usages of friends’ graphs. What you may be able to do with friends
@ -67,7 +67,7 @@ already does this to a certain extent when they recommend you games that are pop
![Steam friends graph](media/steam/ben2.png)
### Hosting the Project
# Hosting the Project
Hosting the front end of this project is easy, it is just thrown on an apache server. The backend
is trickier since it needs to run both a java app and a gremlin server. Currently I am hosting this
@ -76,7 +76,7 @@ loads it uses around 2 GB of ram and saturates my CPU.
![Steam friends graph](media/steam/jrtechs2.png)
### Future Plans for the Project
# Future Plans for the Project
In the future I would love to add more graphs to this website. Instead of just displaying graphs it would
also be cool to create pages which tries to identify friends’ groups, people you may know, and best

+ 5
- 8
blogContent/posts/web-development/history-of-jrtechs.md View File

@ -1,5 +1,4 @@
Original Site
-------------
# Original Site
Jrtechs initially started as a static HTML site that I created early 2014 to
build my HTML skills. I initially chose the name Jrtech, but that name was taken
@ -13,21 +12,19 @@ was working on.
![Original edgy site](media/fbd5a1128549b4feb5bafe3595ac1989.png)
Move to WordPress
-----------------
# Move to WordPress
In 2015 I moved my website to the cloud and started a WordPress site. The
website was focused on turorial like blog posts.
![Initial wordpress theme](media/4fcc3a9fe52f7b2e8bc1bfb164846073.png)
New Theme
---------
# New Theme
![Second wordpress theme](media/55ad5b49fe28c6374968b0f8a5b3e48b.png)
Rebirth in Nodejs
-----------------
# Rebirth in Nodejs
If you want to read about why I created a new content management system and left
WordPress read

+ 23
- 23
blogContent/posts/web-development/node-website-optimization.md View File

@ -5,7 +5,7 @@ done automatically. If you like to build stuff from scratch like me, there is a
ton of work required to optimize a website. This post will cover the 8 things that
I did to decrease the load time of this blog written in node by two seconds.
#### Final Results
# Final Results
![Final Website Speed Test](media/websiteOptimization/finalResults.png)
@ -17,8 +17,8 @@ waterfall for my home page, most of the time is a result of the youtube embedded
videos loading.
1: Optimize Images
------------------
# Optimize Images
Since images are the largest portion of a website's size, optimizing and
reducing the size of images will decrease load time. In a perfect web
@ -72,8 +72,8 @@ The goal of this script is to make most of the images under 100kb for the web.
It is ok to have a few images above 100kb; however, you should really avoid
having images above 200kb.
2: Take advantage of Async calls
--------------------------------
# Take advantage of Async calls
One of the largest benefits of Node is its Async abilities: code is
executed in a multi-threaded fashion. This can become a "callback hell" if not
@ -152,8 +152,8 @@ main: function(requestURL)
}
```
3: Client-Side Caching
----------------------
# Client-Side Caching
Client-side caching is where the client's web browser stores static content they
download from your website. For example, if a client caches a CSS style sheet,
@ -175,7 +175,7 @@ fast and I'm not worried about hash collisions for this application.
You can do this in NGINX if you use it to serve static files, but, you can also
do it directly in Node.
#### Caching CSS
## Caching CSS
```javascript
var eTag = crypto.createHash('md5').update(content).digest('hex');
@ -186,7 +186,7 @@ result.write(content);
result.end();
```
#### Caching Images
## Caching Images
```javascript
var eTag = crypto.createHash('md5').update(content).digest('hex');
@ -197,15 +197,15 @@ result.write(content);
result.end();
```
4: Server-Side Caching
----------------------
# Server-Side Caching
Even with the best async server, there are still ways to improve performance. If
you cache all the static pages that you generate in a HashMap, you can quickly
access it for the next web user without ever having to query the database or
do file IO.
#### Ex:
## Ex:
```javascript
const cache = require('memory-cache');
@ -247,8 +247,8 @@ server's cache.
![Server Cache Example](media/websiteOptimization/serverCache.png)
5: Enable Compression
---------------------
# Enable Compression
Compressing content before it is transferred over the internet can significantly
decrease the loading time of your website. The only trade off from this approach
@ -258,7 +258,7 @@ performance gains. Using Gzip on CSS and HTML can reduce the size by 60-70%.
If you are running an NGINX server, you can enable Gzip there. There is also a
simple node module which will use Gzip compression on an Express app.
#### Gzip on Express App
## Gzip on Express App
```bash
npm install compression
@ -269,8 +269,8 @@ var compression = require('compression')
app.use(compression());
```
6: Remove Unused CSS Definitions
--------------------------------
# Remove Unused CSS Definitions
If you use a CSS library like Bootstrap or W3-CSS, you will have a ton of css
classes which go unused. The standard BootStrap CSS file is around 210kb. After
@ -316,8 +316,8 @@ You don't have to use this through the command line, you can run this directly
in your node app to make it automated. Check out their
[documentation](https://www.purgecss.com/) to learn more.
7: Minify CSS and Javascript
----------------------------
# Minify CSS and Javascript
This is the easiest thing you can do to reduce the size of your website. You
just run your CSS and JavaScript through a program which strips out all
@ -332,8 +332,8 @@ Ex of Minified CSS:
There are Node libraries which can minify CSS and Javascript, however, if you
are lazy, just use a website like [this](https://cssminifier.com/).
8: Keep Minimal JavaScript
--------------------------
# Keep Minimal JavaScript
Ignoring the gross amount of Node dependencies you have, it is critical to
minimize the amount of dependencies the client needs. I completely removed
@ -364,8 +364,8 @@ most cases people don't full take advantage of Google Analytics, a simple
backend analytics service would work just as good while saving the client load
time.
Resources
---------
# Resources
- [Pingdom Speed Test](https://tools.pingdom.com/)

+ 2
- 0
includes/html/contact.html View File

@ -51,6 +51,8 @@
</div>
</form>
</div>
<br>
<br>
<script src='https://www.google.com/recaptcha/api.js'></script>

+ 5
- 0
includes/html/header.html View File

@ -25,6 +25,11 @@
}
p{font-size:18px;}
</style>
<script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_CHTML-full" type="text/javascript"></script>
</head>
<body>

+ 1
- 1
package.json View File

@ -11,9 +11,9 @@
"highlight": "^0.2.4",
"highlight.js": "^9.12.0",
"markdown": "^0.5.0",
"markdown-to-html": "^0.0.13",
"memory-cache": "^0.2.0",
"mysql": "^2.16.0",
"node-pandoc": "^0.3.0",
"nodemailer": "^4.6.8",
"nodemailer-smtp-transport": "^2.7.4",
"promise": "^8.0.1",

+ 3
- 136
posts/singlePost.js View File

@ -1,34 +1,4 @@
const utils = require('../utils/utils.js');
const sql = require('../utils/sql');
const Remarkable = require('remarkable');
const hljs = require('highlight.js');
const md = new Remarkable(
{
html: true,
highlight: function (str, lang)
{
if (lang && hljs.getLanguage(lang))
{
try
{
return hljs.highlight(lang, str).value;
}
catch (err) {}
}
try
{
return hljs.highlightAuto(str).value;
}
catch (err) {}
return ''; // use external default escaping
}
});
const postGenerator = require('../utils/renderBlogPost.js');
module.exports=
@ -41,69 +11,7 @@ module.exports=
*/
renderPreview: function(post)
{
return new Promise(function(resolve, reject)
{
//var html = "<div class=\"w3-card-4 w3-margin w3-white\">";
var html = "<div class=\"blogPost\">";
//image
if(!(post.picture_url === "n/a"))
{
html +="<img src=\"/blogContent/headerImages/" + post.picture_url +
"\" alt=\"\" style=\"width:100%; height:10%\">";
}
html += "<div class=\"p-4\"><div class=\"\">";
//title
html += "<h3><b>" + post.name + "</b></h3>";
//date
html += "<h5><span class=\"w3-opacity\">" +
post.published.toDateString() + "</span></h5>";
html +="</div>";
html += "<div class=\"\">";
try
{
sql.getCategory(post.category_id).then(function(category)
{
var pathName = "blogContent/posts/" + category[0].url + "/"
+ post.url + ".md";
var markDown = utils.getFileContents(pathName).toString();
markDown = markDown.split("(media/").join("(" + "../blogContent/posts/"
+ category[0].url + "/media/");
var htmlPost = md.render(markDown).split("<p>");
for(var i = 0; i < 3; i++)
{
html+= "<p>" + htmlPost[i];
}
html = html.split("<img").join("<img style=\"width: 100%; height:10%\" ");
html = html.split("<code>").join("<code class='hljs cpp'>");
html += " <div class=\"\">\n" +
" <p class='text-center'><button class=\"btn btn-secondary btn-lg " +
"w3-padding-large w3-white w3-border\" onclick=\"location.href='" +
"http://jrtechs.net/" + category[0].url + "/" + post.url +
"'\"><b>READ MORE &raquo;</b></button></p>\n" +
" </div>\n";
html += "</div></div></div><br><br>";
resolve(html)
}).catch(function(error)
{
reject(error);
});
}
catch(ex)
{
reject(ex);
}
});
return postGenerator.generateBlogPost(post, 3);
},
/**
@ -115,47 +23,6 @@ module.exports=
*/
renderPost: function(post)
{
return new Promise(function (resolve, reject)
{
var htmlHead = "<div class=\"blogPost\">";
//image
if(!(post.picture_url === "n/a"))
{
htmlHead +="<img src=\"/blogContent/headerImages/" + post.picture_url +
"\" alt=\"\" style=\"width:100%; height:10%\">";
}
htmlHead += "<div class=\"p-4\"><div class=\"\">";
//title
htmlHead += "<h3><b>" + post.name + "</b></h3>";
//date
htmlHead += "<h5><span class=\"w3-opacity\">" +
post.published.toDateString() + "</span></h5>";
htmlHead +="</div>";
var html = "<div class=\"\">";
try
{
sql.getCategory(post.category_id).then(function(category)
{
const pathName = "blogContent/posts/" + category[0].url + "/"
+ post.url + ".md";
var markDown = utils.getFileContents(pathName).toString();
markDown = markDown.split("(media/").join("(" + "../blogContent/posts/"
+ category[0].url + "/media/");
html += md.render(markDown);
html = html.split("<img").join("<img style=\"max-width: 100%;\" ");
html = html.split("<code>").join("<code class='hljs cpp'>");
html += "</div></div></div><br><br>";
resolve(htmlHead + html);
});
}
catch(ex)
{
reject(ex);
}
});
return postGenerator.generateBlogPost(post, -1);
}
};

+ 4
- 4
utils/sql.js View File

@ -268,16 +268,16 @@ module.exports=
if(post.username && post.password)
{
var cleanName = sanitizer.sanitize(post.username);
var cleanPassword = sanitizer.sanitize(post.password);
const cleanName = sanitizer.sanitize(post.username);
const cleanPassword = sanitizer.sanitize(post.password);
var getSalt = "select * from users where user_name='" +
const getSalt = "select * from users where user_name='" +
cleanName + "'";
fetch(getSalt).then(function(saltResult)
{
if(saltResult.length == 1)
{
var hashedPassword = crypto.createHash('sha256')
const hashedPassword = crypto.createHash('sha256')
.update(cleanPassword + saltResult[0].salt)
.digest('hex');
if(saltResult[0].password === hashedPassword)

Loading…
Cancel
Save