I am trying to modify an existing code that adds credits to a user's account based on the amount they paid. Currently, the code adds an unclear number of credits by dividing the amount paid by 12. I would like to add 500 credits for every $29 paid. How can I modify the code to achieve this?
Here is the code that I am working with
const models = require("../models")
const User = models.user;
const invoice = async (eventType,data) => {
if (!eventType.includes("invoice")) {
return // not a subscription event
}
paid(eventType,data)
}
const paid = async (eventType,data) => {
if (!eventType.includes("invoice.paid")) {
return // not a subscription event
}
const { object } = data
console.log(eventType)
let credits = 0
// 500 credits for $30
if(object.amount_paid > 2900){
credits += (object.amount_paid / 12)
}
if(object.amount_paid > 8900){
credits += (object.amount_paid / 12)
}
let user = await User.findOne({
customerId: object.customer
})
I changed the code to add 500 credits for every $29 paid by using the following logic:
if (object.amount_paid >= 2900) {
credits += Math.floor(object.amount_paid / 29) * 500;
}
This checks if the "amount_paid" property of the "object" variable is greater than or equal to 2900 (since 2900 cents is equal to $29). If it is, it calculates the number of times 29 can go into the "amount_paid" by using the JavaScript Math.floor() function which rounds down to the nearest integer. This result is then multiplied by 500 to get the number of credits to be added to the user's account.
Regarding the value of 2900, in order to get 500 by dividing 2900, I would need to divide it by 5.8333 approximately, but as I said before, this is not the right way to get the number of credits that the user should get.
I am trying to create a Countup counter Starting from 1 to 10000 and i do not want it to reset when user refreshes the page or cancels the page. The Counter should start from 1 for every user that visits the page and keep running in background till it gets to 10000 even if the page is closed.
I have written the page below which;
Starts from the specified number for every new visitor
Saves the progress and does not reset when page is refreshed, however
It does not keep counting when page is closed and starts from the last progress when user closes the tab and comes back later. My code is
function countUp() {
var countEl = document.querySelector('.counter');
var countBar = document.querySelector('.progress-bar');
var x = parseInt(localStorage.getItem('lastCount')) - 1 || 1;
var y = countEl.dataset.to;
var z = countBar.dataset.to;
function addNum() {
countEl.innerHTML = x;
x += 1;
if (x > y && x > z) {
clearInterval(timer);
}
localStorage.setItem('lastCount', x);
}
var timer = window.setInterval(addNum, 1000);
localStorage.setItem("addNum", counter);
toggleBtn.addEventListener('click', function(){
countUp();
toggleBtn.classList.add('hidden');
});
}
countUp();</script>
<body onload=countUp();>
<div class="counter" data-from="0" data-to="10000000"></div>
<div class="progress-bar" data-from="0" data-to="10000000"></div>
</body>
It's difficult to show an example on StackOverflow because it doesn't let you fiddle with localStorage but, it sounds like you want something like:
When a user visits the page check localStorage for a timestamp.
If timestamp exists, go to step 4
Timestamp doesn't exist so get the current timestamp and stash it in localStorage.
Get the current timestamp. Subtract the timestamp from before. If over 10,000, stop, you're done.
Display difference calculated in step 4.
Start a 1 second timer, when time is up, go to step 4.
Something along those lines should work even if they refresh the page and since you are calculating from the original timestamp it will "count" in the background even if the page is closed.
window.addEventListener("DOMContentLoaded", () => {
const start = localStorage.getItem("timestamp") || Date.now();
localStorage.setItem("timestamp", start);
function tick() {
const now = Date.now();
const seconds = Math.floor((now - start) / 1000);
const display = document.getElementById("display");
if (seconds > 10000) return display.innerHTML = "We're done";
display.innerHTML = seconds;
setTimeout(tick, 1000);
}
tick();
});
<div id="display"></div>
So, client-side code can't normally execute when a client-side javascript page is closed.
What you could do, however, is calculate where the timer should be then next time it is loaded.
For example, in your addNum() function, you could in addition to the last count, also store the current date (and time).
function addNum() {
countEl.innerHTML = x;
x += 1;
if (x > y && x > z) {
clearInterval(timer);
}
localStorage.setItem('lastCount', x);
localStorage.setItem('lastDate', new Date());
}
Then, when your code starts, you can retrieve lastDate, and then subtract the current Date() from it.
Then use that to add the difference to your counter.
function countUp() {
let storedCount = parseInt(localStorage.getItem('lastCount'));
let storedDate = Date.parse(localStorage.getItem('lastDate'));
let now = new Date()
let diffSeconds = (now.getTime() - storedDate.getTime()) / 1000;
let storedCount += diffSeconds;
var countEl = document.querySelector('.counter');
var countBar = document.querySelector('.progress-bar');
var x = storedCount - 1 || 1;
var y = countEl.dataset.to;
var z = countBar.dataset.to;
}
I'm sure there are some more changes required to make it work with your code, but the idea is to store the current time so that when the page is closed and reopened, you can 'adjust' the count to catch up to what it should be.
What you want here is not possible just from the client-side code, there is no way for 2 different machines to share that information at all.
Here's the thing though, you can do this with a backend where the database gets updated every time a new IP hits the server. Note with this approach, a user here is one system and not different browsers or sessions.
To update this real-time for someone who is already on the website, run a timer and call an API that specifically gives you the count. Therefore the page gets updated frequently. You can also do this with react-query as it comes with inbuilt functions to do all this.
I have four '.dist' elements. They have a different preloaded data (exactly: 57 , 27 , 17 , 244). I want to animate incrementing, and I wrote this code:
$('.dist').each(function() {
var count = parseInt($(this).text())
var incr = 0
var that = $(this)
var animation_time = 500
var interv = animation_time / count
$(this).text('0')
var fd = setInterval(function() {
if (incr < count){
incr++
that.text(parseInt(incr))
}
} , interv)
console.log(interv)
})
The problem: The biggest value finishes 100 light years after the rest.
Console.log (directly from this code) returns:
8.928571428571429
18.51851851851852
29.41176470588235
2.0491803278688523
Thats the values which I/We expected, but I think every interval has a specific delay, but I dont't know how to detect and correct that delay.
I want to finish all of incrementations from 0 to 'var count' in time ~= 500ms. I want to start all of incrementations in the same time, and finish every one in the same time.
Sorry for my primitive querstion but I started my adventure with js/jq only 6 months ago, and I can't find the answer by google. Maybe I'm retarted or something. Thanks for help.
edit: html
<div class="info back2 border corners1">
<span class="dist">56</span> seriali<br>
<span class="dist">27</span> obejrzanych<br>
<span class="dist">17</span> oczekuje<br>
<span class="dist">244</span> sezonów<br>
</div>
You have two problems: One is that you end up with a very small interval, and second that the calculated interval becomes a float. SetInterval can only handle whole milliseconds, not fractions, so your calculation will always be off. Better to set a start and end time and calculate the difference.
This is the most accurate way to do time calculations in Javascript anyways.
$('.dist').each(function() {
var count = parseInt($(this).text());
var incr = 0;
var that = $(this);
var animation_time = 500;
$(this).text('0');
var time_start = new Date();
var fd = setInterval(function() {
var time_passed = new Date() - time_start;
if (time_passed >= animation_time) {
clearInterval(fd);
time_passed = animation_time;
}
that.text(Math.round(count*time_passed/animation_time));
} , 10);
})
http://jsfiddle.net/xau91msr/
Or if you don't care about the actual time for the animation and want browser stutters etc to not count as passed time you can increment time_passed yourself:
http://jsfiddle.net/jevjyf3m/
If you have a fixed number of steps and increment proportionally, then your counts will reach their ends together, also don't forget to clear the interval once the animation is complete.
http://jsfiddle.net/rtvtdasz/10
clearInterval(fd);
I need to track how many users have visited some page in the past 24 hours, and if the number of users goes over 50 in this time, then I want to display the dynamically summed cumulative user count for that timeframe.
I have previously used a basic combination of JS POST and PHP parsing on the back end like this:
$.post( "//api.link.here/using.php", { someParameter: 'xxx' }, function(data) {
if(data > 50) {
$('#much-visits').html('Hot Like Fire: '+data);
}
});
But am now working on a platform that doesn't allow me to edit PHP in any way, and this method has not been developed on this platform.
The Question:
Is it possible to accomplish this same/similar thing but with javascript only (frameworks/outside API calls allowed)?
It's impossible to do it solely using client-side JavaScript, because then you wouldn't have any unified record of how many visitors came to the site. You must have either a server-side element or a third-party element (such as Google Analytics).
Actually, you can! You need jQuery though, so if you can get that, you're good to go!
Every time a person visits the page, execute this function (change usercount to something more unique):
$.ajax({
url:"http://count.io/vb/usercount/users+",
type: "POST"
});
And when you want to read its value, call this function. Usercount is the unique string you made previously:
$.ajax({
url:"http://count.io/vb/usercount/",
success: function(data) {
alert(data.counts[0].count);
}
});
It's important to know that if someone gets to know the string, they might be able to hack the system so be wary of that.
I figured out how to do this with the help of user kabiroberai's answer regarding count.io.
Every time a person visits the page, execute this function (change usercount to something more unique):
$.ajax({
url:"http://count.io/vb/usercount/users+",
type: "POST"
});
And when you want to read its value, call this function. Usercount is the unique string you made previously:
$.ajax({
url:"http://count.io/vb/usercount/",
success: function(data) {
alert(data.counts[0].count);
}
});
NOTE: It's important to know that if someone gets to know the string, they might be able to hack the system so be wary of that.
The problem with this method is that it gives us the total count of all time, rather than the count of users from the past 24 hours.
To get the 24-hour count, we can do this:
// Timestamp shim for browsers
// Timestamp
var timestamp = Math.floor(Date.now());
// 24 hour old timestampt
var dayAgo = timestamp - 86400000;
// Record a hit to the count.io DB under DankStopProduct# group, as a timestmped hit of 1
var productNumber = $('.some-product-element').find('some-unique-identifier').attr('value'); //Doesn't have to be value, could be any unique identifier
$.ajax({
url:'http://count.io/vb/YourProduct' + productNumber + '/' + timestamp + '+',
type: 'POST'
});
// Make dynamic HTTP prefix that depends on the prefi of the site's current page protocol
var httpPrefix = (window.location.protocol === 'http:' ? 'http:' : 'https:');
// Retrieve current product array
$.post(
//I use CORS-anywhere to retrieve the data as otherwise there is a cross-origin problem
httpPrefix + '//cors-anywhere.herokuapp.com/' + 'http://count.io/vb/YourProduct' + productNumber,
function (data) {
var timedViewCounter = 0;
var myStringArray = data.counts;
var arrayLength = myStringArray.length;
// Check each "timestamped hit" in the current product's array to see if it's older than 24 hours
for (var i = 0; i < arrayLength; i++) {
var itemTimestamp = data.counts[i].item;
// Count up all the product hits that are 24 hours old or newer
if (itemTimestamp > dayAgo) {
timedViewCounter++;
}
}
// If total count is greater than 50, then output HTML onto page
var hotItem = '<div id="hot-item"><strong><i class="fa fa-fire"></i> Hot Like Fire!</strong> - ' +
'<span class="view-count">' + timedViewCounter + '</span> people have viewed this product in the last 24 hours</div>';
if (timedViewCounter > 50) {
$(".FreeShippingContainer").before(hotItem);
}
});
And that's all! Now the product view count will only be output if it's 51 views or higher in the past 24 hours.
I could use some pseudo-code, or better, Python. I am trying to implement a rate-limiting queue for a Python IRC bot, and it partially works, but if someone triggers less messages than the limit (e.g., rate limit is 5 messages per 8 seconds, and the person triggers only 4), and the next trigger is over the 8 seconds (e.g., 16 seconds later), the bot sends the message, but the queue becomes full and the bot waits 8 seconds, even though it's not needed since the 8 second period has lapsed.
Here the simplest algorithm, if you want just to drop messages when they arrive too quickly (instead of queuing them, which makes sense because the queue might get arbitrarily large):
rate = 5.0; // unit: messages
per = 8.0; // unit: seconds
allowance = rate; // unit: messages
last_check = now(); // floating-point, e.g. usec accuracy. Unit: seconds
when (message_received):
current = now();
time_passed = current - last_check;
last_check = current;
allowance += time_passed * (rate / per);
if (allowance > rate):
allowance = rate; // throttle
if (allowance < 1.0):
discard_message();
else:
forward_message();
allowance -= 1.0;
There are no datastructures, timers etc. in this solution and it works cleanly :) To see this, 'allowance' grows at speed 5/8 units per seconds at most, i.e. at most five units per eight seconds. Every message that is forwarded deducts one unit, so you can't send more than five messages per every eight seconds.
Note that rate should be an integer, i.e. without non-zero decimal part, or the algorithm won't work correctly (actual rate will not be rate/per). E.g. rate=0.5; per=1.0; does not work because allowance will never grow to 1.0. But rate=1.0; per=2.0; works fine.
Use this decorator #RateLimited(ratepersec) before your function that enqueues.
Basically, this checks if 1/rate secs have passed since the last time and if not, waits the remainder of the time, otherwise it doesn't wait. This effectively limits you to rate/sec. The decorator can be applied to any function you want rate-limited.
In your case, if you want a maximum of 5 messages per 8 seconds, use #RateLimited(0.625) before your sendToQueue function.
import time
def RateLimited(maxPerSecond):
minInterval = 1.0 / float(maxPerSecond)
def decorate(func):
lastTimeCalled = [0.0]
def rateLimitedFunction(*args,**kargs):
elapsed = time.clock() - lastTimeCalled[0]
leftToWait = minInterval - elapsed
if leftToWait>0:
time.sleep(leftToWait)
ret = func(*args,**kargs)
lastTimeCalled[0] = time.clock()
return ret
return rateLimitedFunction
return decorate
#RateLimited(2) # 2 per second at most
def PrintNumber(num):
print num
if __name__ == "__main__":
print "This should print 1,2,3... at about 2 per second."
for i in range(1,100):
PrintNumber(i)
A Token Bucket is fairly simple to implement.
Start with a bucket with 5 tokens.
Every 5/8 seconds: If the bucket has less than 5 tokens, add one.
Each time you want to send a message: If the bucket has ≥1 token, take one token out and send the message. Otherwise, wait/drop the message/whatever.
(obviously, in actual code, you'd use an integer counter instead of real tokens and you can optimize out the every 5/8s step by storing timestamps)
Reading the question again, if the rate limit is fully reset each 8 seconds, then here is a modification:
Start with a timestamp, last_send, at a time long ago (e.g., at the epoch). Also, start with the same 5-token bucket.
Strike the every 5/8 seconds rule.
Each time you send a message: First, check if last_send ≥ 8 seconds ago. If so, fill the bucket (set it to 5 tokens). Second, if there are tokens in the bucket, send the message (otherwise, drop/wait/etc.). Third, set last_send to now.
That should work for that scenario.
I've actually written an IRC bot using a strategy like this (the first approach). Its in Perl, not Python, but here is some code to illustrate:
The first part here handles adding tokens to the bucket. You can see the optimization of adding tokens based on time (2nd to last line) and then the last line clamps bucket contents to the maximum (MESSAGE_BURST)
my $start_time = time;
...
# Bucket handling
my $bucket = $conn->{fujiko_limit_bucket};
my $lasttx = $conn->{fujiko_limit_lasttx};
$bucket += ($start_time-$lasttx)/MESSAGE_INTERVAL;
($bucket <= MESSAGE_BURST) or $bucket = MESSAGE_BURST;
$conn is a data structure which is passed around. This is inside a method that runs routinely (it calculates when the next time it'll have something to do, and sleeps either that long or until it gets network traffic). The next part of the method handles sending. It is rather complicated, because messages have priorities associated with them.
# Queue handling. Start with the ultimate queue.
my $queues = $conn->{fujiko_queues};
foreach my $entry (#{$queues->[PRIORITY_ULTIMATE]}) {
# Ultimate is special. We run ultimate no matter what. Even if
# it sends the bucket negative.
--$bucket;
$entry->{code}(#{$entry->{args}});
}
$queues->[PRIORITY_ULTIMATE] = [];
That's the first queue, which is run no matter what. Even if it gets our connection killed for flooding. Used for extremely important things, like responding to the server's PING. Next, the rest of the queues:
# Continue to the other queues, in order of priority.
QRUN: for (my $pri = PRIORITY_HIGH; $pri >= PRIORITY_JUNK; --$pri) {
my $queue = $queues->[$pri];
while (scalar(#$queue)) {
if ($bucket < 1) {
# continue later.
$need_more_time = 1;
last QRUN;
} else {
--$bucket;
my $entry = shift #$queue;
$entry->{code}(#{$entry->{args}});
}
}
}
Finally, the bucket status is saved back to the $conn data structure (actually a bit later in the method; it first calculates how soon it'll have more work)
# Save status.
$conn->{fujiko_limit_bucket} = $bucket;
$conn->{fujiko_limit_lasttx} = $start_time;
As you can see, the actual bucket handling code is very small — about four lines. The rest of the code is priority queue handling. The bot has priority queues so that e.g., someone chatting with it can't prevent it from doing its important kick/ban duties.
to block processing until the message can be sent, thus queuing up further messages, antti's beautiful solution may also be modified like this:
rate = 5.0; // unit: messages
per = 8.0; // unit: seconds
allowance = rate; // unit: messages
last_check = now(); // floating-point, e.g. usec accuracy. Unit: seconds
when (message_received):
current = now();
time_passed = current - last_check;
last_check = current;
allowance += time_passed * (rate / per);
if (allowance > rate):
allowance = rate; // throttle
if (allowance < 1.0):
time.sleep( (1-allowance) * (per/rate))
forward_message();
allowance = 0.0;
else:
forward_message();
allowance -= 1.0;
it just waits until enough allowance is there to send the message. to not start with two times the rate, allowance may also initialized with 0.
One solution is to attach a timestamp to each queue item and to discard the item after 8 seconds have passed. You can perform this check each time the queue is added to.
This only works if you limit the queue size to 5 and discard any additions whilst the queue is full.
Keep the time that the last five lines were sent. Hold the queued messages until the time the fifth-most-recent message (if it exists) is a least 8 seconds in the past (with last_five as an array of times):
now = time.time()
if len(last_five) == 0 or (now - last_five[-1]) >= 8.0:
last_five.insert(0, now)
send_message(msg)
if len(last_five) > 5:
last_five.pop()
If someone still interested, I use this simple callable class in conjunction with a timed LRU key value storage to limit request rate per IP. Uses a deque, but can rewritten to be used with a list instead.
from collections import deque
import time
class RateLimiter:
def __init__(self, maxRate=5, timeUnit=1):
self.timeUnit = timeUnit
self.deque = deque(maxlen=maxRate)
def __call__(self):
if self.deque.maxlen == len(self.deque):
cTime = time.time()
if cTime - self.deque[0] > self.timeUnit:
self.deque.append(cTime)
return False
else:
return True
self.deque.append(time.time())
return False
r = RateLimiter()
for i in range(0,100):
time.sleep(0.1)
print(i, "block" if r() else "pass")
Just a python implementation of a code from accepted answer.
import time
class Object(object):
pass
def get_throttler(rate, per):
scope = Object()
scope.allowance = rate
scope.last_check = time.time()
def throttler(fn):
current = time.time()
time_passed = current - scope.last_check;
scope.last_check = current;
scope.allowance = scope.allowance + time_passed * (rate / per)
if (scope.allowance > rate):
scope.allowance = rate
if (scope.allowance < 1):
pass
else:
fn()
scope.allowance = scope.allowance - 1
return throttler
How about this:
long check_time = System.currentTimeMillis();
int msgs_sent_count = 0;
private boolean isRateLimited(int msgs_per_sec) {
if (System.currentTimeMillis() - check_time > 1000) {
check_time = System.currentTimeMillis();
msgs_sent_count = 0;
}
if (msgs_sent_count > (msgs_per_sec - 1)) {
return true;
} else {
msgs_sent_count++;
}
return false;
}
I needed a variation in Scala. Here it is:
case class Limiter[-A, +B](callsPerSecond: (Double, Double), f: A ⇒ B) extends (A ⇒ B) {
import Thread.sleep
private def now = System.currentTimeMillis / 1000.0
private val (calls, sec) = callsPerSecond
private var allowance = 1.0
private var last = now
def apply(a: A): B = {
synchronized {
val t = now
val delta_t = t - last
last = t
allowance += delta_t * (calls / sec)
if (allowance > calls)
allowance = calls
if (allowance < 1d) {
sleep(((1 - allowance) * (sec / calls) * 1000d).toLong)
}
allowance -= 1
}
f(a)
}
}
Here is how it can be used:
val f = Limiter((5d, 8d), {
_: Unit ⇒
println(System.currentTimeMillis)
})
while(true){f(())}
yet another solution
from collections import deque
from datetime import timedelta
from time import sleep
class RateLimiter:
def __init__(self, items: int, per: timedelta = timedelta(seconds=1)):
self.items = items
self.per = per
self.deque = deque(maxlen=items)
def count(self):
now = datetime.now()
self.deque.append(now)
def time_to_wait(self) -> timedelta:
if len(self.deque) < self.deque.maxlen:
return timedelta(0)
now = datetime.now()
per = now - self.deque[0]
return max(timedelta(0), self.per - per)
def throttle(self):
sleep(self.time_to_wait().total_seconds())
self.count()
if __name__ == '__main__':
rate_limiter = RateLimiter(items=3, per=timedelta(seconds=3))
for i in range(10):
rate_limiter.throttle()
print(f'{i}')