franky47 5 years ago

This is great. I tried to hack the progress by automating clicks, using:

  let button = document.getElementsByClassName('button')[0]
  Array(100000).fill(undefined).forEach(() => button.click())

In response, I got the following log message:

  > Such a smart subject.
  • johnfn 5 years ago

    Well, that's an unconventional way to write a for loop. Maybe the website is commending you on that :-)

    • notJim 5 years ago

      This is your brain on javascript :)

      Guessing it's bc one-liners are easier to write than for loops in the console.

      • mrcartmenez 5 years ago

        It’s also because it’s good practice to use the lowest power loop possible.

        A for loop can implement a reduce, a reduce can implement a map, a map can implement a forEach, but not the inverse.

        • thaumasiotes 5 years ago

          Huh? I don't follow.

            In [1]: def lred(function, iterable, initializer): 
               ...:   acc = initializer 
               ...:   def reductor(el): 
               ...:     nonlocal acc 
               ...:     acc = function(acc, el) 
               ...:   for n in map(reductor, iterable): pass 
               ...:   return acc 
               ...:                                                                             
            
            In [2]: lred(lambda a,b: 10*a + b, [2,4,6,3,1], 40)                                 
            Out[2]: 4024631
          

          What's stopping you from running these equivalencies in either direction?

          • paisawalla 5 years ago

            They mean that the forEach runs code per element, but cannot return a transformed list of values, you need map for that.

            A map can run code per list element but the result must be injective (one-to-one).

            Reduce can do all of the above, but must return a lower dimension result from its input.

            And finally, a for loop is basically omnipotent.

            • DangitBobby 5 years ago

              > Reduce can do all of the above, but must return a lower dimension result from its input.

              What do you mean by this? You can accumulate just about anything into the resulting object, including a copy of the original array.

              • SamBam 5 years ago

                I think it's just being confusingly stated. GP already said that reduce could implement map. I think it's merely that reduce can just output a single result, of any type. (Which is already more powerful than map, which must output an array.)

                Of course, in fact you could hack anything in any of these, since you could be doing other work in the function called. But I think the general principle is sound.

                • thaumasiotes 5 years ago

                  > (Which is already more powerful than map, which must output an array.)

                  Don't tell Common Lisp.

            • eru 5 years ago

              Especially, a for-loop can break out early or skip elements.

              • thaumasiotes 5 years ago

                So can reduce. You'd put that logic in the function you pass to the call to reduce.

                So can map. Ditto.

                So can foreach. Ditto again.

                  for el in values:
                    if el == 3: pass
                    else:
                      do_something_with( el )
                • mekkkkkk 5 years ago

                  No, that's just a guard condition. Parent post was referring to break, i.e. skip the rest of the iteration.

                  • thaumasiotes 5 years ago

                    For forEach that's easy:

                      for el in values:
                        if el == 3: return
                        do_something_with( el )
                    

                    For the other two, you still can, but you'll need to handle the control flow yourself, by doing something like goto or invoking a continuation.

                    • mekkkkkk 5 years ago

                      That's a for loop. And depending on the language I'm pretty sure that return call would exit the parent scope.

                      • thaumasiotes 5 years ago

                        > That's a for loop.

                        I take it you've never read any Python? That's a forEach. Python doesn't even have a for loop construct (though it does have while, which is equivalent).

                        > And depending on the language I'm pretty sure that return call would exit the parent scope.

                        Yes, that's the point, that's an illustration of terminating the forEach before you've processed each element.

                        • mekkkkkk 5 years ago

                          I'm not very proficient in Python, no. I thought you were giving pseudo-code examples. If your argument doesn't apply to the common array methods (forEach, map, reduce) in JS and similar languages, then you missed the entire point of this comment thread.

                      • eru 5 years ago

                        Python's for-loops are really for-each loops.

                        If you have a C-style for-loop, you can and have to do everything yourself. That means you can skip elements or processer them twice, etc.

                        In a Python-style for-each loop, you can break out with break or return, but you have a harder time skipping or changing the order of processing. So they are weaker. And that's good.

                        (Your examples still process elements in the body of the loop. It's just that sometimes the body decides to do a no-op.)

                        Putting the no-op logic in the body of the loop, or in the function you pass to reduce is different than being able to short-cut evaluation.

                        You can see the difference most clearly, when trying to process (the start of) an infinite generator with reduce or a for-loop. Reduce will just hang.

            • jolux 5 years ago

              forEach is actually more powerful than map, you would not be able to use map for side effects in a static and/or lazy language. In a strict, dynamic language, it matters less. Even so I wouldn't describe being an expression vs statement as a difference in power. It's contextual.

              • thaumasiotes 5 years ago

                > forEach is actually more powerful than map, you would not be able to use map for side effects in a static and/or lazy language.

                You might notice this problem above, where it's necessary to do

                  for n in map(reductor, iterable): pass
                

                to realize the mapping.

            • thaumasiotes 5 years ago

              A forEach can easily return a transformed list of values.

                acc = []
                for el in values:
                  acc.append(f(el))
                return acc
              

              This hierarchy doesn't exist; you can pretty much implement any of them in terms of the others.

              To make that untrue, you need to define very strict limits on what else your language can do.

              (Sure, we produce a transformed list here through the use of side effects. But note that the original example sparking the claim that forEach can't do what map can was this:

                .forEach(() => button.click())
              

              Side effects are clearly allowed.)

              • joe-user 5 years ago

                The forEach isn't returning it in your example, the line after it is returning. Try again without acc and I believe that's what was meant.

                You can implement any of them in terms of the others, but only if you break convention and introduce side effects. Follow convention and try to implement (for example) reduce with map and you'll find that it's not possible.

                • thaumasiotes 5 years ago

                  > You can implement any of them in terms of the others, but only if you break convention and introduce side effects.

                  This can't be right. forEach has no effects other than side effects. A convention that says not to use side effects prevents you from using forEach at all.

                  But that would make claims about the place of forEach in a hierarchy into meaningless nonsense.

                  > The forEach isn't returning it in your example, the line after it is returning.

                  That depends on your point of view. C has numerous functions which accept pointer parameters and return values in those parameters. That's just the normal way to return multiple values in C.

                  And by that standard, the forEach itself is returning the transformed list; that's where the transformation occurs. The following `return` line is only necessary if this is a snippet within a function whose purpose is to execute a for statement; you would actually do this inline, by just writing the for statement without needing a following `return`.

                  • HeavyStorm 5 years ago

                    I really don't think you got the original point...

                    • thaumasiotes 5 years ago

                      What was the original point?

                      • lurn 5 years ago

                        I think they’re only talking about JavaScript, in which case the forEach function doesn’t return anything. So you can do x.map(…).forEach(…) because map returns an array. But u can’t do x.forEach(…).map(…) Ur examples seem like they’re for a different language.

              • momentoftop 5 years ago

                Haskell has strict limits on side-effects, but also abstracts these functions over the thing you're "forEaching." There, a reduce can't implement a map, because a map is required to return the same type of collection you put in. A reduce can only return an arbitrarily chosen collection (say, an Array).

                And without side-effects, a map can't implement a forEach.

                • thaumasiotes 5 years ago

                  > And without side-effects, a map can't implement a forEach.

                  Yes, it can, because without side effects, forEach is a NOP. That's not difficult to implement. As long as you don't do anything with the return value from map, you're there.

      • vsareto 5 years ago

        >Guessing it's bc one-liners are easier to write than for loops in the console.

        Firefox has a pretty good multi-line editor now if anyone was looking for that

      • hahajk 5 years ago

        I haven’t had an off-by-one error since I stopped using for loops.

        • trulyme 5 years ago

          Got any solution for naming and caching too?

          • TobTobXX 5 years ago

            I get my variable names from `openssl rand -hex 20`

    • halfmatthalfcat 5 years ago

      Can save more bits by doing:

      Array.from({ length: 10000 }, button.click);

      • phogster 5 years ago

        Never heard of a "from" loop before.

        • franky47 5 years ago

          Array.from lets you build an array from an iterable source (often used in conjunction with `new Set` to eliminate duplicates), or in this case, of a fixed length.

      • franky47 5 years ago

        I did not know this variant, thanks. Having to fill the array with anything (even `undefined`) to iterate on it seemed such a weird concept (but then again, JS is weird).

        • bawolff 5 years ago

          new Array(1000); ?

          • franky47 5 years ago

            Try iterating on it, it won't work. This creates 1000 "empty slots".

          • jholman 5 years ago

            In addition to franky47's more important point, I'll add that `new Array()` and `Array()` are equivalent.

          • The_rationalist 5 years ago

            In java it would be default initialized but it isn't in js

        • a1371 5 years ago

          The spread operator does not have the same quirk. I use it but it's still a bit weird tough

          [...new Array(1000)].map(something)

          • ficklepickle 5 years ago

            You can drop the new

            [...Array(1000)]

            I think that is the least bits. Would love to be proven wrong :D

            • franky47 5 years ago

              It may be shorter, but I like the spread syntax best used sparingly, it's harder to grasp why it was necessary there at a glance.

              That's what I like in the elegance of Array.from({ length: 1000 }): it's a hack, but it reads naturally.

              • antonvs 5 years ago

                "Harder to grasp" only lasts until you're mildly familiar with the idiom.

      • warent 5 years ago

        I this awesome... I've always done Array.from(new Array

        But your approach makes perfect sense and is so much cleaner. Thank you!

        If anyone is wondering why it works, it's because everything in JavaScript is an object. So, an array is an object with a length prop. Apparently Array.from just needs any object with a length prop to work

        • kvirani 5 years ago

          Something about ducks?

          • chpmrc 5 years ago

            "If it walks like a duck, and it quacks like a duck, then it must be an object"

            • erhk 5 years ago

              Of it has feathers, then as far as I'm concerned it is a duck.

              Similarly, when I pick up a feathered pen in real life I become a duck

            • DonHopkins 5 years ago

              "If it walks like a duck, and it quacks like a duck, then it must be created by a QuackEnumeratorWalkManangerRepositoryProxyFactoryFactoryAdapterBroker." -Java

          • chmod775 5 years ago

            duckduckduck.duck is still available, by the way.

            Well, .duck isn't a TLD yet and it may not be publicly available...

            https://icannwiki.org/.duck

            • Freak_NL 5 years ago

              Now gogo.duck and go.duck would be nice aliases for DuckDuckGo. (There is ddg.gg of course.)

    • anonu 5 years ago

      It's how you would do it with a language like APL or q.

  • makach 5 years ago

    It responded correctly, it said: Robot, Exciting and then wrote "subject has run script to click on the button ten times within one second" whereafter "subject has clicked on the button a thousand times"

    Maybe a contender to CookieClicker? 73% achievements atm

  • skavi 5 years ago

    Is that actually the best way to do ranges on JS?

    • halfmatthalfcat 5 years ago

      Traditional for loops are probably the most common for ranges but if you want a more functional approach you can use the Array constructor or Array.prototype.from with its various parameters.

      • franky47 5 years ago

        The functional approach also works better as a one-liner when typed in the devtools console.

    • smoe 5 years ago

      The other comment points out Array.from, which seems pretty nifty. Have not seen it before. I would have used:

        for(i of Array(1000).keys()) { doSomething() }
      

      or

        [...Array(1000)].forEach(() => doSomething())
      • vardaro 5 years ago

        why create the array?

        for(let i = 0; i < 1000; i++) button.click()

        wouldn’t be surprised if Javascript has some weird optimization under the hood!

        • epse 5 years ago

          In this case, there's not much difference. In general, iterating over something rather than using a counter with limits makes it harder to create off by one or other errors due to laziness.

    • eins1234 5 years ago

      I'm a fan of `Array.from({ length: 1000 })`

      • mahathu 5 years ago

        am i missing something with this entire subthread? why not for(let i=0; i<n; ++i){something()};?

        • xeromal 5 years ago

          I guess they can argue they're introducing fewer variables. lol

        • kbenson 5 years ago

          I think it's mostly a stylistic choice, but getting in the habit pays dividends in that it makes it easy to do certain list related actions in a consistent way. forEach doesn't necessarily show this off well, but filter and map make it more obvious.

          E.g.

             // Get list of even squares of first 10 integers
              Array.from({ length: 10 }).map((e,i)=>i*i).filter((i)=>i%2==0).forEach((i)=>console.log(i));
              // Or more readable
              Array.from({ length: 10 })
               .map((e,i)=>i*i) // Get squares of each number
               .filter((i)=>i%2==0) // filter for evens
               .forEach((i)=>console.log(i)); // print
          

          Want to filter or manipulate the values in a different way? Throw in another map or filter. Want to pass complex values between steps? You can pack them into an array or object in a map and unpack later.[1] Once you're used to doing stuff with lists, you can use some other interesting list operations like reduce(), some(), every(), etc.

          It's not really better (it's subjective), it's just different and a lot of people are used to it and prefer it (and it's fairly consistent in nomenclature across some languages, which is a bonus).

          1: https://en.wikipedia.org/wiki/Schwartzian_transform

        • topspin 5 years ago

          Doesn't use enough memory perhaps.

        • ficklepickle 5 years ago

          there is no true scotsman

          [...Array(n)].map(something)

        • vardaro 5 years ago

          this is what i’m preaching

        • momentoftop 5 years ago

          Or if you want to avoid off-by-one errors, why not have a function:

              dotimes(n, () => button.click())
          

          If anyone is in the habit of solving trivial constant space problems in linear space where n is expected to be over 100000, I don't know what to say to them. Are Javascript implementations pretty much guaranteed to optimise the array away?

        • still_grokking 5 years ago

          Because let transformed = for(let i=0; i<n; ++i){something()}; doesn't work.

          For loops are just clunky. They're not values, you can't pass them around or copy'n'paste them where the transformed value is needed.

          • eins1234 5 years ago

            This. Data and transformations on data (map, filter, reduce, etc) are trivially composable. Imperative loops are not (unless you abstract them away behind a function that accepts and returns data, in which case you'd be re-implementing map, filter, reduce with imperative loops).

    • antihero 5 years ago

      I guess you could do `[...new Array(1000)].map((_,i) => i);` to create a sequence.

  • NaturalPhallacy 5 years ago

    You and everyone else copying it seems to have DDOSd the site and now I don't get to play with it lol

    • franky47 5 years ago

      Unless clicking the button furiously sends ton of network requests (I'm on my phone so can't confirm ATM), the only thing you're DoSing is your own CPU, as I forgot to add some kind of thread relief delay.

  • Waterluvian 5 years ago

    Javascript has gotten so good with ES6 and beyond. But there's still no nice way to do something n times without a C style loop.

  • BeefWellington 5 years ago

    xdotool can do this type of thing pretty easily as well:

    Open a console, and prep: xdotool click --delay 50 --repeat 1000 1

    Move your mouse to the location and press enter.

  • ericmcer 5 years ago

    I used a `setInterval(() => btn.click(),100)` and that seemed to fool it

MarxOk 5 years ago

Sites like this often go down when they reach the HN first page. I've naively deployed stuff on AWS free tier with no scaling or anything that's handled thousands of concurrent requests out of the box. Is the HN kiss of death that bad, or is it just that a lot of people use weird/shared hosting providers?

  • codegeek 5 years ago

    It depends on what type of site it is. A dynamic site with lot of database calls/no caching would probably crash much quicker than a static HTML page with same amount of traffic. HN easily sends 100s of concurrent users if not many so it can crash a shared hosted dynamic site with no caching.

  • geek_at 5 years ago

    either badly coded website (heavily relying on some backend without static files) or weak hosters but not sure I have a blog that survived every single HN/reddit hug on a pretty weak VPS.

    Blog written in PHP but without database interaction

  • jcpham2 5 years ago

    Surely not the first appearance?

  • pimlottc 5 years ago

    What’s frustrating is the lack of error handling, especially in an intentionally “mysterious” game like this. I spent a few minutes trying to “figure it out” before I realized, nope, it’s just broken (web socket connection failed).

    • mudlus 5 years ago

      Same here, had to switch off of Firefox

      • Izkata 5 years ago

        Worked for me the second time I loaded it in Firefox

    • Honga 5 years ago

      We're (Moniker) doing palliative care for it at the moment. The technology is quite old.

      Sorry about that! There may be an initiative to update it in the near future.

      • c17r 5 years ago

        Doesn't seem to recognize the latest Chromium version of IE Edge

  • syncsynchalt 5 years ago

    When I put up tls.ulfheim.net (a small-ish static site on a t2.micro) HN and Reddit were able to bring it down by maxing out the apache workers.

    Some config changes fixed it right up, but my point is that it's not just the capabilities of the instance, the default http server configs might need some tweaking too.

    • rkv 5 years ago

      Out of curiosity, what config changes did you use on apache?

      • dopidop 5 years ago

        Same questions here. I’m not sure I would know where to start on those particular configs

        • tibu 5 years ago

          Maxrequestworkers, server limit?

      • syncsynchalt 5 years ago

        IIRC it was MaxRequestWorkers to 1500, and MaxConnectionsPerChild to 0 (unlimited)

  • brundolf 5 years ago

    My website is hosted on the cheapest non-free Heroku tier ($7), and served by a single Node process. I've had a couple of posts get to #1 on HN (one stayed there for 24+ hours if I remember correctly), with zero server issues.

    I do statically-render everything, so not doing that is the only reason I can think of for why so many sites might be going down when they get up on the front page. Many of these are blogs so could probably do much better, though I did see someone mention that this one uses websockets for something, so it would definitely be doing some logic on the server-side and wouldn't be able to go fully static.

    • woudsma 5 years ago

      You should look into Dokku!

      I'm hosting 30+ apps (frontends / api's / cms's / other processes) on a single 5eu/mo DigitalOcean droplet. I believe Hertzner is the cheapest hosting provider with a 2,87eu/mo VPS.

      Self-hosting is a lot of fun, and cheaper. Dokku has been around for several years, it's an open-source Heroku clone and I would recommend it to anyone looking into deploying web apps.

      • brundolf 5 years ago

        I've heard of it; for me, messing with a system (even once) isn't really fun, it just gets in the way of spending time on my code. I don't have a ton of projects and Heroku has a free tier for things that don't need 100% uptime, so it's worth the extra couple bucks for me

        Edit: I see DigitalOcean has it available as a 1-click install. Do you get totally automatic updates/system management and everything with that?

      • ornornor 5 years ago

        How do you keep things secure and up to date? That’s always been my problem and when developing an app I don’t want to do system administration so I always end up going with heroku (or it’s cheaper sibling render.com lately) because I don’t have time for system administration, backing up, etc.

  • ddtaylor 5 years ago

    It appears to be hosted on Digital Ocean.

  • woudsma 5 years ago

    I've had the honour to build clickclickclick.click (frontend/backend), with the truly unique team at Studio Moniker in Amsterdam.

    I was quite inexperienced - 1 year after graduating from art school - when I joined and started working on this project. The server went down 5x in a single day because of all the requests. We were using web sockets (simple node server with express + socketio and a react + rxjs frontend) and that put some strain on the server. And I made the rookie mistake of storing images directly into the database instead of in a S3 bucket. Also we chose CouchDB, which saves document revisions (I didn't know..) so at the end of the day the database took 100% disk space and I couldn't SSH into it anymore. There were something like 20M+ database writes within 24hrs of the launch because it went viral.

    We span up larger DO droplets several times because of this issue which took a while to fix.

    It was my first time setting up / working with a VPS and nginx + sockets as well, so I'm actually quite pleased with only 15-30mins downtime overall on launch day :)

    I learned a lot during that time (it was made in 2016), especially with the help of HN. Projects are often developed by junior devs or people skilled in other areas. Some experience is useful when deploying scalable apps. Nowadays it's much more easy with services like Vercel/Cloudflare/Heroku/AWS/etc. We used SFTP to deploy the site. I think I moved it to a Docker container some time after that.

    I'm still using DigitalOcean to this day for my personal stuff, only now I use Dokku + Cloudflare - which works like a charm.

    Check out https://studiomoniker.com if you want to see more crazy projects! (They're my previous employer FYI).

    • Lorin 5 years ago

      re Studio website: minor spook when the arm comes from the bottom of the screen to tap on the shop link unexpectedly

      • PhillyG 5 years ago

        I'd read this comment and still had that horror movie jump scare feeling!

    • pontifier 5 years ago

      Fantastic projects there. I'm interested in "Red Follows Yellow Follows Blue Follows Red". It seems like it would be tons of fun for school kids. I can see a kit of headphones and capes being something a teacher could use to have a fun activity without too much work.

      • pontifier 5 years ago

        Dang... I want to build a sand pen too!

sethammons 5 years ago

I'm on Firefox. I just got "subject clicked the button" and nothin' else is happening. Is that it?

  • oehpr 5 years ago

    seeing this behavior as well.

    As is the plight of a firefox user, I'm headed to chrome to see if it works there :\

    edit: looks like it there's a ton of audio files that may have failed to load.

  • progval 5 years ago

    It makes a network query, and stops at this point if it fails. And it often fails because the website is overloaded.

  • tom_mellior 5 years ago

    No, there's a lot more. I have no problems in Firefox 86.

  • 13415 5 years ago

    Weird. I'm using Firefox and the page says "Secure Connection Failed. An error occurred during a connection to clickclickclick.click. PR_END_OF_FILE_ERROR"

    • branon 5 years ago

      Same here. Can't load the page.

  • ibraheemdev 5 years ago

    Same here. I'm getting:

    > Firefox can’t establish a connection to the server at wss://clickclickclick.click/socket.io/?EIO=3&transport=websocket&sid=... websocket.js:111

    > The connection to wss://clickclickclick.click/socket.io/?EIO=3&transport=websocket&sid=... was interrupted while the page was loading.

    Reading the comments, it sounds the site is supposed to log everything that I do? Perhaps Firefox is blocking it?

    • ficklepickle 5 years ago

      Word on the street is socket.io doesn't scale

  • mrleinad 5 years ago

    I had to disable all adblockers to get the full functionality.

  • peterkelly 5 years ago

    Looks like the devs might want to put in some error handling in on the client side to handle this case. However fantastic/intriguing/addictive this site may be when it works, all I see is a button and this message and wonder WTF is this.

huskyr 5 years ago

This is a piece created by the Amsterdam-based Studio Moniker. They have many more projects that play with the same ideas, see here: https://studiomoniker.com/projects

alvarop 5 years ago

Reminds me of Samy's website. For a fun time, try to view the page source: https://samy.pl/

  • pkkim 5 years ago

    Well there goes an hour.

  • tempestn 5 years ago

    This is great. Thought I'd got it for a second when I hit #11...

  • thricegr8 5 years ago

    IIRC, at one point he offered a semi-bounty on anyone who could actually reveal the source, only partly in jest.

  • perryizgr8 5 years ago

    > No source for you! You found easter egg #7. Close the console to return to samy.pl ;)

    Hmmmmm...

    • BeefWellington 5 years ago

      The detection is pretty simple; in FF undocking the console bypasses all of it and you can debug whatever you like. :)

      • fctorial 5 years ago

        Or open the console while you're on hacker news and then click on the link.

        • saagarjha 5 years ago

          This does not work for me in Safari.

      • pkkim 5 years ago

        Oh, damn. Well, I'm glad I didn't figure that out. Doing it the "right" way was fun!

    • thomond 5 years ago

      Just open the debugger. You can see the entire sources in there.

  • foobar33333 5 years ago

    For some reason the page blanks out as soon as I load it and then when I open the console it loads normally and I can see the source.

dazbradbury 5 years ago

Site is down, but this is an explainer by the site's creators (with demo):

https://studiomoniker.com/projects/click-click-click

Getting to #1 on HN never easy for the robots. :-(

  • thomasjonas 5 years ago

    Sorry about that. It should be live again. Not sure for how long though... We (studiomoniker.com) are quite busy with other projects and we don't have to time to properly support this project. Hopefully we can make it more HN proof in the future. The project definitely deserves it!

runningmike 5 years ago

Security’s worst nightmare! But brilliant creation from a psychological point of view. Awareness Awareness Awareness...

pmastela 5 years ago

Nifty. Now if only this was the required homepage on all major browsers starting up for the first time then folks at home would quickly become aware of just how well tracked they all are.

cyberlab 5 years ago

I have JS disabled by default using uBlock Origin. The first thing I done was press CTRL+U to inspect the source. Then I deduced the site wasn't malicious (or is it malicious?) and played around with it with JS enabled. It creeped me out, as all these data points could be used to fingerprint a user using simple heuristics like mouse movements etc

  • carstenhag 5 years ago

    I don't understand why someone is paranoid of having their mouse movement tracked.

    • cyberlab 5 years ago

      Most users have very unique styles, or mouse cadence. Same with typing cadence, and there are even services[0] which determine if a user is who they claim to be, based on their unique typing 'DNA'. All a site has to do is embed some JS that measures your mouse-movement style and they can reliably determine if it's 'you' who is on the site, and can more accurately target ADs at you, or even sell your data out the back door for a profit.

      [0] https://www.typingdna.com/

wlesieutre 5 years ago

Why does a webpage get to know how many CPU cores I have?

  • tomg 5 years ago
        window.navigator.hardwareConcurrency
    

    [edit: well this is more of a 'how' than a 'why']

    • Sephr 5 years ago

      The answer to why: It helps with efficient allocation of worker thread pools.

      I helped make a timing attack[1] as justification for adding this API, and then presented this suggested API to each browser vendor along with the timing attack. The result was that every browser has adopted my suggestion.

      If this API was not present, ads could get this data in a more resource-intensive manner anyways.

      1. https://eligrey.com/blog/cpu-core-estimation-with-javascript...

      • simias 5 years ago

        Ahah, I like the "give up" approach to fighting browser fingerprinting! "If ads can track us, we might as well make it efficient".

        • moron4hire 5 years ago

          The threshold of information needed to gain reliable fingerprintability is so low that we could rewind the browser development clock 20 years and still be nearly 100% identifiable. We'd gain nothing in terms of privacy, but we'd lose everything in terms of the first and only application platform that runs on every system short of a greeting card, is free to use, easy to use, not tied to an app store, not tied to a single vendor.

          • AnthonyMouse 5 years ago

            The original sin of the web is that the code comes from the server again every time you run it. That means you need robust sandboxing and anti-fingerprinting etc., because you're running potentially hostile code that nobody has been able to audit.

            Other types of programs don't have that problem. If you get some code from Github, you can review it yourself before the first time you run it. Then every time after that, it's still the same code so you only have to do it once. And you can have someone you trust do it for you, like a Debian package maintainer.

            But with nobody reviewing the code, the machine has to do it, i.e. there have to be a bunch of technical constraints on tracking and malicious behavior.

            It's a terrible rubbish fire that we don't have any kind of real application platform for real applications that runs the same on every system and doesn't have a monopolist dictating terms. We should fix that. But we could fix that, and be better off than by giving up and conceding the world to surveillance dystopia.

            • TeMPOraL 5 years ago

              > Other types of programs don't have that problem.

              Well, they didn't. They do now, as you're expected to update everything continuously. A typical user of a PC or a smartphone has something downloading an update pretty much every day. Even a tech-savvy user can't hope to keep up with trying to track down all sneaky automatic updates and read a changelog before applying them (assuming there even is one, beyond "This update improves experience and fixes bugs" zero-information boilerplate).

              At this point I'd be willing to pay for a service that would intercept all automatic updates on my devices and warn me about the ones that bring in telemetry, malware, performance degradation or other misfeatures. Unfortunately, such a service would require impossible feats of crowdsourcing to keep up with the deluge, and itself would be a huge privacy/security risk.

              • AnthonyMouse 5 years ago

                Aren't you just describing a package manager or an app store?

                The reason mobile app stores are garbage is that the store is glued to the platform, making it high-friction to switch to another one if they do a bad job. Then they do a bad job by allowing things you don't want and prohibiting things you do want (and charging high fees etc.) and get away with it.

                There is no reason for this to be centralized into a single approver. If you got 90% of your software through the Debian package manager but specifically need a newer version of Blender than they package, you could get that in particular directly from the Blender developers because you trust them not to intentionally distribute malicious code, while still relying on the package maintainers to do the work for all the other software you use.

                That's possible right now on Linux. The problem is mostly that it's not possible right now on everything.

                • TeMPOraL 5 years ago

                  You're right, in a way. What I described would be a reality under a package manager with curated repositories, if I sourced all my software from there.

                  My wish came from the opposite end - I have all this software on my devices that's sourced from a lot of different places, and some of the software on my PC has built-in auto-update that's independent of the original installation method. What I want is a curation add-on - a single (at least per-device) component that would intercept all automatic updates of everything, coupled with a database (the service part) that could tell me roughly what the update contains, and flag anything problematic (telemetry, ads, feature removals, performance degradation, ...).

                  Your reply made me realize two things:

                  1. I used to hate default package sources on Debian for shipping a small selection of outdated software. I formed this impression back when I was young and naïve, and didn't question it since. But now I can see the value in having actual humans curate the software. I need to get out of the habit of adding random sources and PPAs just for the sake of having everything bleeding edge.

                  2. I'm really mostly pissed about this on behalf of other people. I've learned to manage my devices - mostly by being very selective about the software I run. Most people I know in the meatspace don't have the necessary experience and time, and helping everyone individually doesn't scale.

  • fred123 5 years ago

    Reported by the browser but not always accurate. Used in browser fingerprinting btw

    • Macha 5 years ago

      Yeah, I have a 12C/24T cpu, my browser appears to report 16 cores.

  • moron4hire 5 years ago

    So I can know how many worker threads to create before it's just a waste of thread scheduling

  • seniorgarcia 5 years ago

    https://developer.mozilla.org/en-US/docs/Web/API/NavigatorCo...

    There is no good answer to why, except to improve fingerprinting. Which is most of what this site shows, the amount of data a site, even open in the background, can use to continuously fingerprint you. Or maybe I misjudge what this is supposed to do.

    • moron4hire 5 years ago

      You've been given several good answers as to why, you just refuse to believe anything anyone is telling you.

      • seniorgarcia 5 years ago

        I believe that you think that your answers are true but my desktop will report 12, my work laptop will report 16, my macbook will report 16 as well, my work desktop will report 64 (my surface laptop will report 12 as well, my ipad pro will report 6... I can continue this for some time).

        Which machine do you think has the best performance for your app?

        • moron4hire 5 years ago

          I don't care. You picking the machine is up to you. I only care about giving the best performance on whichever one you've chosen.

        • jtsiskin 5 years ago

          Those numbers actually mean something. That’s approximately how many concurrent threads I would want to use. I’m not sure I follow the point you’re making

    • judge2020 5 years ago

      I bet it helps for some niche apps like webgl/webgpu games.

0df8dkdf 5 years ago

this sites are the exact reason why I browse without JS by default. There is no business a site should know how many previous web site I have visited as well as my CPU. All these JS API ought to be able to disabled by default.

navaati 5 years ago

"You visited about n sites before coming here" How the hell does that work ?

  • tomg 5 years ago
        window.history.length
    

    would be my guess.

    • navaati 5 years ago

      Ugh, slightly creepy. Thanks for your answer !

    • woudsma 5 years ago

      Yes, this is the property that was used to measure the number of previously visited websites.

      It only counts the previous sites in the current browser tab if I remember correctly.

  • acwan93 5 years ago

    I can't find the website, but there's a site that specifically tells you everything it knows about you just by keeping the page open.

    It tells you if it knows where your cursor is, what pages you've been to, what your computer is, etc.

    It was intended to show that you, the user, give out a lot of data without even realizing it.

    EDIT: I did a search on reddit and it looks like it actually is https://clickclickclick.click, but because the site hasn't been accessible I can't be sure.

    • iAmAPencilYo 5 years ago

      Would be interested in it if anyone finds it!

    • xtracto 5 years ago

      There was a very nice attack regarding you being logged in to different websites by attempting to fetch crafted URLs that would be available only if you were logged in.

      Quite clever.

      • mahathu 5 years ago

        but what would the issue be if some random site knew I was logged into google/amazon/facebook at the time?

        • minitech 5 years ago

          - consider that the same thing applies to sites that aren’t google/amazon/facebook that you might care about

          - it helps with fingerprinting

          - there’s no reason to allow it

          • mahathu 5 years ago

            Good points, especially the first one. Thanks.

        • xtracto 5 years ago

          Great question. When I read about that i was working for an online lending startup. We briefly discussed on using such a feature as a signal for credit risk underwriting.

          The logic was that, maybe you were logged to Telcel or to Movistar, or to Liverpool vs Sears (Mexican retailers). That could give us signal on the probability of default

  • SAI_Peregrinus 5 years ago

    You opened a new domain and didn't have it in an isolated container. So it could query the history length, even if it can't query the actual history.

pansa2 5 years ago

I must be missing something.

    “Subject has clicked the button”
    “Subject has scrolled down”
    “Subject has resized the window”
    etc.

So what?

  • freeCandy 5 years ago

    It is a demonstration of how easy it is for websites to track your behavior online.

anonytrary 5 years ago

Damn it HN! Y'all giving this place the hug of death and now I can't get past the "Subject clicked the button" level. It just won't load any other level for me. I guess I'll try tomorrow when it's off the front page.

  • xavi_ 5 years ago

    If you have an ad blocker, you have to disable it for the website to work correctly.

lisper 5 years ago

Wow. This is literally clickbait.

habosa 5 years ago

I own idareyouto.click and have no use for it. If anyone wants to use it for something fun email sam at habosa dot com

kebman 5 years ago

I love this. I also really liked the dance: https://tonite.dance/

  • Groxx 5 years ago

    That's really neat - fun use of VR, and entertaining without it too. It took me a while to figure out that you could click on the dancers and see it from their viewpoint though.

kag0 5 years ago

Given the trick they use to prevent you from using the browser back button, I was expecting it to comment "subject is trying to escape!"

xtiansimon 5 years ago

Love this. I sketched out a similar single-button idea for an art project back in 1998 with a programmer. I wanted human-human interaction, but this is much better.

zaczekadam 5 years ago

It's crazy how many things they predicted. Love it

51Cards 5 years ago

Seems to be failing socket requests in the background for me... likely being swamped right now. I shall have to click later.

ElijahLynn 5 years ago

Getting HN DDoSed. 500 Internal Server Error.

nudpiedo 5 years ago

what's this supposed to do? I do not get beyond "subject clicked the button", perhaps because the add-blockers and privacy extensions I use...

EDIT: Either firefox or edge the result is always the same:

"failed: WebSocket is closed before the connection is established."

abhayhegde 5 years ago

I am so interested in seeing the source code. The voiceover dialogues are so apt.

gnicholas 5 years ago

> subject disconnected from internet

Not sure why I got this message, which is not true.

bradwood 5 years ago

Doesn't place nice with i3 tho. Nor does it appear to recognize Brave

jcun4128 5 years ago

doesn't detect when you delete all dom

YouTube does that, if you try to manipulate the dom it throws some error. I ended up injecting CSS instead.

Aeolun 5 years ago

The experience was a bit limited on mobile.

ketamine__ 5 years ago
ganessh 5 years ago

The page is down :(

mudlus 5 years ago

I suspect this is using GPT-3 or something