Saturday, March 12, 2022

Back to Rails

Been awhile again haha... but had an itch to build something again with Rails!

Have an interesting idea: Sharing Airplanes

Why planes? Well, I've started to work towards getting my Private Pilot's License and at a cost of $150/hr for a Cessna 172s, some back of the napkin math told me that sharing ownership of a plane would be financially beneficial. Not to mention, the money made from renting it would be a nice bonus.

After checking at my local club, Aspen Flying Club (Denver... but I'll be moving back to NYC later this month) I was surprised to learn that this really only happens by someone posting a flying on a board.

If this is not screaming for a tech solution, I dont know what is!

My initial search showed that there is one company out there doing this, but I wonder if maybe I can do better?

At the very least, this will satiate my Rails needs.


Getting Rails Up and Running
Why rails?
TBH- having a full stack ready to go without having all the nonsense of a JS stack is nice haha. 

Installing/Updating Stuffs
Thank Zeus for https://guides.rubyonrails.org/!!!

Noticed my Ruby was out of date, updated via Homebrew... and in my .zhrc added
if [ -d "/usr/local/opt/ruby/bin" ]; then
  export PATH=/usr/local/opt/ruby/bin:$PATH
  export PATH=`gem environment gemdir`/bin:$PATH
fi

Also needed to update my sqlite3
export PATH="/usr/local/opt/sqlite/bin:$PATH"

And after gem install rails

  ~ rails --version

Rails 7.0.2.3


 
YAY!

Now to re-familiarizing with Rails with their blog demo... this make take a few days :) 


Wednesday, April 8, 2020

Building amazonpricegouging.com

Its been awhile since I've posted anything, but now with being stuck at home figured might as well.

So a few weeks ago I was getting quite upset with Amazon and how so many things that people would use to protect themselves against this virus have become crazy expensive. Amazon claims to care, but taking a look at their site it is simply not so.

lol... was stunned that amazonpricegouging.com was available, so I picked it up.

I also figured this would be a good project for me, tech-wise.


To start, I figured I'd go with a MEAN stack. I know Angular and Node... figured Mongo wouldnt be too hard. Boy was I wrong. It was infuriating.

Then it dawned on me... good 'ol (new?) Rails!!! I loved developing the few Rails apps that I did and know how to deploy it easily to Heroku.

OK... now to start building. I decided not to use my work computer, mainly because I didnt want to mess around with the system settings. Lord knows once that happens you're in for a not so fun day.

I still had my 2012 MB Air... bahhh... built a sample app and it took FOREVER. The poor fella was just not working. And, even worse, I noticed that the battery was simply not holding very much charge. Luckily, Apple had just released the newest 2020 MB Airs (with the "proper" keyboard).


Ok, today's the day... built a sample app... gonna fidget with it and see if I can get it up to Heroku!

Wednesday, May 4, 2016

Data Structure, Computing Correlation, Pizza and Squirrels

While I am also going thru my iOS training, decided to shore up my JS. If you haven't come across this book, I highly recommend it: Eloquent Javascript.

Anyway, I am in chapter 4 working thru a somewhat challenging problem. It comes down to this: A dude turns in to a squirrel, somewhat randomly. He decided to write down when he becomes one and what events led to it (see data here).

Just for curiosity's sake, we want to see if there is any correlation between his eating pizza and turning in to a squirrel. To determine this we can calculate a phi coefficient; an array the following sets of information is what we need: <didn't become a squirrel & no pizza>,  <no squirrel & had pizza>, <became a squirrel & no pizza>, <became a squirrel and had pizza>.

This is an interesting problem not only because it requires a certain level of JS knowledge, but also because there are a few ways to solve this problem.

It should be noted that the problem already has a solution in the book, but the interesting part for me is HOW one goes about solving this issue.

I also want to give a shout out to fellow Apple folk who spent some time and we got a working solution: Kenny Crosby & Sonia Brahmi. It was a lot of fun working thru this problem with them and it was a great learning experience for me.

Allright lets start with what what we KNOW we must do- loop thru the "JOURNAL" array (this is just a sample of it, above there is a link for the entire data set):

1
2
3
4
5
6
7
8
9
var JOURNAL = [
  {"events":["carrot","exercise","weekend"],"squirrel":false},
  {"events":["bread","pudding","brushed teeth","weekend","touched tree"],"squirrel":false},
  {"events":["carrot","nachos","brushed teeth","cycling","weekend"],"squirrel":false},
  {"events":["brussel sprouts","ice cream","brushed teeth","computer","weekend"],"squirrel":false},
  {"events":["potatoes","candy","brushed teeth","exercise","weekend","dentist"],"squirrel":false},
  {"events":["brussel sprouts","pudding","brushed teeth","running","weekend"],"squirrel":false},
  {"events":["pizza","brushed teeth","computer","work","touched tree"],"squirrel":false},
  {"events":["bread","beer","brushed teeth","cycling","work"],"squirrel":false},


How to loop?

1
2
3
4
5
6
7
function tableFor(journal) {
 for (var i = 0; i < journal.length; i++){

 }
}

tableFor(JOURNAL);


We're clearly not doing anything here, simply calling the "JOURNAL" array. Perhaps a test to see if this works is a good idea, lets call the number of times he turns into a squirrel over the past 90 days

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
function tableFor(journal) {
 var squirrelYes = 0;

 for (var i = 0; i < journal.length; i++){
  if (journal[i].squirrel == true){
   squirrelYes += 1
  }
 }
 console.log("turned into a squirrel this many times: " + squirrelYes);
}

tableFor(JOURNAL);

//returns in the console: turned into a squirrel this many times: 5


Ok, now we have something to work with. Next up will be to determine what we need to calculate the phi coefficient: didn't become a squirrel & no pizza,  no squirrel & had pizza, became a squirrel & no pizza, became a squirrel and had pizza.

Some steps: need to create an array in which we can hold our new found information, and then determine what goes where.

The tricky part is traversing thru each of the various "events" objects within the JOURNAL array to determine if "pizza" exists or not. For example in JOURNAL[0] there is no pizza, but in JOURNAL[6] there is pizza. How do we do that in code?

Fortunately for us all there is a handy guide that the good folks at Mozilla put together for us. Searching for "array" shows us a whole lotta methods we can use, specifically, lets look at the .indexOf() method. This is kinda cool because this method returns the first index point at which a given element can be found in the array or it returns -1 if it is NOT found.

For example:

1
2
3
4
5
6
var array = ["two", "three", "four"];

array.indexOf("four");
// 2
array.indexOf("five");
// -1


Hmmm... this is good, but we have an array of objects! We can still use the .indexOf() method! Yay :)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
var array = [
  {"events":["carrot","exercise","weekend"],"squirrel":false},
  {"events":["bread","pudding","brushed teeth","weekend","touched tree"],"squirrel":false},
  {"events":["carrot","nachos","brushed teeth","cycling","weekend"],"squirrel":false},
  {"events":["brussel sprouts","ice cream","brushed teeth","computer","weekend"],"squirrel":false}];


array[0].events.indexOf("carrot");
// 0 carrot was found in the 1st object of the array at the 0 index
array[0].events.indexOf("exercise");
// 1 exercise was found in the 1st object of the array at the 1st index
array[0].events.indexOf("pizza");
// -1 pizza was NOT found in the 1st object of the array
array[3].events.indexOf("ice cream");
// 1 ice cream was found in the 4th object of the array at the 2nd index
array[3].events.indexOf("computer");
// 3 computer was found in the 4th object of the array at the 3rd index
array[3].events.indexOf("picked nose");
// -1 picked nose was NOT found in the 4th object of the array


Now that we can find a given element we have to be creative as to how to move thru the JOURNAL.

Taking a look at our existing loop (inside the tableFor function) we are indeed traversing thru the array, and with each loop we are incrementing the variable "i" (i = 0, 1, 2, 3... up to the JOURNAL's length). Since "i" is free, lets use it again when using .indexOf().

Using pseudo-code, we need to go to the "i" object inside JOURNAL, look at the "events" property and see if the value "pizza" exists. Here it is in code:

1
journal[i].events.indexOf("pizza") !== -1


Here, if at the "i" object if pizza exists we will NOT return "-1" and thus it will be true.

This is all getting close to completion! To count up our results we need to setup a variable for that as well, and lets call it table.

Putting it all together we get:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function tableFor(journal) {
 var table = [0];
 for (var i = 0; i < journal.length; i++){
  if(journal[i].events.indexOf("pizza") !== -1)
   table[0] += 1;
 }
 console.log(table)
}

tableFor(JOURNAL);

// [10] is returned, the total number of times pizza appears in the events property


Lets go back to the beginning and revisit what it is we are trying to find: didn't become a squirrel & no pizza,  no squirrel & had pizza, became a squirrel & no pizza, became a squirrel and had pizza.

Putting that in to code we get:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
function tableFor(journal) {
 var table = [0, 0, 0, 0];
 for (var i = 0; i < journal.length; i++){
  if(journal[i].squirrel == false && journal[i].events.indexOf("pizza") == -1) {
   table[0] += 1;
  }
  if(journal[i].squirrel == false && journal[i].events.indexOf("pizza") !== -1) {
   table[1] += 1;
  }
  if(journal[i].squirrel == true && journal[i].events.indexOf("pizza") == -1) {
   table[2] += 1;
  }
  if(journal[i].squirrel == true && journal[i].events.indexOf("pizza") !== -1) {
   table[3] += 1;
  }
 }
 console.log(table)
}

tableFor(JOURNAL);
// [76, 9, 4, 1]


TA DA! We got the solution we've been looking for! But you know what, this isn't "dry" (don't repeat yourself).

Three things immediately stand out: journal[i], the indexOf() method... but perhaps most importantly is how we are calling "pizza". For the journal[i] we can create a variable to hold that in, but the indexOf() method is probably best taken out in to its own function. Lastly, lets move out "pizza" to be another argument when tableFor is called.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function hasEvent(functionEvent, entry) {
 return entry.events.indexOf(functionEvent) !== -1
}

function tableFor(event, journal) {
 var table = [0, 0, 0, 0];
 for (var i = 0; i < journal.length; i++){
  var entry = journal[i];

  if(entry.squirrel == false && !hasEvent(event, entry)) {
   table[0] += 1;
  }
  if(entry.squirrel == false && hasEvent(event, entry)) {
   table[1] += 1;
  }
  if(entry.squirrel == true && !hasEvent(event, entry)) {
   table[2] += 1;
  }
  if(entry.squirrel == true && hasEvent(event, entry)) {
   table[3] += 1;
  }
 }
 console.log(table)
}

tableFor("pizza", JOURNAL);
// [76, 9, 4, 1]


There we go, a slightly different answer than what the book has, but, to be honest, it is more readable and immediately understandable.

My next blog will detail how we go about solving for the phi coefficient itself and, perhaps, determine what it is that makes this dude turn in to a squirrel.

Tuesday, January 5, 2016

Updates

The forces of evil are against me... I mean that I deleted Xcode to free space for movies on my (old) MBAir... and now I also have to upgrade to El Capitan. lol

Thankfully with Gigabit internet the downloads aren't gonna take long. Unfortunately, no coding for me today! 

iOS & Swift

This is where your friend and humble narrator finally takes it upon himself to learn iOS & Swift. Curiously enough, while I am working at Apple, I haven't touched either and these are some of the most incredible things that Apple has come out with. Anyhoo, making apps is (arguably) the best way forward and forward I shall go! Just simple things for now: calculators, word reversers, a simple game or two, (of course) a to-do app and some other silly things.

BUT, one app I really do want to create is one where I can use the iPhone to determine if the speed of a turntable is correct. I wont go into details right now, but when I get a chance I will!

Right- lets get started!!

Tuesday, June 9, 2015

Two big things, one post

Today was a fun day. A lot of the hard work I put in @ Apple paid off, and during WWDC the pages I worked on came live! YAY

Also, for the massage app, got a lot done... specifically I was happy to get much of the logic down for the Admin users. I still have not created the day-of event specs, but that is for tomorrow.

Some things I am proud of:

def admin_user
if !logged_in?
flash[:info] = "please log in"
elsif !current_user.admin?
redirect_to(root_url) && flash[:info] = "Not an admin, cannot create events"
elsif current_user.admin?
flash.now[:info] = "create your event here"
end
end

This is actually part of a before_action I have on my events controller. I was trying to remember a way to ensure only certain classes of users could make it to a page, and thanks again to Hartl's Tutorial it came back. Check out the controller

Oh, and some super simple jQuery to hide some flash messages (like the ones above)

$('document').ready(function() {
setTimeout(function() {
$('.alert-info').slideUp();
}, 3000);
setTimeout(function() {
$('.alert-success').slideUp();
}, 3500);
});

I liked that... nice to get those to go away 

Sunday, June 7, 2015

Oh, some interesting things w/ the app

I've tried to go about this the TDD way. I haven't been testing so much at work... well I dont even use Rails at work either :)

Some examples-







Nothing terribly difficult here, at least now, but these tests have saved me from times when I thought I was only updating one thing, but actually changed the structure much deeper.

OH, another WAY cool thing is a "seed". I want to test how this site reacts with a lot of users.

The faker gem rules and allows me to seed my db:












Also know that I created some other users there for testing (some admins, some not). Ok, back to my admin work.

Massage App

So @ AKQA we have massages and the way to signup is one of two ways:

1. A signup sheet
2. An online form

The first option is not very good because an email is sent out and then there is a rush to where the form is. Of course, if you are in a meeting, dont see the email or maybe not in the office that day you totally miss out.

The second option isn't great because of some of the above reasons and that the people who see the email first get first dibs.

Essentially, its a mad rush and I feel there must be a better way.

I am going to build an app where an admin can create an event and users can select a time for that event.

You can checkout the code here (dont ask why it is called talktome)
and a live version on heroku here

There are essentially 3 phases for this:

1. Users & Admin signup (and a confirmation email is sent)
2. An admin creates an event (which is emailed to users)
3. Users signup for events

Note- the authorization has already been written, now onto getting the admin section completed

Wednesday, January 29, 2014

From Zero to App Store with HTML5, APIs and PhoneGap- Making my first phone app

Thanks Richard (friend and fellow student from General Assembly) for letting me know about an awesome meeting @ Apigee to build an API driven mobile app. I've been looking for something new and fun and this is it!

I'll post the juicy details of the one day bootcamp afterwards... should be fun... 

Friday, January 17, 2014

Benchmarking, what a difference a line makes

What a difference a line of code makes
32 little lines
...
Ok, now that we have Renee Olstead's song in our heads lets get what it is I'm trying to say:

Code that works may very well not perform well. I wanted to see about writing some code to figure out the first n prime numbers. Pretty easy stuff:


I got to thinking that the downside of this is that I am running the modulo operator on each and every number. This clunkiness isn't so apparent on testing the first 100 numbers, but, what if we are talking about 100,000?!?

More to the point, how to even see what is the time spent?

require 'benchmark' => from ruby docs we can see that this module lets us see what the time factor really is.



From the docs we understand that the time breakdowns are: CPU time, system CPU time, sum of user and system CPU time and, arguably, most importantly, elapsed real time (the on in quotes: (0.000100) )

Lets change array_test(100) to array_test(100000). This will run our benchmark on our method to show us the prime numbers 1 - 100,000.


Yeah, a big time difference. Before coding I wouldda thought there would have been a linear difference, but here we see instead of it taking x1,000 more, it is x100,000. Here is our first taste of Big O, and I'll go over that later. But lets instead focus on making this faster.


Nice... ~x6 faster

what does adding (2..Math::sqrt(max)).each do |i| help us achieve?

Essentially we have to recognize that x * y =  z. If z is not a prime then there has to be two numbers x * y = z. If both x and y were are greater than the square root of n then x * y would be greater than n; This then means that x or y must be less than (or equal to) the square root of n (thanks to Edward Guiness's book for really helping me understand this).

So, instead of checking all the numbers 1-100,000 (as the iterated array using i), we can test a much smaller set of numbers. 

Sunday, January 12, 2014

Deleted a whole lotta files, now what about git?

I'm sure we've all run into this problem: Want to cleanup a directory since it has a lot of old files we are no longer using. But when we want to commit our changes using git we see something like this:


I can think of very few other things than manually doing "git rm blahh blahh blahh" x many times which would annoy me more. Maybe TMNT on the NES ... ;)

So, I figured that "git add . " adds all the modified/new/renamed files, so why not try "git rm .". Well that didn't work, but there was a temping thought in my mind to try "git rm . -r". This recursively deletes files, and I thought it would only do the ones in question. Alas, it went about deleting everything... recursively ... duhh.

Fortunately, I've become git obsessed so with a "git reset --hard" I went back to the previous commit and all is ok.

After some sleuthing, it turns out there is a one trick pony to be able to do what I want,
git rm $(git ls-files --deleted)

With a git commit we're good to go!

Now, looking at the way I removed the files it appears to narrowly select the deleted files, I wonder if this will work on other types too (modified, new, etc)?

I'll try to remember to try when I come across this next. 

Friday, January 10, 2014

A link in an ALT that is being referenced to another image? Wait whaaa...??

I am in the midst of putting up some of the final touches to my personal/portfolio website (tejas-mehta.com) and one thing I really wanted to do was to include a link to my projects.

Sounds easy, right??

BUT what if Isotope is used to dynamically show the full pic after clicking on a thumbnail, that full pic being referenced via another link AND the text is shown within an ALT tag? Now are you squirming?? (only the cronies will get that joke)

After a few tries I used the most important lesson I have ever learned: Keep at it, the answer is there, you'll get it done and search around. Yes, I consider that ONE lesson... they flow together.

Here's my code before tinkering:






And after lots of testing... sweetness









A small lesson: links can indeed be included within alt tag.... here's the result:



That nice orange link works... nicely ;)


Wednesday, January 8, 2014

Why ask for twitter when a blog is way better?

I was filling out a "info-form" for General Assembly's employer meet and greet and was surprised that while there is a space to put in my twitter account, there wasn't anything for my blog!?!

While I am not against twitter, I feel that having a space for a blog is better. Granted, I dont blog so often and that a great thing about twitter is that you can splurt out your thoughts real fast.

Anyway, long story short I should blog more often ;)

Thursday, January 2, 2014

Changed Database... now gotta rake task for Heroku, but how?

Issue: Ok, so for Hacker Corral I never setup a "forgotten password" field in case, well, if someone forgets their password. To do this I need to setup an Authorization Token for each user so that when an email is sent, that specific token, which will be assigned to a user some random token (SecureRandom.urlsafe_base64) is sent with the email, rather than just the user id number.

Here's the problem: the database on my Heroku deployed version has actual users, not fake ones. On my "local" version it was ok for me to just rake db:reset my database... but I dont want to do that on a live site. Doing so would delete my users.

The solution: RAKE TASK it baby!! ;)

What this means: Essentially, it will go thru my database and generate the auth_token as needed for those users who dont have one. Pretty cool, no?


lib/tasks/rebuild_token_auth.rake

+namespace :user do
+  desc "Rebuild Auth-Tokens"
+  task :rebuild_auth_token => :environment do
+    User.transaction do
+      User.all.each { |u|
+        u.generate_token(:auth_token)
+        u.save!
+      }
+    end
+  end
+  
+end

The only "downside" of this particular implementation is that it the auth_token that will be sent to the user will be the same for any future request to update a password. I'll probably do something like running this particular task once a week/month/whatever to keep those auth_tokens changing, thus preventing someone who may get a user's token from being able to reset the password. 

Anyway, next steps are simple. 

1. git add .
2. git commit -m "rake take to generate auth token"

This is the part where one has to think about what is going on with heroku.

3. heroku run rake user:rebuild_auth_token
       this then populates the auth_token as needed
4. for good measure, heroku restart

Now we have populated what is needed, and the users who registered before I created the reset password option can do so as well, yay!