Rails Sidekiq configuration for micro services on reverse proxy.

Content posted here with the permission of the author Rahul Ojha, who is currently employed at Josh Software. Original post available here.

This blog is intended to describe how to configure multiple sidekiq webs for API only apps using reverse proxy server.


We have 4 API services running on ECS. We used a single domain for all the services and segregated them with the namespace in routing. For namespace routing and pointing to Docker containers, we have used Traefik. We can do the same thing using Nginx and some other reverse proxy too.



Problem Faced

Now the problem was when we try to access sidekiq webs with these namespace routes. It does not load rails assets because namespace path ‘rails-api-1 ’ is not considered in the root path, and sidekiq tries to find assets in the path `www.domain.com/sidekiq/` and it doesn’t exist actually.


Initially, we mounted sidekiq path in config/routes.rb like this.

mount Sidekiq::Web => '/sidekiq'

Later, we changed it to

mount Sidekiq::Web => '/rails-api-1-sidekiq'

Configuration for Traefik:

You need to add a new rule in docker labels

Key => traefik.sidekiq.frontend.rule 
Value => Host:www.domain.com;PathPrefix:/rails-ap1-1-sidekiq

Configuration for Nginx:

If you are using Nginx as a reverse proxy then you need to add these configuration for each service.

location /rails-ap1-1-sidekiq/ {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://your_domain/rails-ap1-1-sidekiq/;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
  }location /rails-ap1-2-sidekiq/ {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://your_domain/rails-ap1-2-sidekiq/;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

Now you can access your sidekiq web at


After that Sidekiq will look for assets in path /rails-api-1-sidekiq/. Here as per docker label rails-api-1-sidekiq indicates that it will point to the container rails-api-1 because it is configured forrails-api-1task and within that container, it will look for the assets in /rails-api-1-sidekiq/.path, You can see in below image

Similarly, you can setup multiple sidekiq on your reverse proxy.

Thank you!

Posted in General, Ruby on Rails | Leave a comment

Building Decentralised Link Shortner on Ethereum blockchain using Truffle

Original post available here.

Blockchain is emerging technology, it needs no introduction. By any chance if you are left behind and don’t know about blockchain then I recommend reading about blockchain first before reading this article. You can read about blockchain here or here or search on internet and you will find plenty of article to read from.

What is Ethereum ?

Launched in 2015, Ethereum is the world’s leading programmable blockchain. It is a global, open-source platform for decentralized applications. These decentralized applications (or “dapps”) gain the benefits of cryptocurrency and blockchain technology. Read more about ethereum here.

What is Truffle ?

Truffle is a framework for blockchain development, it streamlined smart contractcreationcompilationtesting, and deployment onto Ethereum. Read more about truffle here

What is Decentralised App ?

Decentralised application does not require centralised server to work (hence no maintenance cost). It interacts with smart contract deployed on blockchain network.

What is Smart Contract ?

Smart contracts are programs which govern the behaviour of accounts within the Ethereum state. We will write smart contract in Solidity language, Solidity is an object-oriented, high-level language for implementing smart contracts. Read more about solidity from here.

Getting Started:

A) Install npm, node & Truffle

Follow https://docs.npmjs.com/downloading-and-installing-node-js-and-npm for installing npn & node.

Then install truffle

npm install -g truffle

check if truffle installed successfully or not

$ truffle version
Truffle v5.0.21 (core: 5.0.21)
Solidity v0.5.0 (solc-js)
Node v11.0.0
Web3.js v1.0.0-beta.37

B) Create Project

Create new folder for project & initialise with truffle. We will use React Truflle box

$ mkdir link_shortner
$ cd link_shortner/
$ truffle unbox react
✔ Preparing to download
✔ Downloading
✔ Cleaning up temporary files
✔ Setting up box
Unbox successful. Sweet!
Compile:        truffle compile
  Migrate:        truffle migrate
  Test contracts: truffle test

If you are new to Truffle then read about created directory from https://www.trufflesuite.com/docs/truffle/getting-started/creating-a-project

C) Install Ganache for blockchain setup on local machine https://www.trufflesuite.com/docs/ganache/overview

Link Shortner Smart Contract

Create LinkShortner.sol file inside contracts/ folder and write following content in it.

pragma solidity ^0.5.0;

contract LinkShortner {
  event LinkAdded(uint linkId, string url);
  uint lastLinkId;
struct LinkTemplate {
  address userAddress;
  string url;

mapping (uint => LinkTemplate) public linkMapping;
constructor() public {
  lastLinkId = 0;

function createNewLink(string memory url) public returns (uint, string memory) {
  linkMapping[lastLinkId] = LinkTemplate(msg.sender, url);
    emit LinkAdded(lastLinkId, url);
  return(lastLinkId, url);

function getLink(uint linkId) public view returns(address, string memory) {
  LinkTemplate memory link = linkMapping[linkId];
  return(link.userAddress, link.url);

function getLastLink() public view returns(address, string memory, uint) {
  LinkTemplate memory link = linkMapping[lastLinkId];
  return(link.userAddress, link.url, lastLinkId);

Now deploy this contract on local blockchain network:

$ truffle compile
$ truffle migrate
Ganache Screenshot after contract deployment

React Application for interaction with Smart Contract

Open client/src/App.js file & Replace

import SimpleStorageContract from"./contracts/SimpleStorage.json";


import SimpleStorageContract from "./contracts/LinkShortner.json";

Creating new link

contract.methods.createNewLink(this.state.url).send({ from: accounts[0] })

Install Metamask chrome extension

and run React app

cd client
npm run start

Deploying contract on Ropsten test network

- Register new account on infura.io
- Create new project
- Get project api and connection link:

Goto Truffle project, install truffle-hdwallet-provider

npm install truffle-hdwallet-provider — save

Create `.env` file, put MNEMONIC and <network>_URL to file

MNEMONIC=wallet mnemonic 12 words

Update truffle-config with following content

const path = require("path");
const HDWalletProvider = require('truffle-hdwallet-provider')
const MNEMONIC = process.env.MNEMONIC
const ROPSTEN_URL = process.env.ROPSTEN_URLmodule.exports = {
  // See <http://truffleframework.com/docs/advanced/configuration>
  // to customize your Truffle configuration!
  contracts_build_directory: path.join(__dirname, "client/src/contracts"),
  networks: {
    ropsten: {
      provider: function() {
        return new HDWalletProvider(MNEMONIC, ROPSTEN_URL);
      network_id: '3',
    development: {
      host: "",
      port: 7545,
      network_id: "*",
   test: {
     host: "",
     port: 7545,
     network_id: "*",

Run following command to deploy

truffle migrate --network ropsten

Sinatra API for reading Short Link on ethereum network

Create folder backend
Add following content in backend/app.rb

# Require the bundler gem and then call Bundler.require to load in all gems
# listed in Gemfile.
require 'bundler'

require 'sinatra'

require 'ethereum'before do
  content_type 'application/json'

class Contract
  def initialize
    @client = Ethereum::HttpClient.new("https://ropsten.infura.io/v3/<API-KEY>")
    contract_json = JSON.parse(File.read('LinkShortner.json'))
    @contract_abi = contract_json['abi']
    @address = contract_json["networks"]["3"]["address"]
    @client.default_account = "0x3b8B0b23C4850FA8289da815a6abEE4Fc2DF941A"

  def result(id)
    return nil unless id
  enddef contract_instance
    Ethereum::Contract.create(name: "LinkShortner", address: @address, abi: @contract_abi,
                              client: @client)

class App < Sinatra::Base
  get '/url' do
    response.headers["Access-Control-Allow-Origin"] = "*"
    return {url: Contract.new.result(params[:id])}.to_json

Deploy sinatra API on heroku

heroku create
heroku buildpacks:set https://github.com/timanovsky/subdir-heroku-buildpack
heroku buildpacks:add heroku/ruby
heroku config:set PROJECT_PATH=backend
git push heroku master

Now use deployed API for reading short link

fetch("https://<heroku-app-url>/url?id="+id).then((response) => {
  return response.json();
}).then((response) => {
  const url = response.url

That’s it, now you have your link shortner decentralised app deployed on ethereum network. Generated short link can be shared with anyone, irrespective of browser. For creating short link Metamask plugin is required.

Code is hosted on github

Application is hosted at http://anilmaurya.github.io/link-shortner

Demo of Link Shortner




Posted in Blockchain, Tutorials | Tagged , , , | Leave a comment

An Efficient way to manage API calls with RxRetrofit


Android is becoming popular day by day and thousands of apps are being published on Play Store. To survive in this competition, the User experience matters a lot. The app crash is the worst User experience, in other words we can say 1 billion dollar mistake. So I am going to explain how to use RxRetrofit efficiently to make API calls.


The most common mistake made by the Android developer is while making an API call and not handling the fact that the user can exit the app or press the back button, before the API call returns. The result is app crash!

In more detail, when an API is hit, that network call is being performed on the background thread and based on response the UI needs to be updated in UI thread. Now, when the background thread is running and the back button is pressed, the current screen (Activity or Fragment) will be popped out from the stack. After this when data is received from the API and an attempt to update the UI will result in a crash as the current screen (Activity or Fragment) will not be in the stack.


Make API calls using RxRetrofit !!


   .observeOn(AndroidSchedulers.mainThread()) // On UI thread
   .subscribeOn(Schedulers.io()) // On background thread 
   .subscribe({ response -> // On Success 

         // App will crash on the below line
         buttonLogin.setText("Verify OTP")

   }, {
       // On Error (Could not reach to the server)

According to the above example, when you hit the Login API and immediately press the back button (Activity or Fragment removed from the stack) then you get the response from the API in the subscribe() method, you try to update the UI and the app will crash!

Use the Disposable interface of the RxJava which is used with RxRetrofit.

See the below example :

public interface Disposable {
   void dispose();  // Dispose the resource or an operation.
   boolean isDisposed(); // Returns true if this resource has been disposed.

Let’s implement it in the above example,

1) private var disposableLoginAPI: Disposable? = null // Globally
disposableLoginAPI = 
   .observeOn(AndroidSchedulers.mainThread()) // On UI thread
   .subscribeOn(Schedulers.io()) // On background thread 
   .subscribe({ response -> // On Success 

         buttonLogin.setText("Verify OTP")

   }, {
       // On Error (Could not reach to the server)

The subscribe() returns disposable so initialize the disposable with it.

3) override fun onStop() {

     // If it's not disposed then dispose  
    if (disposableLoginAPI?.isDisposed == false) {
         disposableLoginAPI?.dispose() // Magic!

So once you are about to leave the screen (Activity or Fragment), in the onStop() method, dispose() method will dispose the API call and there will be no response in the subscribe() method, so UI will not be updated and the app will not crash.

For Multiple API calls

You can use CompositeDisposable to add multiple disposable objects:

val listOfDisposables=CompositeDisposable() // Init object

//Adding multiple disposables

And finally dispose in the onStop() method.

override fun onStop() {

   listOfDisposables.dispose()  // Dispose all the disposables 

Happy Coding!

Posted in General | Tagged , , | Leave a comment

AWS EC2: Increase volume size on the fly (Using AWS Management Console)

As time passes the production requirements grow. This happens all the time and recently again it happened and I got an alert from Nagios telling me that disk space is getting full. I immediately checked the server to find out what is consuming space!!

Initially, I thought, perhaps unnecessary files are consuming the space. I can just delete those files and get rid of the problem. But on checking it turned out that everything was important to keep in the EBS (Elastic Block Store) volume and nothing can be deleted.

The only solution was to increase the volume size. Thankfully it is AWS. They have enhanced the console to a great extent and increasing the volume size is a piece of cake now. Here are the simple steps:

1) Check the exact volume size which is initially their with ‘lsblk’.

 nvme0n1     259:0    0   50G  0 disk  
 └─nvme0n1p1 259:1    0   50G  0 part / 

This is the exact size of my volume it means 50 GB is available and it is using the exact 50 GB

To increase the volume size follow the below steps:

2) Login to your aws console and than go to the volumes in your EC2 dashboard and find the volume which you want to increase.

3) Select the volume and then click on the ‘Actions’ -> ’Modify Volume’ .

4) Increase the volume size edit the field and enter the new volume size (In my case i want to increase it to 60 GB).

5) Click on the ‘Modify’ button then you can see it will be reflacted to your aws console within a minute but it will be not in use until ‘reboot’.

6) Login to your server and check with ‘lsblk’ you will get to see output as below.

nvme0n1     259:0    0   60G  0 disk  
└─nvme0n1p1 259:1    0   50G  0 part /

Note: This denotes that disk size is 60 GB and 50 GB is allocated to nvme0n1p1.

7) Now to allocate 60 GB to nvme0n1p1 reboot your instance.

CAUTION: While rebooting the instance it will down your service.

8) After rebooting its done now you can check with ‘df -h’. You will see partition is using 60 GB.

/dev/nvme0n1p1   59G  24G   35G  42% /
Posted in General | Leave a comment

Deploy Digital Certificates to the iOS System keychain Store

Content posted here with the permission of the author Amit Dhadse, who is currently employed at Josh Software. Original post available here.

iOS devices became widely used in an enterprise level daily-work now a days, due to this we need to have guaranteed secure communications between device and associated enterprise services.

So question raise about enterprise environment security which can be covered with the help of VPN or any other third party tool. Actually what VPN does is creating secure tunnel between identity device and service which is hosted on cloud or on partner networks.

Thats one part of accessing enterprise service but what if we don’t want to use any VPN client and still wants to access enterprise service from any device in our case we are taking iOS device.One way of doing that is using digital certificates to encrypt/decrypt, sign and authenticate communications and data.So how we can use certificate on iOS device at system level so that iOS can use that certificate while consuming services. Advantage of this over VPN is, User has login every time on VPN Client to consume services where as deploying certificate on iOS device is one time activity and it will work all along till User removed certificate.


I have been asked to create an iOS app to request and deploy digital certificates in device system keychain so that, it will be recognised by all system apps of iOS while accessing enterprise services. After doing my research I concluded that in iOS devices there are two types of certificate keychain stores:

  • App certificates keychain store:
    • This keychain store embedded  in app space and can be used by that app only.(Not exposed at system level)
    • Apple offer APIs to Insert/Delete/Update certificate
  • System certificate keychain store:
    • This keychain is exposed at system level. This store located in Setting -> General -> Profiles used for VPN and wifi networks
    • Apple does not offer any API to deploy/retrieve certificates from the system certificate keychain store (Profiles).

So there are four ways to deploy certificates to system certificate keychain store (not programmatically):

  1. Configuration Profiles: Pre-configured profiles that used to distribute settings.(These can be created on MAC and deploy in iOS device)
  2. Using Simple Certificate Enrolment Protocol (SCEP): this protocol enables Over-the-Air Enrolment of digital certificates, mainly used for routers and switches.
  3. Email Attachment: send the certificate from a desktop or mac to iOS device as an email attachment. Open this attachment(certificate) in iOS mail client ( having system privileges ). It will automatically ask you for installation. 
  4. Using Safari: browse the certificate using Safari. Safari has system privileges over normal UIWebView.

After I did my research I found a workaround that worked for me to deploy a certificate to the System Certificate Store from Xcode directly.

Here’s what you will need to do, first, to create a web-server inside your App, then save the certificate in this web-server and open it’s URL.

When the page launches, Safari will recognize that it’s a certificate, then the System Profiles will pop up and ask the user to install the certificate. After the user install the certificate it will be saved to the Profiles and the certificate can be used in the System level.

To create web server inside iOS app, there are 2-3 libraries are available on Git. I recommend “GCDWebserver” library to create web server due to its easy implementation, background support and most important it is stable.

How to use GCDWebserver :-

    let localServer = GCDWebDAVServer(uploadDirectory: path)
    localServer?.start(withPort: 8080, bonjourName: nil)
    let url = localServer?.serverURL
    • Here “path” is your certificate path(in my case it was document directory path as my certificate was store in document directory(NSDocumentDirectory) folder).
    • “serverURL”  will return URL of certificate which is hosted on local server.
    • Open this URL on safari, Safari recognise that it is certificate and pops an installation alert automatically.

Note :-  Now in this scenario here is one problem, as soon as user open URL in safari, user were no longer in app all control is shift to safari and to comeback in app, user has to do manually.

 Solution :- import “SafariServices” framework which already have a safari view in it which opens safari inside your app.

I spent a lot of time and research efforts to reach upto this solution, I hope someone surly will get benefit from my results. Please contact me for any question.

Posted in General | Tagged , , , , , , | Leave a comment

Adding SSL certificate to Traefik on ECS

Content posted here with the permission of the author Anil Kumar Maurya, who is currently employed at Josh Software. Original post available here.

Traefik is awesome reverse proxy & load balancer. If you are not using Traefik already then I recommend using it in your next project. I can guarantee that you will not regret.

Setting up SSL certificate on Traefik is a cakewalk. While adding SSL on traefik, I realised how it outshine other reverse proxy (Nginx , HAProxy).

Traefik use LetsEncrypt to automatically generate and renew SSL certificates.


FROM      traefik:v1.7-alpine

COPY      traefik_ecs.toml /etc/traefik/traefik.toml
RUN touch /etc/traefik/acme.json
RUN chmod +x /etc/traefik/acme.json


defaultEntryPoints = ["https", "http"]

  address = ":80"
    entryPoint = "https"
  address = ":443"
  address = ":8080"

entryPoint = "bar"
dashboard = true

clusters = ["YOUR_ECS_CLUSTER_NAME"]
watch = true
autoDiscoverClusters = false
refreshSeconds = 15
exposedByDefault = true
region = "YOUR_AWS_REGION"
email = "YOUR_EMAIL"
storage = "acme.json"
entryPoint = "https"
onHostRule = true
entryPoint = "http"

Replace YOUR_* values with actual, build image using Dockerfile and deploy it on ECS. That’s it, Traefik will take care of rest and SSL certificate will be added to your domain. Isn’t Traefik awesome ? Let me know what you think through comments below.


  1. https://www.smarthomebeginner.com/traefik-reverse-proxy-tutorial-for-docker/
  2. https://blog.networkprofile.org/my-traefik-reverse-proxy-setup/
  3. https://github.com/netbears/traefik-cluster-ecs


Posted in General | Tagged , , | Leave a comment

My Internship at Josh

It was during our sixth-semester, that the entire class received an email about the internship at Josh Software Pvt Ltd. We had to attend a coding round, and then two technical rounds followed by an HR round. Being a student of Industrial mathematics course I was not into programming much but still, I decided to appear for the coding round. Overall 40 students came for the internship drive. After the initial round due to some glitch, my name was not in the list of those selected for the next round. This was a major blow to me because I was hoping to make it to the next rounds. As I was about to leave the place with a heavy heart I was informed that I have also cleared the first round. I was literally on cloud nine by this time(So overwhelmed…that I almost shouted at my friend). Then came the technical and HR rounds, I excelled in all of them and ultimately bagged my first ever internship. When I look back the whole selection process itself was a learning experience. I got to know more about myself, my goals, strengths, and weaknesses. The fact that I was the only student from my class and the only female candidate who was awarded the internship helped in firmly establishing my belief in myself.

After joining as an intern at Josh, I went through a rigorous 10 days training. I learned and relearned a lot of stuff. It was exhausting and scary at the same time. The feeling of vulnerability and inadequacy would come now and then. One thing which helped me initially in gelling out with the people at Josh was the new year’s party.

My first office party!!

All the interns were introduced to the other team members at Josh. The environment at the party was very chill. From co-founders to new appointees everyone was present there and was enjoying freely. This was an ice-breaking moment for me because I realized that your work is all that matters. As long as you are doing your work sincerely, you don’t need to be scared of anyone. It doesn’t matter whether you are experienced or fresher. Also being an intern all I wanted was an environment where there is room for mistakes, improvements and a place where people are approachable. One thing which standout for Josh is its amazing work culture. It’s so conducive for one’s overall growth.

After a while, I was assigned a project manager and a mentor. I was very nervous and especially when I and my partner were called by our project manager Anil Kumar and mentor Rahul Ojha. We were asked to complete an assignment which was full of technical jargon. Being a naive programmer I was scared to death when I was asked for this. I requested them that I need time because I have never attempted such an assignment before. To my surprise, they understood and told me to start with elementary assignments. It took a lot of mistakes, learning and brainstorming sessions with Rahul but ultimately I was able to complete my assignment. This was a huge achievement for me. The way I was being monitored by my mentor was amazing. He was not just spoon feeding but was giving me hints about what to learn and where to look for the answers. It was like a puzzle. I enjoyed it thoroughly.
The first project was finally given to me and my partner after carefully analyzing our performances. We were working on the rails technology and were asked to make an app. From being a student to an intern to my first client meeting. It was a roller coaster ride. I got a chance to directly communicate with the client. It was a humbling experience. For the first time, I felt like I am an integral part of Josh and have been given responsibilities for which I am accountable.

Presently my project is at the fag end of completion. I would be lying if I say it was an easy journey from beginning to this end. There were many ups and downs. Often I found myself in the position where I couldn’t decide how to go about the problem. When one is not able to even pinpoint the problem, finding the solution is a different problem altogether to solve. But then a word with Anil or others would dissipate the clouds of dismay. Things became easier for us because we could ask our doubts to anyone and everyone was ready to help us with full enthusiasm.

I could mention so many incidents where I was helped by my team like the one time I was frustrated with the pace at which I was completing my work. This was hampering my performance also. I was like what I am even doing here. This is not for mathematics students and is tailor-made for computer science students. Like a cold breeze on a hot day, Rahul’s advice would come to stick with the problem and that with extra effort I could solve my problem. God and only he knows how much I have troubled him by my doubts. Shailesh for whom I had this impression that he is very reserved and strict proved me wrong by laughing at the memes I used to show him. The attitude of Ganesh whenever he sees a problem often leaves me speechless. His statement “ab to isko solve karenge hi” works like glucose. It provides immense energy to tackle any problem. Sahil’s perseverant attitude always pushed me to have the same tenacity on my work too. I still remember one talk delivered by Mr. Gautam Rege(Co-founder of Josh), it was accessible to anyone and was very motivating. All one needs at the start of his career is ample support and motivation. I really look up to you sir. Thank you for being so inspiring and motivating.

As I have mentioned earlier, the one thing which standout at Josh is its work culture. It’s a perfect blend of professionalism and flexibility. One gets appreciated for good work and at the same time, you can’t take your work for granted. I remember the numerous times I have been rebuked for my mistakes and also appreciated for my good work. My participation as a trainer during one of Rails girls meet up was appreciated in All hands. These little acts worked as a catalyst for my growth.

How many times does an intern get the chance to share lunch with co-founders? Yes, not many times but at Josh, the environment is very congenial. The monotonous office culture would sometimes take a toll on us and to kill the boredom we-the music lovers-would start playing songs. Instead of not allowing us Neha and Sai would just advice us to slightly lower the volume. The other thing which came to our rescue was carrom. I am nowhere qualified even to tell myself a naive player. The probability that I would not hit the piece I am targeting was more than I hit it. I was casually made fun of my bad shots by Mr. Umesh and Mr.Swapnil but now it seems that along with programming skills, I have also honed up my carrom skills.
This blog has been the hardest to write for me by far. In part, the challenge stems from trying to sum up months worth of experiences in just a few paragraphs.
My internship at Josh software has taught me more than I could have imagined. As an Intern, I feel my duties were diverse and ever-changing. Sometimes it’s tough to recall everything I have taken in over the past months, but I feel that these are some of the most beneficial lessons I have learned.

What I’ve Learned:

I’m not alone: Coming into this position, I felt that I had no idea where my career was going and I lacked confidence about what I could do and what I am really good at. My internship has definitely given me a better understanding of my skill set and where my career may take me, but most importantly, I’ve come to learn that I am not alone. This job has taught me that almost everybody is in the same position. Very few college students know what they want to do, and it is something that is simply not worth worrying about. Thanks to my internship I now know that if I continue to work hard things will fall into place.

How to behave in the office: This being my first position in an office atmosphere, I didn’t know exactly what to expect. The environment here at Josh is quite relaxed, yet it taught me how to behave in the workplace. Simply working in the office and getting used to everything here has definitely prepared me for whatever my next position may be. Just observing the everyday events has taught me more about teamwork, and how people can come together to get things done. Although sometimes I have to remind myself to use my inside voice, I feel I’ve adapted to office life relatively well.

How to build my resume: As I said, this internship has improved my skills a ton, both off the paper and on paper. I didn’t realize it all of this time, but this position served not only as a positive learning experience but a resume builder as well. I came into this with a resume that was basically naked, now I am leaving and I have lots of updating to do. My resume doesn’t need a makeover, it needs to be restarted from scratch, and that’s a good thing! I underestimated how much work I did that actually translates to my resume.

I’d like to thank everyone here at Josh who has helped me out. This has truly been a great learning experience and I’ll be forever indebted to those who gave me a hand here. As far as future interns are concerned I would advice to always be friendly, work hard, and ask questions. Always ask questions. Hopefully, you come away from your internship with as much as I did.

Posted in General | Leave a comment