10 interesting stories served every morning and every evening.
This page is a free and open-source wiki about hardware hacking!
The goal of HardBreak (https://www.hardbreak.wiki/) is to collect knowledge about Hardware Hacking / IoT hacking in one place. There are many great blogs about Hardware Hacking, but it is a rather unpleasant experience to search through multiple blogs in different formats to find the information you need. HardBreak aims to organize all information in one accessible and easy-to-use platform.
🎉 We just launched our HardBreak Discord Server! 🎉
* Want to discuss hardware hacking and IoT security
* Share the project you are working on
* Have feedback or requests for new content on our wiki
Come be a part of our growing community of hardware hackers⚡
We strongly encourage anyone interested to contribute their knowledge and insights. By sharing your discoveries or improving existing content, you help build a valuable resource for everyone.
* Help us keep the content accurate—if you notice an error, please report it so we can correct it quickly! Reach out on LinkedIn or Twitter
Check out our Contribution Guide for a step-by-step tutorial to making your first pull request!
...
Read the original on www.hardbreak.wiki »
Since I last wrote about WordPress, things have gone off the rails. This after a brief period when things were blissfully quiet. Matt Mullenweg stopped commenting for a while, though his company had launched WP Engine Tracker — a site for tracking WordPress-driven websites that moved away from WP Engine. I think this is a bit gauche, but it seems like fair marketing given everything that’s going on. It should be noted that many sites are leaving for Pressable — owned by Mullenweg’s company, Automattic — because of a sweetheart deal.
But the drama ramped up quickly after WP Engine won a preliminary injunction against Automattic on December 10th. The injunction required that WP Engine be allowed to access WordPress.org resources, and that Automattic stop interfering with WP Engine plugins, while the trial moves forward. Ernie Smith wrote an excellent piece with more details on outcome of the injunction, including a note about Mullenweg quitting a community Slack instance with a hammy message. Mullenweg complied with the injunction, though the “loyalty test checkbox” text was changed to a still-required note about pineapple on pizza.
On December 20th, Mullenweg announced that WordPress.org would be on holiday break for an unspecified amount of time. In a post on the WordPress.org blog, he again mentioned being “compelled to provide free labor and services to WP Engine thanks to the success of their expensive lawyers”. He also invited people to fund legal attacks against him by signing up for WP Engine services, and hoped to have the “time, energy, and money to reopen all of this sometime in the new year”.
This was the first time WordPress.org had ever gone on break, and it was another instance of Mullenweg using a core part of the WordPress community to send a message. WordPress.org returned to service on January 4th, but plugin and theme updates weren’t being reviewed until then. I’m all for giving volunteers time off, but this came as a surprise to the community and there was initially no indication when the break would end. Mullenweg’s “woe is me” language around maybe, possibly, being able to find the resources to reopen a core piece of WordPress infrastructure didn’t help things. It further cemented that Matt Mullenweg’s current mood is an important function of whether or not the WordPress community operates smoothly.
While WordPress.org was on hiatus, Mullenweg also reached out to the WPDrama community on Reddit, asking what drama he should create in 2025. A couple of years ago, this sort of thing would have been some tongue-in-cheek fun from a person who’s always been a bit of a goof. These days it comes off a bit differently.
Then yesterday happened. Automattic announced that it would restrict its contributions to the open source version of WordPress. The company would now only put in about 45 hours a week total — down from nearly 4,000 a week — so as to match the estimated hourly contributions of WP Engine. This action is blamed on the “the legal attacks started by WP Engine and funded by Silver Lake”, which I think is a gross mischaracterization. WP Engine definitely did not start this.
Automattic noted it would focus its open source hours on “security and critical updates”. The other hours would be redirected to for-profit projects like WordPress.com. This means that the community will be expected to take up the slack if it wants WordPress to improve. I worry that 45 hours a week isn’t enough time to keep WordPress secure and bug-free. Hopefully others will step up, here.
But you know what? In a normal world, having the community taking the lead would be fine. I’d be all for it! The problem is that Mullenweg has final say over some very important parts of the WordPress community. He also seems recently to be acting more childishly and impulsively than usual.
Another thing that came to light yesterday was that the WordPress Sustainability committee was shuttered after a core member, Thijs Buijs, stepped down. In a post on the WordPress Slack, Buijs cited the “2025 drama” post on Reddit as the reason he was leaving, and called for a change in WordPress community leadership. In response, Mullenweg responded in part with “[t]oday I learned that we have a sustainability team”, and closed the channel.
The WordPress Sustainability Team had four core members, and 11 people who had contributed on GitHub. As far as I can tell, they were all community members, and none were Automattic employees. Even if it wasn’t producing amazing results, I can’t see what harm it was doing. The sin was pointing out something stupid that Mullenweg did, and having a member wanting change. The optics, especially given current world events, are definitely not great. The wildest part of this to me is that there’s video of Mullenweg — live on stage at Word Camp Europe in 2022 — requesting the creation of the Slack channel he was turning off. Guess that slipped his mind.
All of this bodes poorly for the open source version of WordPress. I think it’s perfectly fair for Automattic to switch gears and focus on for-profit projects — it’s a company after all. The problem is that there’s a void being left. Automattic had, for better or worse, lead the development of both the commercial and open source pieces of the WordPress ecosystem. Now it seems like the community needs to take over, but Mullenweg still holds all the keys.
In the announcement, Automattic said that WordPress.com would be updated to be more in line with the open source version of WordPress. This also makes sense to me, as WordPress.com has always been a weird version of the software. Of course, having slight differences to the core WordPress experience is the argument that Mullenweg initially used to call WP Engine a “cancer”, but who’s keeping track? I’d also like to point out again that Automattic invested in WP Engine in 2011. It also acquired Pressable in 2016, likely because it was a hosting service that offered a “real” version of WordPress, unlike WordPress.com.
It’s hard to see how to move forward from here. I think the best bet would be for people to rally around new community-driven infrastructure. This would likely require a fork of WordPress, though, and that’s going to be a messy. The current open source version of WordPress relies on the sites and services Mullenweg controls. Joost de Valk, the original creator of an extremely popular SEO plugin, wrote a blog post with some thoughts on the matter. I’m hoping that more prominent people in the community step up like this, and that some way forward can be found.
In the meantime, if you’re a WordPress developer, you may want to look into some other options.
Update: Moments after posting this, I was pointed to a story on TechCrunch about Mullenweg deactivating the WordPress.org accounts of users planning a “fork”. This after he previously promoted (though in a slightly mocking way) the idea of forking open source software. In both cases, the people he mentioned weren’t actually planning forks, but musing about future ways forward for WordPress. Mullenweg framed the account deactivations as giving people the push they need to get started. Remember that WordPress.org accounts are required to submit themes, plugins, or core code to the WordPress project. These recent events really make it seem like you’re no longer welcome to contribute to WordPress if you question Matt Mullenweg.
...
Read the original on anderegg.ca »
Every morning I get up and check what malicious packages my detector had found the night before. It’s like someone checking their fishing nets to see what fish they caught.
As I was looking at last nights malicious packages I noticed something strange: Someone from Snyk had deployed several packages to NPM. Even weirder, the names of those packages appeared to show they were targeting Cursor, the hot new AI coding company.
These packages were deployed by an NPM user named sn4k-s3c. The packages are named things like “cursor-retreival”, “cursor-always-local” and “cursor-shadow-workspace”.
If you install any of these packages they will collect data about your system and send it to an attacker controlled web service.
...
Read the original on sourcecodered.com »
13 Jan 2025
Here’s my fluid simulation pendant, a handcrafted piece of jewellery running a realtime FLIP fluid simulation. The enclosure is gold plated, and the display is protected by a watch glass.
Watch the following video to experience the narrated design and construction:
I produced the first pendant in March 2024, and then several more over the next few months. I now have a small handful of pendants, and if you’d really, really like to own one, then while stocks last, a few of them are for sale.
The motivation and initial design is described extensively in the youtube video, so I won’t repeat myself too much here, but in short, following the volumetric display animations, I’ve been looking to implement a realtime fluid simulation that ultimately could create a 3D virtual snowglobe. Progress has been made on that front, but along the way, we came up with the Simsim concept, upon which this pendant is based.
While working on it, I came up with a bunch of cool new developments that led to several other projects, which I’ll post in due time, but this is the project that spawned them. Not just the fluid simulation stuff, but also the unexpected benefits of a diagonal charlieplexed display.
The FLIP simulation is based on the work of Matthias Müller, check out his website Ten Minute Physics and particularly the “How to write a FLIP Water Simulator” tutorial. It explains FLIP better than I can here.
My fluid simulation is not a direct port, but a re-implementation following the tutorial.
The hardware consists of an STM32L432KC (ARM Cortex-M4 with FPU, overclocked to 100MHz), an ADXL362 ultra-low power accelerometer, an MCP73832 charge controller for the LiR2450 battery, a TPS7A02 regulator (crazy low power) and a TPS3839 supervisor. It all comes together on a four-layer, 0.8mm PCB.
The key takeaways from this project are as follows:
Diagonal charlieplexing permits routing with half the number of vias as compared to a conventional matrix. For small-pitch LED displays, the number of vias is often the limiting factor, so this makes a huge difference. The arrangement also places LEDs with the same net end-to-end, so a solder bridge doesn’t impact performance. One could even intentionally squish the LEDs closer together with this in mind.
DMA in circular mode can run a display matrix with zero overhead. This can also be used, with some wrangling of two DMA streams, to run a charlieplexed matrix with no overhead too.
A lookup table is required to map LEDs to the corresponding pixels, but this means that there is no additional cost to changing that mapping. In other words, we can connect any signal of the matrix to any pin of the microcontroller port, which makes routing surprisingly easy, if a little unconventional.
Running a larger display direct from GPIO ordinarily suffers from brightness issues as the on-resistance of the output FETs limits the current. But charlieplexing necessarily illuminates only one pixel at a time, which means the effect of on-resistance is factored out, as it dims all pixels evenly. You can even control the brightness of the display by varying the voltage to the microchip. With this in mind, we could solve the problem for a conventional matrix by forcibly illuminating just one pixel at a time, instead of a whole row. Normally this would increase the overhead of running the display, but if it’s handled entirely by DMA, that gets factored out too. Pretty cool!
Again, I followed the Ten Minute Physics tutorials for this, but in order to understand what’s going on, I re-implemented it, trying as much as possible not to look directly at the source code. This was a really fun journey.
In the Eulerian fluid simulation, the movement of the fluid is enacted through a process called advection. In FLIP, we don’t do this step, and instead let the particles’ motion carry the fluid about.
There are some places where not enough detail was given in the videos, and in those cases I did peek at the other source code. One such example is the particle collisions. Initially I didn’t bother with doing a hashgrid, as we’re starting on a desktop computer and that’s an optimisation that can be left until later. But even with naive collisions, what actually happens when particles collide? They are pushed apart with an impulse inversely proportional to their distance, but the stability of the simulation depends on getting that impulse right, much in the same way that the “overrelaxation” step of solving for incompressibility sort of magically corrects things. It did occur to me that if we’re solving for incompressibility, and the eulerian grid velocities are transferred back to the particles, why are explicit collisions between particles even needed?
I can confirm that without the collisions step, the whole fluid collapses into an overlapping mess, so the step certainly isn’t superfluous.
There’s a lot of overhead (both computational, and mentally) to the hashgrid. In my final code I had a switch between naive collisions and hashgrid collisions, and the difference is remarkable — even at a tiny size of 8x8, the hashgrid algorithm provides a significant speedup.
I created a vast number of bizarre not-quite fluid simulations along the way. With the particles rendered, most of them looked like some variation of frogspawn. I have a collection of odd screenshots where I’ve forgotten what exactly was going on at the time, I don’t remember what led to this doughnut…
The example from Ten Minute Physics has a small error in the boundary condition for the left edge, meaning that the fluid never comes to rest. I spotted the mistake (and vaguely considered sending a pull request but forgot). With the boundaries working correctly, the whole mass of fluid and particles still doesn’t quite stop moving, as there’s no viscosity or friction except for the walls, but it does sort of congeal in a way that reminds me of crystal structures, often with dislocations or grain boundaries between groups of regularly spaced particles. Here’s an early screenshot:
Here we see a sort of triforce emerging from the fluid being pushed into a corner:
The yellow plot is of density (number of particles overlapping each grid cell) which helped create some really cool visualisations. If we bunch up the fluid into one corner, then suddenly change gravity to point into the other corner, we get a shock wave as it crashes against the walls.
It only lasts for a frame or two, blink and you’ll miss it, but I find that circular wavefront of dense particles to be a really pleasing effect, especially as it emerged somewhat organically from the rules of FLIP. You can even see the shockwave directly in the particle positions if you freeze-frame at the right moment. Here I just missed the corner and two competing shockwaves are propagating:
Barely a fortnight after posting the Simsim concept, I produced the Simsimsim demo, as an internal testing tool to determine how low we could make the LED density and still call it a fluid.
It also gives me a rough estimate of how much RAM is required when we port it to bare metal. A lot of problems can be solved by adding another lookup table, but as the diameter increases the necessary RAM for all those tables blows up very quickly. The STM32L432KC has 64KB of RAM — not a lot, but a diameter of 16 needs only 26KB. It’s the kind of thing that’s definitely worth checking before you commit to hardware though.
These demos, along with the source code to the pendant itself, are not yet released to the public, but I plan to do that at some point in future. I figured that at least for a short while, given that I’ve put some of the pendants up for sale, there should be some mystery behind their exact operation, but all will be revealed in time.
Before even starting on the PCB, I had to convince myself that the charlieplexed display pattern was going to work. There are a large number of charlieplexed display routing options out there. I found references to an arrangement called “twistyplexing” which optimises for hand-soldered circuits. But as the incredible benefits offered by a diagonal criss-cross started to become apparent, I began to question myself and figured I needed to produce a working prototype.
This small display took bloody ages to put together. A laser-cut piece of card is used to hold the LEDs in place, and a souvenir from MCH2022 supports the contrivance.
I am reminded of a paper I once read but can’t find for the life of me, about the discovery of certain knots. The Ashley book of knots, which serves as a kind of knot gospel, lists a huge number of knots that have been in use for centuries. But when a mathematical notation was used to describe the topology of these knots, it was discovered that some of them are, in fact, identical, at least from a topological point of view. They were listed separately, because without a rigorous language to describe them, mentally reshuffling one knot into another form is extremely difficult.
I suppose things aren’t quite as simple as all that. If you dress a knot incorrectly, that can impact its performance, so arguably a reshuffled knot could have different applications, but you’d think variations of the same knot would at least be grouped together. The point I’m making is that the capacity of a human brain to manipulate knotwork is surprisingly limited.
We wired up our 8x9 matrix to the L432 dev board. The blue wire on the right is the BOOT0 pin of the chip, which isn’t broken out, but was needed way back for debugging the flash synth.
The pain of soldering this thing together with enamel wire convinced me to quickly throw a PCB together. Just a generic, diagonally-routed, charlieplexed LED arrangement to avoid having to do this again. Consider that some not-so-subtle foreshadowing. But in the heat of the moment, nothing beats a hand-wired prototype to confirm your idea without delay.
I got our FLIP simulation running on the L432, first as a teeny 8x8 square, then as the upper left corner of an imaginary fluid pendant.
When we think about possible routings for a charlieplexed display, and how this alternative routing mode was hiding in plain sight, it makes us wonder how many other routing options are out there and yet to be discovered. The temptation is to try and use a computer algorithm to seek out new possibilities.
Autorouters are, in general, famously bad, at least outside of basic situations. That may change in the near future when people no doubt throw huge neural networks at the problem. But for autorouting to even be an option we need to accurately describe the constraints. Such as, certain components need to be in certain places. A more important constraint is that the routing needs to match the netlist (schematic). In our case, that schematic is not fixed: thanks to the lookup table, we don’t care which display net ends up at what GPIO pin. But the search space is much bigger than that. We want to constrain all the LEDs to the grid of the display, but we don’t care which LED goes at what position. The lookup table for a “conventional” charlieplexed matrix bares no resemblance to the diagonal criss-cross version.
Constraints reduce the search space, and with enough constraints, solving it via brute force becomes possible. The constraints for what we want to automate here are so broad, so much less constraining than in other circuit designs, that I don’t think we’ll be autorouting a better charlieplexed display anytime soon. There are even further “unconstraints” I haven’t mentioned. In one of the follow-up projects, space was so tight that I ended up routing some of the tracks through the pads of unused GPIO on that microcontroller, thus breaking one of the implicit constraints that different nets shouldn’t touch each other. It’s trivial to tri-state those pins in the firmware for the chip, but knowing that’s on the cards expands our search space even further.
As a reminder, the “conventional” charlieplexed matrix follows a pattern like this:
Adding labels along both edges is conceptually helpful, but only one edge is strictly necessary as connections can be made along the diagonal. This arrangement needs at least one via per LED.
The diagonal arrangement, after squishing into something resembling a circle, looks like this:
Of a possible 240 LEDs on 16 GPIO pins, we only need 216 to fill out our display, but one edge has to be pieced together from the missing corners. I did this somewhat arbitrarily, deleting unused LEDs and shifting the nearest ones into place. In the process we ended up with LEDs that don’t match the pattern. This came back to bite me later, as a solder bridge on that edge is now a problem, and guess where a solder bridge occurred… With a bit more thoughtful placement, I think we could have produced the whole display with end-to-end connections making it immune to soldering mistakes.
The display is supposed to be a circle, but ended up as an octagon by coincidence. For the Simsimsim program, I just placed LEDs based on distance to the centre, a circle from first principles. It happens that at 16, depending on whether you round-down or round-to-centre, you can end up with an octagon. The option to delete some of the corner LEDs and make the display more round was considered, and rejected.
The first PCB design for the pendant, on the whole, was easier than I expected. We’re not boosting the current from the GPIO so there really isn’t all that much that needs to go on the back, and the reduced number of vias makes things so much easier. We also have a good amount of space to shove those vias about as needed.
Rounding the internal layers of a PCB is both comical and, given the existence of an excellent track-rounding plugin, compulsory!
I added the panel manually, specifically because I need a way to hold the board in the pick-and-place machine. You can ask the board house to panelise it for you, but then you’re at the whims of their arrangement, and the component position file will need adjustment to match. I do the mouse-bites manually, just place two drill holes on the border, a ring of stop mask to mark the edge of the pcb. I keep in mind that the normal endmill for routing these boards is 2mm diameter. It’s fairly easy to round most of the internal edges, but on the mouse-bites where we’re mating to another curved outline, there’s no easy way in kicad to fillet those. So far, I’ve not had any complaints with ordering boards like this, I guess it’s very clear what is desired.
The quarter-arcs between each mouse-bite are a real pain to make in kicad. In retrospect I probably should have drawn it in something else and imported a DXF. Within kicad, I first placed the circular outline of the board, then intersected it with the support arms of the panel. I zoomed way in, adjusted the end of the intersecting lines to meet the circle exactly, then used those as start and end points for the arc. Quite tedious really.
For the amulet I used a bent bit of wire to press against the battery. Functional but a bit lame. The correct search term, if you want to find PCB-mounted gold-plated spring terminals, is “RFI shield finger”.
I later upgraded the spring tab to a larger one with more travel but didn’t bother to update the 3D model.
We have plenty of room around the LiR2450 coin cell. The original design was a bit smaller, but I embiggened it while struggling to source the magnetic charging connector. Back in 2023, a bunch of very cheap “smart rings” appeared on aliexpress, some of which used a 4mm magnetic charging connector. I originally ordered them because I wanted to steal the curved battery, which until now was not possible to buy in small quantities. But the appeal of a magnetic charging connector for this pendant was undeniable, if I could source it.
Searching for 4mm magnetic charging connector, or variations upon that theme, returned a bunch of connectors that protruded far further into the case than I was happy with. They were clearly intended as through-mount components, whereas the ring had a total thickness of maybe 3mm.
At the time of writing, the range of connectors available has increased dramatically, and the 4mm connector I spent so long searching for does now appear in the first page of results, so perhaps it was simply a newly launched product that hadn’t been indexed yet. The part number, for future reference, is cx-4mm-jz from WNRE.
Incidentally, the charging cables for the different 4mm connectors are not compatible. Even though they have the same polarity, even the same magnetic polarity, the cable from one doesn’t stick properly to the other. I think the larger connector has a stronger magnetic field, and a correspondingly weaker field on the cable, possibly to reduce the chance of it shorting out on everything metal in the vicinity.
Huge thanks to Martin for giving me free use of his metalworking equipment.
The video shows the process in full, essentially just boring out some brass and making a few grooves. Producing a snap-back was definitely quicker than machining a fine thread. I didn’t have any clear dimensions for how a snap-back should be built, and made some educated guesses. The resulting snap-back test piece did snap together, but was a little loose, it didn’t hold itself under tension. However, the addition of an O-ring completely took up the slack, and gave us a watertight seal in the process. The O-ring means the required tolerances are way more relaxed.
Filming the process was interesting as Martin’s lathe is smaller than the big Colchester I’m used to. It’s a Hardinge lathe, and my magnetic tripod is too large to be useful. Also, the headstock has no flat surfaces.
A couple of magic arms to the rescue.
Positioning the camera this way is very impractical, and makes the process take so much longer. Ideally, we could have one big arm holding it, but the vibrations of the lathe motor mean that if it isn’t supported from multiple positions, the footage ends up all wobbly. If, as I hope, I get to do some more projects on this lathe, I’ll have to come up with something better.
In an earlier edit of the video, I went on a bit of a tangent about being between workshops and eventually cut that whole bit, replacing it with some (hopefully less aggravating) piano music. There’s nothing exaggerated in the rant, but it’s not really the feeling I wanted to convey with a nice metalworking montage.
But for completeness, let me clarify here that the hackspace is where most of my metalworking has previously taken place, and in 2022 the hackspace closed as it was (not for the first time) evicted from the premises. At the time of writing, after much delay the hackspace has now moved into a new location, but at the time of this project I was stumped. I eventually befriended Martin who, as part of his business, has a well-equipped metalworking shop.
My first reaction upon using this lathe is that all of the tools and equipment I’ve used in the past have been rubbish. The hackspace machines aren’t bad quality, but they were pretty well worn even before they were donated to the space. Much of the value in a metal workshop is in the tooling, which is another area where the hackspace falls short.
Unlike the hackspace, Martin’s workshop is used in a commercial setting, which puts the equipment on a completely different level. At the same time, my usage of the workshop, in addition to being limited to business hours and only when the machines aren’t otherwise in use, is a favour, and one that, if we’re honest, I suspect was granted at least in part due to my youtube subscriber count. Which is fantastic in a way, finally we have some genuine credentials, but really life would be so much easier if I had a decent workshop of my own.
Unfortunately, I live in London and in London our houses are tiny and the rent is extortionate. Even if I could afford the equipment, I simply haven’t got the space for it. My Chinese mini-lathe is, quite frankly, a piece of crap. The hackspace machines are a step up, but they’re still the bottom rung.
We lie to ourselves about weighted training shoes, that learning on bad equipment makes us better overall… but it’s nonsense! Anyone can see that if you have access to good tools and equipment you can do better things, more easily.
I believe that access to a lathe is a fundamental human right, and the entire notion of the hackspace limping along on a trickle of donations is abhorrent to me. This is somewhere where the government should just step in. I mean, forget socialised healthcare, I want socialised workshops! The vast majority of people can’t justify owning big milling machines and lathes, even if they can afford it, but at those times when they are needed, they should be there, for all.
Anyway, that all seemed a bit too whiny and political versus the type of content I want to produce, so to the written word it was delegated, and let’s quickly move on with the fun stuff.
Partway through the metalworking I decided to produce a second pendant with a watch glass (“crystal”) covering the display. Watch glasses are available in almost all diameters, with plenty of options for thickness, whether it’s flat or curved, etc. Something I struggled to find any info about is the dimensional tolerances, or in fact any dimensions at all, for the metal part it’s pressed into.
A small test piece was cut. I chose a glass diameter of 27.5mm. I imagine that somewhere out there are some instructions on how to build watches to accommodate such glasses, but here all I could find was about replacing the glass during a watch repair. Between the glass and the metal sits a gasket. With a gasket thickness of 0.45mm, our total diameter would be 28.4mm.
The glass did in fact press in beautifully, with just the right amount of force. The test diameter seemed perfect. The cracked glass didn’t happen until later, when I became overconfident in how easy it was to press the glass in without the special tool. Sometimes it’s good to test these limits to calibrate our judgement.
Anyway, those glass flats are very cheap, so nothing lost really, and I pursued the second pendant case with abandon. When it came to bore the 28.4mm recess on the front, ordinarily it would be an ordeal to re-chuck the part after parting off. But Martin’s extensive collection of soft collets turned it into a non-issue. The idea with soft collets is that you machine them to custom fit the part you’re working on, but apparently by coincidence, several of the soft collets on the shelf matched my 28mm internal diameter already.
The milling process was uneventful and I think I was overly cautious. For subsequent pendants, I raced through this part in no time. The plastic arbour in a square collet-holder worked very well (and was reusable for later pendants).
It’s a pretty pleasing little slot. The O-ring adds some definition to the snap-back, I like the look of it, turning it into a feature. The alternative would be trying to hide it, but that would need much tighter tolerances, and also make opening it more difficult as there’d be no room to insert a case knife.
The jump rings were soldered using “hard” brass solder. Jewellers use multiple different grades of solder, although even “soft” jewellers’ solder is harder than normal electronics solder. The idea is that you can solder the first joints with the hardest (highest melting point) solder, and subsequent joints with softer solder, without the risk of the earlier joints melting.
My gut feeling is that I probably could have done both joints with the hardest solder, but for all of the pendants so far I used soft solder for the second joint. This is electronics solder, and following some disparaging comments on a previous project, I used lead-free solder. This was meant to be a subtle joke, as the brass alloy has a significant quantity of lead in it anyway.
I would later realise that this lead-free solder is completely incompatible with gold plating, it just bounces off the surface. I don’t think it’s a bad look as such, but in the past, the silver-lead solder was able to accept electroplating without any trouble. For the first pendants I made the fillet as tiny as possible, but later became concerned that there might be gaps that would compromise the overall seal, and made the fillets more prominent.
I brush plated these parts with gold. For the first two pendants I really did a poor job of preparing the surface, and the toolmarks were embossed by the plating process. I was somewhat in a hurry to finish as the PCBs were due to arrive very shortly.
Sometimes you get these brown splodges during plating. I’m not entirely sure what causes it.
An expected part of the plating process is to polish the parts afterward with a very fine abrasive (jeweller’s rouge). This removes such marks, and gives us a perfect finish, or at least it would be if not for the tool marks.
We definitely rushed this part, but who cares, the circuit boards had arrived. First off the pick-and-place machine:
More solder bridges than I’d anticipated. I was using a different grade of solder paste than usual (just to experiment) and I think it would have benefited from smaller apertures in the stencil. The 0402 LEDs are quite small, and touching up bridges between them is quite tricky. As mentioned, the majority of them have no impact on the performance as end-to-end LEDs are mostly the same net, all bar the few on the edge where I repositioned them. However, it detracts from the look, so I felt compelled to remove such mistakes from being on show.
One oversight is that I didn’t break out the reset pin of the microcontroller. The display uses all of port A, and the SWDIO/SWCLK debug lines also exist on port A. For general use, that’s not going to matter as we can disable them in software. But for development, this makes it impossible to flash new software onto the board. The trick is to reset the chip right before you program it, but here that means adding a bodge wire.
The first circuit board became my dev board. At this stage I still hadn’t sourced the desired magnet connector, but the older magnet connector proved the charging circuit worked. With a 3D printed coin-cell holder, I was able to power the dev board from the battery too.
The bus keeper on the accelerometer’s interrupt line caused a few (of several) display glitches. A resistor was bodged onto the track which helped a bit.
Ultimately I added a diode there, which completely fixed the issue. At one point I replaced that resistor with an LED, which had the added bonus of letting me see the signal as I nudged the board.
I gave a quick montage of some of the other bodges I applied to the circuit in the video, mostly trying to ensure that the circuit couldn’t be tricked into a soft-lock. The battery undervoltage detection being in software made our circuit simpler, but made me sufficiently uneasy that the next revision of the PCB did it in hardware. The beauty of the simple case design, with no buttons and no easy way to open it, comes with a certain amount of paranoia. I really wanted a way to reset the chip if needed, so the circuit listening for the charging connector was constructed.
Some datasheets/devboards suggest always having a 100n cap on the reset line of an STM32 chip. I’m not sure whether it’s needed, but I think I’d rather have a predictable, reasonable capacitance on the pin than a small amount of unknown capacitance. The pulse of connecting the charger passes through a small capacitor on the base of an NPN transistor, which amplifies the current to pull down the reset pin. Not shown in the picture above, I added a 100n cap to the reset line as recommended, and a pulldown resistor on the transistor side of the signal cap, to try and maximise the pulse voltage when the charger connects.
It’s very easy to short the charging connector as it approaches, and in that case the polyfuse heats up and drops the output voltage. Even though it starts charging as the voltage returns, the slowly rising power is not enough to trigger the reset circuit. I decided that this is fine, because if you really need to reset it, just connect the magnet end of the cable first, then plug in the USB. And, in the redesign of the PCB, the hardware undervoltage detection means that resetting the chip should never be a requirement, this circuit is just there to placate my paranoia.
Jumping ahead somewhat, we epoxied the magnet connector in place, and also filled the little hole for the charging LED with epoxy too. Under the microscope, there’s a tiny meniscus of resin there.
The circuit board is soldered to the case in a few strategic locations, for mechanical stability, and to make electrical contact with the battery ground.
After a few assemblies and disassemblies, the foam pads were corrected, the spring pin was replaced with a taller one, the overall display brightness was reduced, and the various other display glitches were corrected.
It is somewhat scary to close up the back and have no access to anything except that charge connector. The only input to the device is the accelerometer data. I had planned to activate the “deep sleep” mode by spinning the pendant on the end of a chain, which would be very easy to detect compared to most gestures, just the Y coordinate beyond a threshold for some amount of time. It would be swish if that was how to wake it up as well. Unfortunately, that would mean more complex wakeup logic. We’d need to wake up, then check the condition and go back to sleep if it wasn’t met.
But I was quite pleased to think of simply increasing the threshold of the accelerometer’s movement detection interrupt. By setting it to 6g, it will be unlikely to wake up accidentally, but it’s easy enough to shake it back to life. Shake-to-wake. This is a great solution because it uses no more power than the regular sleep.
But we can do better!
Before assembling the second pendant with the promised watch glass, I wanted to revise the PCB, incorporating our reset circuit, the wakeup line diode, and the hardware supervisor chip.
In the same series as the incredible TPS7A02, the TPS3839 supply voltage monitor chip comes with some similarly impressive specifications, and in the same tiny package. Its supply current of 150nA may sound a lot compared to the 25nA of the regulator, but then you take a step back and realise both of these numbers are basically zero. The coin cell has a capacity of 120mAh, so even a 1000nA would take over 13 years to drain it. And on such timescales extrapolating doesn’t really make any sense, due to self-discharge, nonlinear effects and so on.
That regulator is essentially an ideal component, both the dropout and the quiescent current are infinitesimally small. But it is quite a bit more expensive than a normal regulator, by which I mean it costs maybe $1.
I chose the supervisor to cut off at 3.08V, which is conservative enough that if the battery gets this low, we still have enough capacity to sit on a shelf for a few years without hurting the chemistry. A lot of lithium protection circuits cut out at 2.5V, in fact you might be wondering why I’m not using an off-the-shelf Li-ion protection circuit, of which there are many. It’s generally accepted that you shouldn’t let the open-circuit voltage of a lithium battery drop below 3.0V, but in use, if there’s a load on the battery, the voltage at the terminals is lower than the open-circuit voltage. For this reason, most batteries set their undervoltage protection at 2.5V, to stop it kicking in too soon when the battery has a heavy load.
In the case of our ~10mA load, and my reasoning above about not wanting to run it totally flat, a 3.08V threshold makes perfect sense. Protection circuits usually add a couple of low-voltage mosfets in the path to the battery, which themselves will eat some of the power. My plan was to connect the supervisor chip to the enable pin of the regulator. I had tried earlier to pulse the enable pin of the regulator when the charging cable is connected with no success. I later figured out that there are two versions of the TPS7A02: the TPS7A0233DQNR, and the TPS7A0233PDQNR. The P version has an “active discharge” circuit for when the regulator is disabled. The non-P version simply lets the microchip, and its power supply capacitors, sit there until they run down. If the microcontroller is in deep sleep, that could take a significant time.
I might have been creating an artificially fast rundown as I varied the voltage to the circuit, but I found that the non-P version of the regulator I was originally using caused a number of problems when the supervisor kicked in. There may or may not be some brownout monitoring circuitry on the STM32, but it was definitely possible to latch the circuit into another softlock by waving the voltage around the threshold. I ordered the P-version of the regulator, swapped it over with the heat gun, and the problems went away.
The two X2SON parts were placed probably too close together, that made rework more difficult than it needed to be.
It’s not like I was trying to mass produce these things, but assembling several at once is more efficient on the odd chance that a third or fourth pendant might happen.
...
Read the original on mitxela.com »
Discussions on X, LinkedIn, YouTube. Also: Meet AI Engineers in person! Applications closing soon for attending and sponsoring AI Engineer Summit NYC, Feb 20-21.
The picks from all the speakers in our Best of 2024 series catches you up for 2024, but since we wrote about running Paper Clubs, we’ve been asked many times for a reading list to recommend for those starting from scratch at work or with friends. We started with the 2023 a16z Canon, but it needs a 2025 update and a practical focus.
Here we curate “required reads” for the AI engineer. Our design goals are:
* tell you why this paper matters instead of just name drop without helpful context
* be very practical for the AI Engineer; no time wasted on Attention is All You Need, bc 1) everyone else already starts there, 2) most won’t really need it at work
We ended up picking 5 “papers” per section for:
You can both use and learn a lot from other LLMs, this is a vast topic.
We covered many of these in Benchmarks 101 and Benchmarks 201, while our Carlini, LMArena, and Braintrust episodes covered private, arena, and product evals (read LLM-as-Judge and the Applied LLMs essay). Benchmarks are linked to Datasets.
Note: The GPT3 paper (“Language Models are Few-Shot Learners”) should already have introduced In-Context Learning (ICL) - a close cousin of prompting. We also consider prompt injections required knowledge — Lilian Weng, Simon W.
Section 3 is one area where reading disparate papers may not be as useful as having more practical guides - we recommend Lilian Weng, Eugene Yan, and Anthropic’s Prompt Engineering Tutorial and AI Engineer Workshop.
RAG is the bread and butter of AI Engineering at work in 2024, so there are a LOT of industry resources and practical experience you will be expected to have. LlamaIndex (course) and LangChain (video) have perhaps invested the most in educational resources. You should also be familiar with the perennial RAG vs Long Context debate.
We covered many of the 2024 SOTA agent designs at NeurIPS, and you can find more readings in the UC Berkeley LLM Agents MOOC. Note that we skipped bikeshedding agent definitions, but if you really need one, you could use mine.
CodeGen is another field where much of the frontier has moved from research to industry and practical engineering advice on codegen and code agents like Devin are only found in industry blogposts and talks rather than research papers.
Much frontier VLM work these days is no longer published (the last we really got was GPT4V system card and derivative papers). We recommend having working experience with vision capabilities of 4o (including finetuning 4o vision), Claude 3.5 Sonnet/Haiku, Gemini 2.0 Flash, and o1. Others: Pixtral, Llama 3.2, Moondream, QVQ.
We do recommend diversifying from the big labs here for now - try Daily, Livekit, Vapi, Assembly, Deepgram, Fireworks, Cartesia, Elevenlabs etc. See the State of Voice 2024. While NotebookLM’s voice model is not public, we got the deepest description of the modeling process that we know of.
With Gemini 2.0 also being natively voice and vision multimodal, the Voice and Vision modalities are on a clear path to merging in 2025 and beyond.
We also highly recommend familiarity with ComfyUI (upcoming episode). Text Diffusion, Music Diffusion, and autoregressive image generation are niche but rising.
We recommend going thru the Unsloth notebooks and HuggingFace’s How to fine-tune open LLMs for more on the full process. This is obviously an endlessly deep rabbit hole that, at the extreme, overlaps with the Research Scientist track.
This list will seem intimidating and you will fall off the wagon a few times. Just get back on it. We’ll update with more thru 2025 to keep it current. You can make up your own approach but you can use our How To Read Papers In An Hour as a guide if that helps. Many folks also chimed in with advice here.
* If you’re looking to go thru this with new friends, reader Krispin has started a discord here: https://app.discuna.com/invite/ai_engineer and you’re also ofc welcome to join the Latent Space discord.
* Reader Niels has started a notes blog where he is pulling out highlights: https://niels-ole.com/2025/01/05/notes-on-the-2025-ai-engineer-reading-list
Did we miss anything obvious? It’s quite possible. Please comment below and we’ll update with credit to help the community.
Thanks to Eugene Yan and Vibhu Sapra for great suggestions to this list.
...
Read the original on www.latent.space »
Data informing the GDD modeling estimates for this study, including from LMICs (low- and middle-income countries), were collected between 1980 and 2018 from GDD consortium members and publicly available sources in the form of dietary intake surveys. If nationally representative surveys were not available for a country, we also considered national surveys without representative sampling, followed by regional, urban or rural surveys, and finally large local cohorts, provided that selection and measurement biases were not apparent limitations (for example, excluding studies focused on a selected population with a specific disease, a certain profession or following a particular dietary pattern). For countries with no surveys identified, other sources of potential data were considered, including the WHO Infobase, the STEP database and household budget survey data. As of August 2021, we identified and retrieved 1,634 eligible survey years of data from public and private sources. Of these, 1,224 were checked, standardized and included in the GDD model, including 450 surveys informing SSB intake estimates12.
Most surveys identified were privately held or, if public, not available in relevant format for GDD modeling (for example, not jointly stratified by age, sex, education, and urban or rural status). We thus relied almost entirely on direct consortium member contacts for each survey to provide us with exposure data directly. Roles and responsibilities of GDD consortium members were determined and agreed upon before data sharing as part of a standardized data sharing agreement. The draft manuscript was shared with all GDD consortium members before submission for peer review, and all members are included as coauthors of this work. We endorse the Nature Portfolio journals’ guidance on LMIC authorship and inclusion and are committed to the inclusion of researchers from LMICs in publications from the GDD. We share the GDD data with the entire consortium, encourage authors from LMICs to take the lead on analyses and papers, and can provide technical and writing support to LMIC authors. For more details on the collaborative GDD data collection process, please visit our website at https://www.globaldietarydatabase.org/methods/summary-methods-and-data-collection.
This research is locally relevant to all countries included, given that it disaggregates findings nationally and subnationally by key demographic factors such as age, sex, education level and urbanicity, providing decision-makers with the CVD and diabetes risk associated with SSB intakes over time.
This modeling investigation was exempt from ethical review board approval because it was based on published data and nationally representative, de-identified datasets, without personally identifiable information. Individual surveys underwent ethical review board approval required for the applicable local context.
A CRA model14 estimated the numbers, proportions and uncertainty of global T2D and CVD incidence, DALYs and mortality attributable to intake of SSBs among adults aged 20+ years. Importantly, the CRA framework does not use ecologic correlations to estimate risk, but incorporates independently derived input parameters and their uncertainties on sociodemographics, population size, risk factor (that is, SSBs) their multivariable-adjusted estimated etiologic effects on disease based on external studies, and background disease incidence, mortality and DALYs14. These parameters are entered into the model to estimate the disease burdens and their uncertainties. Specifically for this investigation, we leveraged input data and corresponding uncertainty in 184 countries including (1) population SSB intake distributions based on individual-level survey data from the GDD (https://www.globaldietarydatabase.org/)7,12,13; (2) optimal SSB intake levels from previous analyses67; (3) direct age-adjusted etiologic effects of SSBs on T2D, ischemic heart disease and ischemic stroke adjusted for BMI2,68,69,70, and of weight gain on T2D15, ischemic heart disease16 and ischemic stroke15 from previous meta-analyses and pooled analyses of prospective cohorts, as well as linear, BMI-stratified effects of SSBs on weight gain or loss17; (4) population overweight (BMI ≥ 25 kg m−2) and underweight (BMI −2) distributions from the (non-communicable disease) NCD Risk Factor Collaboration (NCD-RisC)71; (5) total T2D, ischemic heart disease, and ischemic stroke incidence, DALYs and mortality estimate distributions from the GBD study72,73; and (6) population demographic data from the United Nations Population Division74,75 and the Barro and Lee Educational Attainment Dataset 201376, as previously reported31 (Supplementary Table 7).
Bias and reliability were addressed in each of the independent data sources used in our model. The GDD selected national and subnational dietary surveys without apparent measurement or selection biases7, and leveraged a Bayesian model to incorporate differences in data comparability and sampling uncertainty. In GBD, bias adjustment of underlying rates of T2D and CVD not specifically meeting the gold-standard definition of these causes was done using network meta-regression before estimation in DisMod, while implausible or unspecified causes of death were redistributed to valid underlying causes of death using reclassification algorithms73,77. Etiologic effects were obtained from published meta-analyses or pooled analyses of prospective cohorts and randomized control trials including multivariable adjustment for age, sex, BMI and other risk factors to reduce bias from confounding2,68,69,70. Studies with increased risk of bias such as retrospective or cross-sectional studies were excluded2. Underlying adiposity rates were obtained from the NCD-RisC, which used national or subnational surveys that collected measured height and weight data to avoid bias in self-reported data71.
The GBD study uses a different approach to dietary assessment, primarily relying on adjusted United Nations (UN) and FAO national per capita availability of sugar as primary data to estimate SSBs, with a limited set of individual-level dietary surveys (N = 44). In comparison, the GDD uses a much more comprehensive database of largely individual-level dietary surveys to estimate SSB intake (N = 450), with other data (such as UN FAO sugar) used as covariates rather than as primary data. Thus, in addition to novel stratification by educational level and area of residence, the GDD dietary estimates may be more valid and informative. Our investigation leverages published diet–disease etiologic effects from extensive meta-analyses identified through reviews conducted by our team, includes both direct and BMI-mediated effects, and incorporates new data on prevalence of overweight and obesity from the NCD-RisC. Our study also estimates incident cases, which is not a measure reported in previous global studies.
Compared with our previous 2010 estimates3, our present investigation includes major expansion of individual-level dietary surveys and global coverage through 2018; updated modeling methods, covariates and validation to improve estimates of stratum-specific mean intakes and uncertainty; inclusion of updated dietary and disease data that are jointly stratified subnationally by age, sex, education level, and urban or rural residence; and updated SSB etiologic effect estimates on T2D, ischemic stroke and ischemic heart disease. This present analysis focused on adults aged 20+ years given the low rates of T2D and CVD globally at younger ages.
The GDD systematically searched for and compiled representative data on individual-level dietary intakes from national surveys and subnational surveys7,12. The final GDD model incorporated 1,224 dietary surveys representing 185 countries from 7 world regions and 99.0% of the global population in 2020. Of these, 450 surveys reported data on SSBs, totaling 2.9 million individuals from 118 countries representing 86.8% of the global population. Most surveys were nationally or subnationally representative (94.2%), collected at the individual level (84.7%), and included estimates in both urban and rural area of residence (61.6%). Further details on characteristics of surveys with data on SSBs, including availability of surveys per world region, are available in Supplementary Table 1. The world region classification used in our study was based on groupings that are likely to have consistent exposures to disease risk and rates of disease outcomes, and this or similar classifications have been previously used by our team and others73. Countries included in each world region are listed in Supplementary Table 2. Global, regional and national estimates among the 30 most populous countries, by population characteristics in 2020, are available in Supplementary Tables 3 and 4.
SSBs were defined as any beverages with added sugars and ≥50 kcal per 8 oz serving, including commercial or homemade beverages, soft drinks, energy drinks, fruit drinks, punch, lemonade and aguas frescas. This definition excluded 100% fruit and vegetable juices, noncaloric artificially sweetened drinks and sweetened milk. All included surveys used this definition. We used an average sugar content per SSB serving, an assumption that probably has little influence on large-scale demographic estimates such as these but could be a problem for more focused local studies. Home-sweetened teas and coffees (which often would have less than 50 kcal per serving) were not explicitly excluded from the SSB definition at the time of data collection, but total tea and coffee intake were separately collected in the dietary surveys and by the GDD as separate variables. Compared with soda and other industrial SSBs, 100% fruit juices and sugar-sweetened milk, coffee and tea have shown inconsistent evidence for health effects, and were therefore excluded from our definition of SSBs2,9. Differences in health effects may relate to additional nutrients in those drinks, such as calcium, vitamin D, fats, and protein in milk, caffeine and polyphenols in coffee and tea, and fiber and vitamins in 100% juice, or to differences in the rapidity of consumption and/or drinking patterns of these beverages. Notably, each of these other beverages is also generally excluded in policy and surveillance efforts around SSBs12. At high intakes, alcoholic beverages have been associated with T2D and CVD in prospective cohorts and genome-wide association studies78,79. However, the effect of alcoholic beverages on T2D and CVD differs from the effect of SSBs on these diseases, and thus, alcohol and SSB should be analyzed separately2,79,80. Moreover, the exclusion of alcoholic beverages ensures comparability across diverse populations, given variations in alcohol consumption due to religious and cultural factors81. Regulatory shortcomings in labeling 100% fruit and vegetable juices may have led to underestimations in SSB intake and attributable burdens for certain populations82,83.
For our present analysis, we updated SSB intake estimates for 2020 using similar methodology as previously reported12, but with updated food availability data released by FAO for 2014–2020 as covariates. Because FAO updated its methodology for these new estimates, the FAO estimates from this period versus their estimates from earlier years are not directly comparable (for example, a ‘step change’ in FAO estimates was noted comparing 2013 versus 2014 data for most countries). To account for this and retain the relative ranking between nations, we calculated a nation-specific adjustment factor for each FAO covariate, based on the ratio of that nation’s 2013 versus 2014 data, and applied this to each nation’s FAO estimates from 2014 to 2020.
A Bayesian model with a nested hierarchical structure (with random effects by country and region) was used to estimate the mean consumption level of SSBs and its statistical uncertainty for each of 264 population strata across 185 countries from 1990 through 2020, incorporating and addressing differences in data comparability and sampling uncertainty12,84. The model then estimated intakes jointly stratified by age (22 age categories from 0 to 6 months through 95+ years), sex (female, male), education (≤6 years of education, >6 years to 12 years, >12 years) and urbanicity (urban, rural). Although this analysis focuses only on adults aged 20+ years, the model used all age data to generate the strata estimates.
Of the 188 countries with survey data, 3 were dropped from the GDD estimation model owing to unavailability of FAO food availability data (Andorra, Democratic People’s Republic of Korea and Somalia), an important covariate in the estimation model. Uncertainty of each stratum-specific estimate was quantified using 4,000 iterations to determine posterior distributions of mean intake jointly by country, year and sociodemographic subgroup. The median intake and the 95% UI for each stratum were computed at the 50th, 2.5th and 97.5th percentiles of the 4,000 draws, respectively.
Global, regional, national and within-country population subgroup intakes of SSBs and their uncertainty were calculated as population-weighted averages using all 4,000 posterior estimates for each of the 264 demographic strata in each country–year. Population weights for each year were derived from the United Nations Population Division74,75, supplemented with data for education and urban or rural status from a previous study85. Intakes were calculated as 8 oz (248 g) servings per week. For our present analysis, GDD SSB estimates were collapsed for adults aged 85+ years using the 4,000 simulations corresponding to the stratum-level intake data derived from the Bayesian model. In this study, regression-based methods were used to estimate the standard deviation corresponding to each estimated, stratum-specific mean from the dietary survey input data. These mean–standard deviation pairs were then used to generate gamma distribution parameters for usual dietary intake as detailed in the following section.
Dietary intakes cannot be negative, and the usual intake distributions tend to be skewed to the right86,87. Gamma distributions were shown to be more appropriate than normal distributions for SSBs based on the analysis of GDD input data (for example, NHANES data) in a previous study88 and other research on assessment of population dietary intake89,90, as it is nonnegative and includes a wide range of shapes with varying degrees of skewness91. Standard deviation (s.d.) needed to be obtained to construct the gamma distribution of intakes. Parameters for gamma distribution were generated using the mean estimate from the GDD estimation model and the estimated s.d. for the mean estimate from 1,000 simulations.
Stratum-level GDD input survey data were used to fit a linear regression of the s.d. of intake on mean intake (both adjusted for total energy). To determine the appropriate transformation of the input data used for fitting the linear regression, scatter plots of energy-adjusted means versus energy-adjusted s.d. were created. Using this approach, we concluded that a natural log transformation for both mean and s.d. was most appropriate. We also explored excluding demographic and health surveys, household surveys and outlier data owing to the potential unreliability of such surveys for estimating s.d., but determined that no one dietary assessment method contributed unevenly to the observed linear trend. Thus, all available data were included, allowing for the largest possible sample size and greatest generalizability. We also investigated whether the log mean and log s.d. relationship differed by world region, but did not find strong evidence for such heterogeneity. A regression model was used for each individual diet factor to calculate the s.d.:
where i refers to each survey stratum, Y is the natural log of the s.d. of stratum-specific intake, x is the natural log of the mean of stratum-specific intake and ε is the random error that follows N(0, σ2).
Estimates for β and β were used to predict 1,000 ln(s.d.) values corresponding to 1,000 iterations (k) of the predicted mean intake for each population stratum (j) using Monte Carlo simulations.
in which \(\widehat{{X}_{{jk}}}\) is the kth sample draw of the posterior distribution for mean intake for population stratum j. We propagated uncertainty from the model estimates, as well as variation within the sampling data itself, by randomly drawing from a t-distribution with n − 1 degrees of freedom using the following equation:
in which \(\hat{\sigma }\) is the estimate for σ, n is the number of survey strata, \({t}_{k}^{n-1}\) is the kth sample drawn from a t-distribution with n − 1 degrees of freedom and \(\widehat{{s.d.}_{{jk}}}\) is the kth sample draw of the predicted s.d. distribution for population stratum j.
The posterior distributions for each stratum-specific s.d. were used to generate 1,000 corresponding shape and rate gamma parameters for the distribution of usual intake, a primary input in the CRA model, using the following equations:
The direct risk estimates between SSB intake and T2D, ischemic heart disease and ischemic stroke were obtained from published systematic reviews and evidence grading, based on published meta-analyses of prospective cohort studies and randomized controlled trials including multivariable adjustment for age, sex, BMI and other risk factors to reduce bias from confounding (Supplementary Table 8)2,68,69,70. The methods and results for the review, identification and assessment of evidence for the SSB–disease relationships have been described2,67. Briefly, evidence for each SSB–disease relationship was first evaluated by grading the quality of evidence according to nine different Bradford Hill criteria for causation: strength, consistency, temporality, coherence, specificity, analogy, plausibility, biological gradient and experiment. This evidence grading was completed independently and in duplicate by two expert investigators. Based on these assessments, probable or convincing evidence was determined independently and in duplicate, in accordance with the criteria of the FAO and World Health Organization92 and with consideration of consistency with similar criteria of the World Cancer Research Fund and the American Institute for Cancer Research93. SSBs had at least probable association for direct etiologic effects (BMI independent) on T2D, ischemic heart disease and ischemic stroke risk, as well as on weight gain. See Supplementary Table 9 for further details on the evidence grading criteria and results of this evaluation. All SSB–disease estimates were standardized from the originally reported 250 ml serving size to 8 oz servings (248 g), the unit used in our analysis.
Given that these studies adjusted for BMI, we separately assessed the BMI-mediated effects (BMI change in kg m−2) based on pooled analyses from long-term prospective cohort studies of changes in diet and changes in BMI (Supplementary Table 8)17. Specifically, we used data from three separate prospective cohort studies: the Nurses’ Health Study (1986–2006), involving 50,422 women with 20 years of follow-up; the Nurses’ Health Study II (1991–2003), including 47,898 women with 12 years of follow-up; and the Health Professionals Follow-up Study (1986–2006) with 22,557 men with 20 years of follow-up. Participants included in these analyses were initially free of obesity (that is, BMI −2) or chronic diseases and had complete baseline data on weight and lifestyle habits. The associations between SSBs and weight gain were estimated separately for overweight and obese (BMI ≥ 25 kg m−2) and non-overweight adults (BMI −2), given observed effect modification by baseline BMI status17. We used linear regression with robust variance, accounting for within-person repeated measures, to assess the independent relationships between changes in SSB intake and changes in BMI over 4 year periods. Women who became pregnant during follow-up were excluded from the analysis. BMI-mediated effects did not specifically differentiate between overweight and obesity, which could have led to an underestimation in the BMI-mediated effects among adults with obesity.
To examine the BMI-mediated associations, we assessed the impact of differences in BMI on the risk of T2D, ischemic heart disease and ischemic stroke (Supplementary Table 8)15,16. These relationships were obtained from pooled analyses of multiple cohort studies investigating the quantitative effects of BMI on T2D15, ischemic heart disease16 and ischemic stroke15. The risk estimates were transformed from the originally reported 5 kg m−2 to 1 kg m−2.
Age-specific relative risks were calculated for each SSB–disease etiologic relationship based on evidence showing decreasing proportional effects of metabolic risk factors on cardiometabolic disease incidence at older ages (for example, due to other competing risk factors)15,67. The age-specific relative risks were calculated based on the age at event and were assumed to have a log-linear age association, although the true age relationship may differ.
To calculate the age at event for each SSB–disease pair, we obtained relevant data from the original studies. This included the average age at baseline in years, the follow-up time in years, the type of follow-up time reported (for example, maximum, median or mean) and the study weight for each study in each meta-analysis (Supplementary Tables 10–12 and Supplementary Data 4). In cases in which the age at baseline was reported as a range rather than as the average, we used the central value to estimate the mean. If follow-up time to events was not reported, we estimated it based on the duration of the study. For studies that reported maximum follow-up time, we estimated the mean time to event as half of the maximum follow-up, and for studies that reported mean or median follow-up times, as two-thirds of the mean or median follow-up. The unweighted mean age at event for each study was calculated by summing the mean age at baseline and the appropriate mean time to event, and the weighted mean age at event for the meta-analysis as the weighted age at event across all studies. In cases in which specific studies were excluded from the meta-analysis owing to limitations in study quality, or when the meta-analysis was conducted for multiple outcomes, the weights were adjusted accordingly. When study weights were not reported, we assigned equal weights to each study when calculating the mean overall age at event.
Given limited evidence of significant effect modification by sex, we incorporated similar proportional effects of risk factors by sex67. In previous research, we evaluated the proportional differences in relative risk for key diet-related cardiometabolic risk factors, including systolic blood pressure, BMI, fasting plasma glucose and total cholesterol, across six 10 year age groups from 25–34 years to 75+ years67. Given similarities across these four risk factors, the mean proportional differences in relative risk across all risk factors were applied to the SSB–disease relative risks. In this study, we disaggregated the mean proportional differences into 14 5 year age groups from 20–24 years to 85+ years. This was achieved by linearly scaling between each 10 year mean proportional difference in log relative risk, anchoring at the calculated mean age at event for each SSB–disease.
We used Monte Carlo simulations to estimate the uncertainty in the age-distributed log relative risk, sampling from the distribution of log relative risk at the age at event. On the basis of 1,000 simulations, we used the 2.5th and 97.5th percentiles to derive the 95% UI.
Prevalence of overweight (BMI ≥ 25 kg m−2) and underweight (BMI −2) in each country–year–age–sex–urbanicity stratum and their uncertainty was obtained from the NCD-RisC. The NCD-RisC collected data from 1,820 population-based studies encompassing national, regional and global trends in mean BMI, with measurements of height and weight taken from over 97 million adults71,94. Surveys were excluded if they relied solely on self-report data, focused on specific subsets of the population or involved pregnancy. The NCD-RisC used a Bayesian hierarchical model to estimate age-specific mean BMI and prevalence of overweight and obesity by country, year and sex. The model incorporated data-driven fixed effects to account for differences in BMI by rural and urban area of residence. A Gibbs sampling Markov Chain Monte Carlo algorithm was used to fit the model, producing 5,000 samples of the posterior distributions of the model parameters. These samples were then used to generate posterior distributions of mean BMI and prevalence of overweight and obesity for each stratum. Estimates were age standardized using age weights from the WHO standard population. Weighting was also used at the global, regional and national levels, taking into account the respective age-specific population proportions by country, year and sex. The estimates of mean BMI and overweight and obesity prevalence were presented along with their respective 95% credible intervals, representing the uncertainty around the estimates. To further stratify the NCD-RisC overweight and obesity prevalence estimates by education level and urbanicity, we assumed that the prevalence did not vary across different education levels or between urban and rural residences. In addition, it was assumed that these estimates remained constant between 2016 and 2020 (as NCD-RisC reports only through 2016, but this CRA analysis assesses estimates for 2020), a conservative assumption that probably underestimates the prevalence of overweight and obesity and, thus, SSB-attributable burdens.
The optimal intake level of SSBs served as the counterfactual in our CRA modeling analysis, allowing the quantification of impacts of SSBs on disease risk at the population level. We determined the optimal intake level based on probable or convincing evidence for effects of SSBs on cardiometabolic outcomes. The methodology for defining the optimal intake level has been described67. Briefly, it was determined primarily based on disease risk (observed consumption levels associated with lowest disease risk in meta-analyses) with further considerations of feasibility (observed national mean consumption levels in nationally representative surveys worldwide)95,96, and consistency with existing major food-based dietary guidelines97,98. The term ‘optimal intake’ can be considered analytically analogous to what has been referred to as the ‘theoretical minimum risk exposure level’ in other analyses99,100. We prefer the former term as it is more relevant to dietary risks, which can serve as a benchmark for quantifying disease risk, informing dietary guidance and informing policy priorities.
The estimates of underlying cardiometabolic disease burdens at global, regional and national levels were obtained from the GBD 2021. The GBD collected data from censuses, household surveys, civil registration, vital statistics and other relevant records to estimate incidence, prevalence, mortality, years lived with disability (YLDs), years of life lost (YLLs) and DALYs for 371 diseases and injuries73. These estimates were stratified by 204 countries and territories, 23 age groups and sex, yearly from 1990 to 2021. For this analysis, we used GBD estimates of incidence, mortality and DALYs for T2D, ischemic heart disease and ischemic stroke for 1990 and 2020. The GBD defined T2D as fasting plasma glucose greater than or equal to 126 mg dl−1 (7 mmol l−1) or reporting the use of diabetes medication73. Estimated cases of type 1 diabetes were subtracted from the overall diabetes cases at the most stratified level of age, sex, location and year to estimate T2D cases. Ischemic heart disease was estimated in the GBD as the aggregate of myocardial infraction (heart attack), angina (chest pain) or ischemic cardiomyopathy (heart failure due to ischemic heart disease). Ischemic stroke was defined as rapidly developing clinical signs of (usually focal) cerebral function disturbance lasting over 24 h, or leading to death, according to the WHO criterion of sudden occlusion of arteries supplying the brain due to a thrombus101.
GBD mortality estimates were generated using the Cause of Death Ensemble Model framework, which incorporated various models including different sets of covariates testing the predictive validity, and generating cause-specific mortality estimates73,102,103. Cause of Death Ensemble Model estimates were scaled among all causes such that the sum of cause-specific deaths did not exceed all-cause mortality. YLLs were calculated as the product of the number of deaths for each cause by age, sex, location and year times the standard life expectancy. Life expectancy was first decomposed by cause of death, location and year to represent the cause-specific effects on life expectancy102. Then, the sum across age groups was taken to estimate the impact of a given cause on the at-birth life expectancy from 1990 to 2021. Incidence was modeled using DisMod, a meta-regression tool that used epidemiologic data to estimate the occurrence disease within a population and determines whether cases remain prevalent, go into remission or result in death. YLDs were calculated by splitting the prevalence of each cause into mutually exclusive sequela, each defined by a health state; each health state was then weighted by the corresponding disability weight73. Finally, DALYs were calculated as the sum of YLLs and YLDs.
The GBD provides underlying disease estimates at global, regional and national levels for 1990 to 2021, jointly stratified by age and sex. Extensive previous evidence shows that T2D and CVD outcomes vary by educational attainment and urbanicity104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122. We further stratified the 1990 and 2020 GBD estimates by education level (low, medium, high) and area of residency (urban, rural) to examine potential variations in risk within these subpopulations and to align with the demographic and GDD dietary data stratifications available. This approach required assumptions on distributions of disease burdens by these demographic factors and potentially underestimated uncertainty in our results stratified by these factors.
To stratify the GBD estimates, we conducted a search of scientific literature to identify recent meta-analysis, pooled analyses and large surveys evaluating the association between educational attainment and urbanicity with the risk of T2D and CVD. Because we hypothesized that country income level was a potential effect modifier for the relationships of educational attainment and urbanicity with T2D and CVD risk, we further collected and collated risk estimates stratified by country income level. We limited our analysis to studies adjusting only for age and sex, when possible, to avoid the attenuating effects of adjusting for additional covariates104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122.
We conducted fixed-effects meta-analysis of collated effect sizes (associations between education or urbanicity and disease rates), stratified by country income level. Published estimates were standardized to high versus low education level, matched as closely as possible to the GDD definitions (low: 0–6 years of education; high: >12 years of education), as well as to urban versus rural residence. We pooled estimates within studies when (1) multiple estimates were reported for different CVD outcomes, (2) separate estimates were provided for men and women, (3) estimates were reported for different locations (except by country income) or (4) an intermediate category matched our definitions for education level or area of residence. The characteristics of the studies used to calculate the effect estimates, including their original and calculated effect sizes, can be found in Supplementary Data 5 and 6 for education level and area of residence, respectively.
We conducted a separate fixed-effect meta-analysis for the relationship of education or urbanicity to T2D and CVD, stratified by country income level. We distributed the central estimate of our meta-analyzed risk estimate equally for high versus low education, and urban versus rural residence, by taking its square root and inverse square root (Supplementary Table 13). This approach assumed similar differences from high to medium education as from medium to low education. We also explored distributing the central estimate by incorporating information on the actual distance (for example, grade years) from high to medium education and medium to low education, when such information was available. As the results did not appreciably differ, we used the square root and inverse square root approach to maintain consistency across studies, particularly given heterogeneity in categorizations of education levels. The final calculated effect estimates for the association between education level and area of residence with T2D and CVD, by income country level, can be found in Supplementary Table 13.
The T2D, ischemic heart disease and ischemic stroke estimates for each year–country–age–sex stratum (mean and 95% UI) were multiplied by their respective population proportion, education effect and urban effect. This process created six de novo strata with the raw (unscaled) fully proportioned burden estimates and their uncertainty. The global population proportions for each year were derived from the United Nations Population Division75, supplemented with data on education attainment from a previous study76. Finally, to prevent under- or overestimation of the absolute number of T2D, ischemic heart disease and ischemic stroke cases globally, the raw fully proportioned burden estimates were scaled to match the total burden estimate for each stratum. This scaling ensured that the overall burden estimates remained consistent. Supplementary Table 14 provides a fictitious, illustrative example of how 1,000 T2D cases in a single age–sex population stratum (low-income country) in a given year were disaggregated into the 6 finer education–urbanicity strata using the central estimate of the meta-analyzed education and urban effects. The population proportioned only burden estimates is also provided as a comparison. While uncertainty was incorporated in all the modeling parameters, we were unable to include uncertainty in the stratification of T2D and CVD cases by educational attainment and urban or rural residence as rigorous data to do so were not available.
The CRA framework incorporated the data inputs and their uncertainty to estimate the absolute number, rate (per million adults 20+ years) and proportion of T2D, ischemic heart disease and ischemic stroke cases attributable to intake of SSBs in 1990 and 2020 (Supplementary Fig. 18). For each stratum, the model calculated the percentage (population attributable fraction (PAF)) of total T2D, ischemic heart disease and ischemic stroke incidence, mortality and DALYs attributable to intake of SSBs. For BMI-mediated effects, the model considered the associations between observed SSB intakes and changes in BMI at the stratum level. This association was weighted by the prevalence of overweight (BMI ≥ 25), normal weight (BMI >18.5 to
Given that summing direct and BMI-mediated PAFs would overestimate the combined effect, for each disease stratum (that is, country–year–age–sex–education–residence), the PAF was calculated using proportional multiplication of the direct and BMI-mediated PAFs as follows:
The resulting PAF was then multiplied by the corresponding number of disease cases to calculate the attributable burden in each stratum. Findings were evaluated globally, regionally and nationally, and by specific population subgroups of age, sex, education and urbanicity. The results are presented as proportional attributable burden (percentage of cases) and attributable rate (per one million adults). This representation of the proportional multiplication for a single risk factor (that is, SSBs) is equivalent to the formula commonly reported for several risk factors: \({\rm{PAF}}=1-\,\mathop{\prod}\nolimits_{i=1}^{n}1-{\rm{PAF}}_{i}\)
The PAF formula is used to quantify the burden of disease attributable to a particular exposure. It involves comparing the disease cases associated with the observed exposure levels in the population to a counterfactual scenario with an optimal intake distribution, given a known etiologic exposure–disease risk relationship.
In this analysis, we aimed to estimate the burden of incidence, mortality and DALYs for T2D, ischemic heart disease and ischemic stroke attributable to intake of SSBs.
The PAF formula used is as follows:
where P(x) is the usual SSB intake distribution in a specific population stratum, assumed to follow a gamma distribution as used in previous analyses3,31,88; RR(x) is the age-specific relative risk function for T2D or CVD risk; and m is the maximum exposure level.
where β is the stratum-specific change in log relative risk per unit of exposure, x is the current exposure level and y(x) is the optimal exposure level. y(x) is defined to be \({F}_{\rm{optimal}}({F}_{x}^{-1}\left(x\right))\), where F is the cumulative distribution function of the optimal intake and \({F}_{x}^{-1}\) is the inverse cumulative distribution function of the current exposure distribution. Implicit in how we characterize the relative risk function are certain assumptions, including a linear relationship between the log relative risk (beta) and the unit of exposure. This model assumes that no further risk is associated with exposure beyond the optimal intake level, and that both x and the optimal intake level for an individual at exposure level x are the qth quantile of their respective distributions (the observed exposure distribution and the optimal intake distribution, respectively).
In practice, simple numerical integration using Riemann sums can be used to compute the integrals in the PAF formula88.
n categories are determined by dividing the exposure range (chosen here to be 0, \({F}_{x}^{-1}\left.\left(\varPhi \left(-6\right)\right)\right)\) into 121 intervals, each of length 0.1 when converted to the standard normal scale (except for the first one). Φ is defined as the cumulative distribution function of the standard normal distribution (N(0,1)). More precisely, the range of exposure groups i can be described as:
The association of change in BMI with change in SSB intake was assessed in three pooled US cohorts using multivariate linear regression accounting for within-person repeated measures, as described in an earlier study17. Separate linear relationships were estimated for underweight (BMI 17. Because individuals with obesity were excluded in these previous analyses, we used the risk estimate for individuals with overweight for individuals with obesity, which could underestimate the full effects of SSB on weight change.
To assess the BMI-mediated effects of SSB intake on incidence, mortality and DALYs of T2D, ischemic heart disease and ischemic stroke, we first calculated the monotonic effect of SSB intake on BMI change for each population stratum by weighting the baseline BMI-specific effect by the respective prevalence of underweight, normal weight and overweight (including obesity) within each stratum. We obtained overweight and underweight population distributions from the NCD-RisC71 and calculated the prevalence of normal weight as 1 minus the sum of these prevalences71. The NCD-RisC estimates go up to 2016, and thus, for our 2020 analysis, we used data from 2016 as a proxy for 2020. Given increasing adiposity globally, this assumption could result in underestimation of disease burdens due to SSBs in 2020. We assumed that individuals with underweight did not experience increased risk of T2D, ischemic heart disease or ischemic stroke with increased consumption of SSBs. As such, the monotonic effect for this population segment was set at 0:
We then estimated the BMI-mediated log(RR) by multiplying the log(RR) per unit increase in BMI and the SSB-to-BMI effect (associated increase in BMI per one-unit-associated increase in SSB intake).
We used Monte Carlo simulations to quantify the uncertainty around the PAF estimate. In this calculation, we incorporated uncertainty of multiple key parameters, including the usual intake distribution of SSBs in each stratum; underlying T2D, CVD and DALY burden estimates in each stratum; the etiologic estimates (RR) for SSB–BMI, SSB–T2D and SSB–CVD relationships; and the prevalence of individuals with underweight, normal weight or overweight in each stratum. For each SSB–disease combination and stratum, we drew randomly 1,000 times from the respective probability distributions. This included drawing randomly from the normal distribution of the estimate of disease-specific changes in the log(RR) of BMI-mediated and direct etiologic effects for a one-unit increase in SSB intake, the posterior distributions for shape and rate parameters for usual dietary intake and the normal distribution of the estimate for the prevalence of underweight, normal weight and overweight. Draws of proportions that were less than 0 or greater than 1 were truncated at 0 or 1, respectively, and draws of mean intake that were 0 or less were truncated at 0.00001. Each set of random draws was used to calculate the PAFs and, multiplied by the stratum-specific disease rates, the associated absolute attributable disease burden. Corresponding 95% UIs were derived from the 2.5th and 97.5th percentiles of 1,000 estimated models.
We assessed national-level findings by SDI in 1990 and 2020. The SDI is a composite measure of a nation’s development based on factors such as income per capita, educational attainment and fertility rates18.
To compare estimates across different years (1990 and 2020), we calculated differences for absolute and proportional burdens from 1990 to 2020 (that is, 2020 minus 1990). We performed this calculation for each simulation resulting in a distribution of differences, and we report the median and 95% UIs for each difference. We did not formally standardize comparisons over time by age or sex. This decision was made to ensure that findings would reflect the actual population differences in attributable burdens that are relevant to policy decisions. However, we also performed analyses stratified by age and sex, taking into account changes in these demographics over time. All analyses were conducted using R statistical software, R version 4.4.0 (ref. 123) on the Tufts High Performance Cluster.
Further information on research design is available in the Nature Portfolio Reporting Summary linked to this article.
...
Read the original on www.nature.com »
A/B testing is used far too often, for something that performs so badly. It is defective by design: Segment users into two groups. Show the A group the old, tried and true stuff. Show the B group the new whiz-bang design with the bigger buttons and slightly different copy. After a while, take a look at the stats and figure out which group presses the button more often. Sounds good, right? The problem is staring you in the face. It is the same dilemma faced by researchers administering drug studies. During drug trials, you can only give half the patients the life saving treatment. The others get sugar water. If the treatment works, group B lost out. This sacrifice is made to get good data. But it doesn’t have to be this way.
In recent years, hundreds of the brightest minds of modern civilization have been hard at work not curing cancer. Instead, they have been refining techniques for getting you and me to click on banner ads. It has been working. Both Google and Microsoft are focusing on using more information about visitors to predict what to show them. Strangely, anything better than A/B testing is absent from mainstream tools, including Google Analytics, and Google Website optimizer. I hope to change that by raising awareness about better techniques.
With a simple 20-line change to how A/B testing works, that you can implement today, you can always do better than A/B testing — sometimes, two or three times better. This method has several good points:
It can reasonably handle more than two options at once.. Eg, A, B, C, D, E, F, G, �
New options can be added or removed at any time.
But the most enticing part is that you can set it and forget it. If your time is really worth $1000/hour, you really don’t have time to go back and check how every change you made is doing and pick options. You don’t have time to write rambling blog entries about how you got your site redesigned and changed this and that and it worked or it didn’t work. Let the algorithm do its job. This 20 lines of code automatically finds the best choice quickly, and then uses it until it stops being the best choice.
The multi-armed bandit problem takes its terminology from a casino. You are faced with a wall of slot machines, each with its own lever. You suspect that some slot machines pay out more frequently than others. How can you learn which machine is the best, and get the most coins in the fewest trials?
Like many techniques in machine learning, the simplest strategy is hard to beat. More complicated techniques are worth considering, but they may eke out only a few hundredths of a percentage point of performance. One strategy that has been shown to perform well time after time in practical problems is the epsilon-greedy method. We always keep track of the number of pulls of the lever and the amount of rewards we have received from that lever. 10% of the time, we choose a lever at random. The other 90% of the time, we choose the lever that has the highest expectation of rewards.
def choose(): if math.random() < 0.1: # exploration! # choose a random lever 10% of the time. else: # exploitation! # for each lever, # calculate the expectation of reward. # This is the number of trials of the lever divided by the total reward # given by that lever. # choose the lever with the greatest expectation of reward. # increment the number of times the chosen lever has been played. # store test data in redis, choice in session key, etc..
def reward(choice, amount): # add the reward to the total for the given lever.
Why does this work?
Let’s say we are choosing a colour for the “Buy now!” button. The choices are orange, green, or white. We initialize all three choices to 1 win out of 1 try. It doesn’t really matter what we initialize them too, because the algorithm will adapt. So when we start out, the internal test data looks like this.
Then a web site visitor comes along and we have to show them a button. We choose the first one with the highest expectation of winning. The algorithm thinks they all work 100% of the time, so it chooses the first one: orange. But, alas, the visitor doesn’t click on the button.
Another visitor comes along. We definitely won’t show them orange, since we think it only has a 50% chance of working. So we choose Green. They don’t click. The same thing happens for several more visitors, and we end up cycling through the choices. In the process, we refine our estimate of the click through rate for each option downwards.
But suddenly, someone clicks on the orange button! Quickly, the browser makes an Ajax call to our reward function $.ajax(url:“/reward?testname=buy-button”); and our code updates the results:
When our intrepid web developer sees this, he scratches his head. What the F*? The orange button is the worst choice. Its font is tiny! The green button is obviously the better one. All is lost! The greedy algorithm will always choose it forever now!
But wait, let’s see what happens if Orange is really the suboptimal choice. Since the algorithm now believes it is the best, it will always be shown. That is, until it stops working well. Then the other choices start to look better.
After many more visits, the best choice, if there is one, will have been found, and will be shown 90% of the time. Here are some results based on an actual web site that I have been working on. We also have an estimate of the click through rate for each choice.
Edit: What about the randomization?
I have not discussed the randomization part. The randomization of 10% of trials forces the algorithm to explore the options. It is a trade-off between trying new things in hopes of something better, and sticking with what it knows will work. There are several variations of the epsilon-greedy strategy. In the epsilon-first strategy, you can explore 100% of the time in the beginning and once you have a good sample, switch to pure-greedy. Alternatively, you can have it decrease the amount of exploration as time passes. The epsilon-greedy strategy that I have described is a good balance between simplicity and performance. Learning about the other algorithms, such as UCB, Boltzmann Exploration, and methods that take context into account, is fascinating, but optional if you just want something that works.
Wait a minute, why isn’t everybody doing this?
Statistics are hard for most people to understand. People distrust things that they do not understand, and they especially distrust machine learning algorithms, even if they are simple. Mainstream tools don’t support this, because then you’d have to educate people about it, and about statistics, and that is hard. Some common objections might be:
Showing the different options at different rates will skew the results. (No it won’t. You always have an estimate of the click through rate for each choice)
This won’t adapt to change. (Your visitors probably don’t change. But if you really want to, in the reward function, multiply the old reward value by a forgetting factor)
This won’t handle changing several things at once that depend on each-other. (Agreed. Neither will A/B testing.)
I won’t know what the click is worth for 30 days so how can I reward it?
...
Read the original on stevehanov.ca »
...
Read the original on www.githubstatus.com »
Skip to content
We read every piece of feedback, and take your input very seriously.
Include my email address so I can be contacted
Use saved searches to filter your results more quickly
To see all available qualifiers, see our documentation.
Sign up
You signed in with another tab or window. Reload to refresh your session.
You signed out in another tab or window. Reload to refresh your session.
You switched accounts on another tab or window. Reload to refresh your session.
Notifications
You must be signed in to change notification settings
161 commits
to master
since this release
This tag was signed with the committer’s verified signature.
We are excited to announce the release of OpenZFS 2.3.0.
RAIDZ Expansion (#15022): Add new devices to an existing RAIDZ pool, increasing storage capacity without downtime.
Direct IO (#10018): Allows bypassing the ARC for reads/writes, improving performance in scenarios like NVMe devices where caching may hinder efficiency.
JSON (#16217): Optional JSON output for the most used commands.
Long names (#15921): Support for file and directory names up to 1023 characters.
Thank you to all 134 contributors who participated in this release cycle
[behlendorf1@pip zfs]$ git shortlog -s zfs-2.2.0..zfs-2.3.0
4 Ahelenia Ziemiańska
2 Akash B
12 Alan Somers
1 Alek Pinchuk
144 Alexander Motin
6 Allan Jude
1 Alphan Yılmaz
26 Ameer Hamza
2 Andrea Righi
2 Andrew Innes
2 Andrew Turner
1 Andrew Walker
1 Andy Fiddaman
2 Benda Xu
1 Benjamin Sherman
1 Bojan Novković
8 Brian Atkinson
61 Brian Behlendorf
4 Brooks Davis
2 Cameron Harr
1 ChenHao Lu
1 Chris Davidson
1 Chris Peredun
9 Chunwei Chen
14 Coleman Kane
1 Colin Percival
3 Dag-Erling Smørgrav
2 Daniel Berlin
1 Daniel Perry
1 Dennis R. Friedrichsen
1 Derek Schrock
1 Dex Wood
3 Dimitry Andric
13 Don Brady
4 Edmund Nadolski
2 Fabian-Gruenbichler
4 George Amanakis
5 George Melikov
3 George Wilson
6 Gionatan Danti
1 Gleb Smirnoff
1 Gordon Tetlow
1 Ilkka Sovanto
1 Ivan Volosyuk
1 JKDingwall
1 James Reilly
1 Jaron Kent-Dobias
2 Jason King
2 Jason Lee
1 Jessica Clarke
4 Jitendra Patidar
1 John Wren Kennedy
1 Jose Luis Duran
1 José Luis Salvador Rufo
1 Justin Gottula
4 Kay Pedersen
1 Kent Ross
1 Kevin Greene
1 Kevin Jin
1 Lalufu
1 Laura Hild
1 Mariusz Zaborski
17 Mark Johnston
3 Mart Frauenlob
9 Martin Matuška
1 Martin Wagner
4 Mateusz Guzik
7 Mateusz Piotrowski
1 Matthew Ahrens
1 Matthew Heller
1 Mauricio Faria de Oliveira
1 Maxim Filimonov
2 MigeljanImeri
1 Olivier Certner
14 Paul Dagnelie
6 Pavel Snajdr
6 Pawel Jakub Dawidek
1 Peter Doherty
...
Read the original on github.com »
Webtop - Alpine, Ubuntu, Fedora, and Arch based containers containing full desktop environments in officially supported flavors accessible via any modern web browser.
We utilise the docker manifest for multi-platform awareness. More information is available from docker here and our announcement here.
Simply pulling lscr.io/linuxserver/webtop:latest should retrieve the correct image for your arch, but you can also pull specific arch images via tags.
The architectures supported by this image are:
This image provides various versions that are available via tags. Please read the descriptions carefully and exercise caution when using unstable or development tags.
The Webtop can be accessed at:
Modern GUI desktop apps have issues with the latest Docker and syscall compatibility, you can use Docker with the –security-opt seccomp=unconfined setting to allow these syscalls on hosts with older Kernels or libseccomp
By default this container has no authentication and the optional environment variables CUSTOM_USER and PASSWORD to enable basic http auth via the embedded NGINX server should only be used to locally secure the container from unwanted access on a local network. If exposing this to the Internet we recommend putting it behind a reverse proxy, such as SWAG, and ensuring a secure authentication solution is in place. From the web interface a terminal can be launched and it is configured for passwordless sudo, so anyone with access to it can install and run whatever they want along with probing your local network.
This container is based on Docker Baseimage KasmVNC which means there are additional environment variables and run configurations to enable or disable specific functionality.
The environment variable LC_ALL can be used to start this container in a different language than English simply pass for example to launch the Desktop session in French LC_ALL=fr_FR. UTF-8. Some languages like Chinese, Japanese, or Korean will be missing fonts needed to render properly known as cjk fonts, but others may exist and not be installed inside the container depending on what underlying distribution you are running. We only ensure fonts for Latin characters are present. Fonts can be installed with a mod on startup.
To install cjk fonts on startup as an example pass the environment variables (Alpine base):
The web interface has the option for “IME Input Mode” in Settings which will allow non english characters to be used from a non en_US keyboard on the client. Once enabled it will perform the same as a local Linux installation set to your locale.
For accelerated apps or games, render devices can be mounted into the container and leveraged by applications using:
The DRINODE environment variable can be used to point to a specific GPU. Up to date information can be found here
Nvidia support is not compatible with Alpine based images as Alpine lacks Nvidia drivers
Nvidia support is available by leveraging Zink for OpenGL support. This can be enabled with the following run flags:
The compose syntax is slightly different for this as you will need to set nvidia as the default runtime:
And to assign the GPU in compose:
If you run system native installations of software IE sudo apt-get install filezilla and then upgrade or destroy/re-create the container that software will be removed and the container will be at a clean state. For some users that will be acceptable and they can update their system packages as well using system native commands like apt-get upgrade. If you want Docker to handle upgrading the container and retain your applications and settings we have created proot-apps which allow portable applications to be installed to persistent storage in the user’s $HOME directory and they will work in a confined Docker environment out of the box. These applications and their settings will persist upgrades of the base container and can be mounted into different flavors of KasmVNC based containers on the fly. This can be achieved from the command line with:
PRoot Apps is included in all KasmVNC based containers, a list of linuxserver.io supported applications is located HERE.
It is possible to install extra packages during container start using universal-package-install. It might increase starting time significantly. PRoot is preferred.
To help you get started creating a container from this image you can either use docker-compose or the docker cli.
Containers are configured using parameters passed at runtime (such as those above). These parameters are separated by a colon and indicate respectively. For example, -p 8080:80 would expose port 80 from inside the container to be accessible from the host’s IP on port 8080 outside the container.
You can set any environment variable from a file by using a special prepend FILE__.
As an example:
Will set the environment variable MYVAR based on the contents of the /run/secrets/mysecretvariable file.
For all of our images we provide the ability to override the default umask settings for services started within the containers using the optional -e UMASK=022 setting. Keep in mind umask is not chmod it subtracts from permissions based on it’s value it does not add. Please read up here before asking for support.
When using volumes (-v flags), permissions issues can arise between the host OS and the container, we avoid this issue by allowing you to specify the user PUID and group PGID.
Ensure any volume directories on the host are owned by the same user you specify and any permissions issues will vanish like magic.
In this instance PUID=1000 and PGID=1000, to find yours use id your_user as below:
We publish various Docker Mods to enable additional functionality within the containers. The list of Mods available for this image (if any) as well as universal mods that can be applied to any one of our images can be accessed via the dynamic badges above.
* To monitor the logs of the container in realtime:
Most of our images are static, versioned, and require an image update and container recreation to update the app inside. With some exceptions (noted in the relevant readme.md), we do not recommend or support updating apps inside the container. Please consult the Application Setup section above to see if it is recommended for the image.
Below are the instructions for updating containers:
* You can also remove the old dangling images:
* Recreate a new container with the same docker run parameters as instructed above (if mapped correctly to a host folder, your /config folder and settings will be preserved)
* You can also remove the old dangling images:
If you want to make local modifications to these images for development purposes or just to customize the logic:
The ARM variants can be built on x86_64 hardware and vice versa using lscr.io/linuxserver/qemu-static
Once registered you can define the dockerfile to use with -f Dockerfile.aarch64.
To help with development, we generate this dependency graph.
* 26.09.24: - Swap from firefox to chromium on Alpine images.
* 29.12.23: - Rebase Alpine to 3.19 and swap back to Firefox.
* 05.02.22: - Rebase KDE Ubuntu to Jammy, add new documentation for updated gclient, stop recommending priv mode.
...
Read the original on docs.linuxserver.io »
To add this web app to your iOS home screen tap the share button and select "Add to the Home Screen".
10HN is also available as an iOS App
If you visit 10HN only rarely, check out the the best articles from the past week.
If you like 10HN please leave feedback and share
Visit pancik.com for more.