Simple letter replacement translator into Viking Runes.
A fine line separates fishing from standing on the shore like an idiot
Simple letter replacement translator into Viking Runes.
(Version 1.0)
The Student Loan Calculator is intended to help with student loan repayment planing when things are not just simple and static. For professions such as physicians with federal loans, income based repayment may be available with loan forgiveness at the end of the initial loan period. Physicians are also commonly expected to have a huge jump in their income level at some point during the original loan period. I have come in contact with some misleading information around these topics and often “back-of-the-envelope” calculations fail to capture the basic scope of the problem.
I’m not a financial expert, I’m not giving any official financial advice, but I am an engineer, scientist, and proficient at maths. My family and I have some skin in this game of student loans and I got tired of getting half answers and relying on just intuition despite good success. Therefore, I created this little tool to help get some reasonable financial estimates and gain some insight into problems similar to mine and perhaps also yours. It’s not a perfect tool but I think the estimates are good enough to inform some of my personal and family financial decisions.
After describing the loan parameters, the following repayment plans are considered
Comparison Results of the repayment plan calculations are presented in a small graph.
Saving/Investment comparisons are also presented
The link below the “Comparison Results” section provides a url link with your current settings of the calculator that can be used to save or share results.
The following sections describe the repayment plans and the workings of the calculator.
This is the nominal plan if you can afford it.
This is likely the best plan if you can afford more than the minimum payment.
This is the same as the aggressive plan but in two phases. If you expect to have a huge jump in income during the loan period, you are likely to be able to afford to pay more at a later date.
For example, if you are a physician resident earning a 1/4 of your minimum expected pay in 3–5 years.
If you have a drop in disposable income during your loan period, you may afford to pay less extra at a later date.
For example, due to foreseeable life events such as loss of employment, relocation, or expanding your family, all of which may reduce your disposable income. These cases can also be modeled here by lowering the extra payment or possibly taking advantage of a lower minimum monthly payment needed to complete paying off the loan on time, assuming the terms of your loan allows for that (they should, assuming you were allowed to pay towards the capital of the loan).
Some loans allow for income based repayment, possibly lower than the minimum payment on the loan in order to pay it back on time. Furthermore, if there is a remaining balance at the end of the loan period, that balance is forgiven. For example, a physician may work for a non-profit organization and at the end of the loan period, may have been working there long enough to qualify for loan forgiveness.
The motivating example for this is if a person has the option to live frugally enough to make extra payments but might also qualify for forgiveness. What will allow for minimum total payment? Will faster repayment be sufficient to result in a lower overall payment than to take advantage of potential forgiveness at the end of the loan period.
Special Case: If the income based repayment is less than the interest being accrued on the loan, then the nominal case is that the unpaid interest is added to the principal. In the “Other Results/Comments/Warnings” text field, an alternative case is computed where the remaining interest is forgiven. There are certain loans and repayment plans that correspond to this case. There are also loans where 50% of the remaining interest is forgiven but that case is not considered here. The total payment for such a loan will be somewhere between the nominal and the interest forgiven cases that are considered.
The length of the bars shown are proportional to the total amount paid under each repayment plan, as indicated by the text on each bar. The text at the end of the bar restates the amount.
This allows for a quick comparison of the total amount paid under all the plans and helps evaluate which one fits your finances best, or if the differences are small enough for you to rather be guided by other life goals.
Savings/Investments comparisons are also made and are discussed in the next section.
This is attempting an apples-to-apples comparison given that you can afford the aggressive repayment plan and that you can sustain paying the original minimum payment throughout original loan period.
For example, if you can afford the minimum repayment plan throughout the loan period but are able to live extra frugally for a while and execute the aggressive plan. How much will you have saved on each plan if you put your extra funds towards savings/investments.
The length of the bars show the savings accumulated on each plan according to the list below. The text shows the total savings.
This is attempting an apples-to-apples comparison assuming you can afford the aggressive repayment plan throughout the original loan period.
For example, if you can afford the aggressive repayment plan throughout the original loan period: How much will you have saved on each plan if you put your extra funds towards savings/investments throughout the original loan period.
The length of the bars show the savings accumulated on each plan according to the list below. The text shows the total savings.
I had  my little workout timer app all written out nice and neat, with little beeps for breaks and starts.  But I heard nothing on my iPad.  I find out mobile Safari doesn't support automatically played audio, it must be initialized by the user. Soon after, I see there are ways around the limitation.  With other people providing more details.  My thanks for their help and input which I rely on below.
I wanted it simple and "easy", so I boiled it all down.
Using Audacity or other audio editor, record/combine/edit/track your audio clips all together in one file such that:
Export the audio sprites file to a compatible format, e.g., Â .mp3 or .m4a (I used .m4a in the example).
The HTML includes assigning the audio source (here the file is named "12345.m4a")
[code language="html"]<audio id="audio"> <source src="12345.m4a" type="audio/mp4" /> </audio>
[/code]
The Javascript has the following commented setup near the top.  The "spriteData" contains the names of the clips/sprites, their start time in sec, and their length.  This particular audio sprite file is a sequence of counts from one to five, each starting at their respective second and 0.5sec long.  The "currentSprite" will be used to keep track of the current sprite begin played or most recently played.
[code language="javascript"]// Audio Sprite Setup
// Get the sprite element
var audioSprite = document.getElementById('audio');
// Assign the sprite data (field names for id, start time of the clip in sec and length in sec)
// Place a silence at the beginning and end of the clip (about a second each) as a buffer to avoid undesired playback or termination due to inaccuracy in audio timing due to the browser
var spriteData = {
// Always have the first second silence and named "silence"
silence: {start: 0.0, length: 0.5},
one: {start: 1, length: 0.5},
two: {start: 2, length: 0.5},
three: {start: 3, length: 0.5},
four: {start: 4, length: 0.5},
five: {start: 5, length: 0.5}
};
// current sprite being played
var currentSprite = {};
// End Audio Sprite Setup
[/code]
Then somewhere below it has the remaining setup for playing the sprite, commented for clarity.
[code language="javascript"]// AUDIO SPRITE HANDLING
// time update handler to ensure we are in the current sprite and stop when it is complete
var onTimeUpdate = function() {
var timing_tolerance = 0.2; // .currentTime is not accurate, set this as the tolerance for its inaccuracy
// If at the end of the current sprite, then pause
if (this.currentTime >= currentSprite.start + currentSprite.length) {
this.pause();
}
// If playing but not in the current sprit, then go there (this can occure due to iOS timing issues and start playing from the start of the sprite file unintentionally)
else if (this.currentTime < currentSprite.start-timing_tolerance) {
audioSprite.currentTime = currentSprite.start;
}
};
// Set listener for timeupdate to have the currentTime be in the current sprite
audioSprite.addEventListener('timeupdate', onTimeUpdate, false);
// in mobile Safari, the first time this is called will load the audio. Ideally, we'd load the audio file completely before doing this.
// This function needs to be called first from a user touch event such as onmousedown, onmouseup, onclick, or ontouchstart.
var playSprite = function(id) {
if (spriteData[id] && spriteData[id].length) {
currentSprite = spriteData[id];
audioSprite.currentTime = currentSprite.start;
audioSprite.play();
}
};
var playSpriteInitialize = function(){
playSprite('silence');
// Whatever code you want first executed
//...
};
[/code]
That's all. Â As long as "playSprite" or "playSpriteInitialize" are called using a button first (or other compatible event), then the sprites can be played programmatically from that point on using
[code language="javascript"]playSprite["name_of_clip"][/code]
Note that the "currentTime" is not accurate to within about 0.2 or maybe even more seconds. Â So this solution may have some limits if vary rapid audio transitions are needed.
Here is a little code snip wrapped with HTML/CSS to play a count from 1 to 5 using text and audio. Â The proof of concept is in that once you push the start button once, the program is able to use "setInterval" to automatically/programmatically play the count from the audio sprite file.
Here is the complete code for the example:
[code language="javascript"]
<!DOCTYPE html>
</html>
<audio id="audio"> <source src="12345.m4a" type="audio/mp4" /> </audio>
<button onclick="start_count();">Start Counting</button>
<button onclick="stop_count();">Stop Counting</button>
<div id="count_txt"> --- </div>
<script>
// Audio Sprite Setup
// Get the sprite element
var audioSprite = document.getElementById('audio');
// Assign the sprite data (field names for id, start time of the clip in sec and length in sec)
// Place a silence at the beginning and end of the clip (about a second each) as a buffer to avoid undesired playback or termination due to inaccuracy in audio timing due to the browser
var spriteData = {
// Always have the first second silence and named "silence"
silence: {start: 0.0, length: 0.5},
one: {start: 1, length: 0.5},
two: {start: 2, length: 0.5},
three: {start: 3, length: 0.5},
four: {start: 4, length: 0.5},
five: {start: 5, length: 0.5}
};
// current sprite being played
var currentSprite = {};
// End Audio Sprite Setup
// DEMO ------------------------------------------
var myTimer = {}; // Initialize variable used for timers
var counter = 0; // Initialize counter
var Ncounter = 5; // Up to how many counts
// Assign audio sprite according to the counter, and increment
function sound_count(){
var ids = ["one","two","three","four","five"]; // Array of the sprite names
counter = (counter%Ncounter); // make sure counter is in bounds
playSprite(ids[counter]); // play sprite
document.getElementById('count_txt').innerHTML = ids[counter]; // show counter
counter++; // increment counter
}
// Start a count on a timer
function start_count(){
clearInterval(myTimer); // Clear timer if in case it was already running
myTimer = setInterval(sound_count,1000); // Set timer to run the sound count every 1000ms
}
// End a count
function stop_count(){
clearInterval(myTimer);
}
// End DEMO ------------------------------------------
// AUDIO SPRITE HANDLING
// time update handler to ensure we are in the current sprite and stop when it is complete
var onTimeUpdate = function() {
var timing_tolerance = 0.2; // .currentTime is not accurate, set this as the tolerance for its inaccuracy
// If at the end of the current sprite, then pause
if (this.currentTime >= currentSprite.start + currentSprite.length) {
this.pause();
}
// If playing but not in the current sprit, then go there (this can occure due to iOS timing issues and start playing from the start of the sprite file unintentionally)
else if (this.currentTime < currentSprite.start-timing_tolerance) {
audioSprite.currentTime = currentSprite.start;
}
};
audioSprite.addEventListener('timeupdate', onTimeUpdate, false);
// in mobile Safari, the first time this is called will load the audio. Ideally, we'd load the audio file completely before doing this.
// This function needs to be called first from a user touch event such as onmousedown, onmouseup, onclick, or ontouchstart.
var playSprite = function(id) {
if (spriteData[id] && spriteData[id].length) {
currentSprite = spriteData[id];
audioSprite.currentTime = currentSprite.start;
audioSprite.play();
}
};
var playSpriteInitialize = function(){
playSprite('silence');
// Whatever code you want first executed
//...
};
// End Audio Sprite Setup
</script>
</html>
[/code]