j Elon Musk’s job as Trump’s bureaucracy buster could be just the start - The Australian Financial Review By news.google.com Published On :: Wed, 13 Nov 2024 03:47:00 GMT Elon Musk’s job as Trump’s bureaucracy buster could be just the start The Australian Financial ReviewElon Musk tapped for ‘government efficiency’ role by Donald Trump Sydney Morning HeraldEvening News Bulletin 13 November 2024 SBS NewsDonald Trump wants Elon Musk to slash regulations as he reveals his role ABC News Full Article
j Overcoming Objections By onfundraising.blogspot.com Published On :: Thu, 27 Dec 2007 02:48:00 +0000 Telephone Fundraising would be much easier if everyone you called said yes, but in the real world, nine out of ten people on a campaign may reject you outright. The key to converting a small percentage of those no's to yes's is understanding why the donor is saying no to you. some of the more common objections and the ways to get beyond them are listed below. Donor has no time to take a call. In xMore to come later.... Full Article
j A bushel of buzzwords from Japan; the advent of phoneticization By languagelog.ldc.upenn.edu Published On :: Wed, 06 Nov 2024 22:13:04 +0000 Below are two lists of nominations for Japanese buzzword of the year. Each has 30 entries, and from each list one will be chosen as the respective winner. Since the two lists are already quite long and rich, I will keep my own comments (mostly at the bottom and focusing on phoneticization) to a minimum. […] Full Article Alphabets Word of the year Writing systems
j From now on, the title of the post is allowed to just be "January 2024" (only when it is January 2024, however) By radar.spacebar.org Published On :: Wed, 31 Jan 2024 22:08:59 -0500 Hello again, This month I've been plugging away on the project I mentioned in the previous post which involves among other things a PDF generator and now an implementation of ML (as in Standard ML, but also the other one). This is probably the 10th "compiler" I've written in my life, and it's kind of fun to revisit these problems that you've done many times and try out different approaches, although this time one of the approaches is "Use C++" (for reasons of making good on a joke, but also for reasons of mlton doesn't work on my computer any more). And although C++ is a fine tool for many applications, it does have some deficiencies for the task of writing a compiler (one of the most irritating: a very modest limit on the stack depth? Like my computer has 256 Gigabytes of RAM and 2^64 virtual addresses and somehow it can only manage 1 megabyte for the stack and there's no standard way to increase it? Get off my lawn). But then you can also experience new ways of struggling with C++, like: A middle of the night power failure wrecked my computer's GPT (as in GUID Partition Table, but also the other one) and I was deep in the depths of taking the computer apart to reset its parts, its BIOS (its Basic In/Out System, which is where it stores its biography) and its hard drives were everywhere on the floor, and it could not be saved, and this after I already broke my computer this year by trying to put the world's biggest video card in it, too hard. And I could not merely perform recovery because of Unknown Error, so I had to begin anew again and restore from backups. But when you restore from backup and you're in the mood of "why is this so complicated and I don't understand how computers work any more?" it occurs to you (me) to also change your underlying development environment instead of reinstalling the devil you know. So I ended my friendship with Cygwin64 and switched to new best friend MSYS2. Both of these things are different ways of wishing that you were using Linux while you're using Windows. The main reason I tried this new way of struggling is that Cygwin is very behind on its version of x86_64 clang (C++ compiler), which I wanted to try because it supports AddressSanitizer and clangd on Windows, and I wanted to give LSP in emacs a shot (it's finally good!). There were a few growing pains, but I think MSYS2 is what I would recommend now. One of the nice things they did was create multiple different environments depending on what you want to do (e.g. "I want to use clang to compile x86_64 code" or "I want to do 32-bit cross compilation for ARM") and in that environment, you just say "g++" and it invokes the compiler you want, instead of the weird contortions I've been doing for years with manually invoking x86_64-w64-mingw32-g++. I was also able to get clblast working before being too filled with rage to continue, so that is nice for the ML inference on the world's biggest graphics card. I made these graphics to help me tune the correct settings of GPU layers (y axis) and number of threads (x axis): tune-single tune-batch In some sense the results are obvious (more threads and more layers is faster) but it was interesting to me how the cliff of performance drops off at a different number of layers for single and batch mode (I guess because the batch needs some memory itself?) and how it's clearly better to use fewer threads than cores for batch as well. I was not surprised to see performance drop off for >32 threads (everybody knows that hyper-threads kinda suck) but I was very surprised to see performance pick up again when it gets back up to 64? And only for single mode? I wish I understood that better. But mostly I'm a sucker for the custom visualizations. Right but when writing this compiler I realized that I wanted to use some Greek letters, and I can't handle it when some characters are in a different font in my source code, so I finally made some space for those in my programming font FixederSys. These certainly still need some tweaks, but it's already better than just being in some other weird font: {{{caption}}} You can also see that I have been adding some "useful" emoji at the top. It is an interesting puzzle to try to make these things recognizable (especially for the 1x version, whose charboxes are 8x16 pixels). I am pretty sure I will not try to do all of the emoji (like, the flags are totally hopeless at 8x16), but it is tempting to round out the Unicode support somewhat. Like I was trying to make a ¯\_(ツ)_/¯ today and had to settle for ~\_( :) )_/~ which is pretty much (ノಠ益ಠ)ノ彡┻━┻. Also: Adam revived our old game jam game Headcat, which I described in post 927, now over 16 years ago. You can play it online at Headcat.org. It is harder than I remember, perhaps explaining why it did not reach #1 on the One Appstore Per Child charts. Also: I started and finished (true ending, but just with one character) Slay the Spire. Good game, but you don't need me to tell you that. Same for Alwa's Legacy, which is the sequel to Alwa's Awakening. Both of these are very true-to-form "8-bit" and "16-bit" platformers that I enjoyed and would recommend for genre fans, though I did not try to 100% them. The graphics are the highlight and I thought it was very cute how these could easily have been a pair of games from the NES and SNES. The good old days. And speaking of good-old days, I am now playing Katamari Damacy, which I had played at a friend's house many years ago, and always wanted to spend more time with. It totally holds up (aside from stuff like: You have to play through the tutorial and first level before you can access the menus at all, like to make the game fullscreen?) and it's honestly inspiring how unhinged the game design and writing are, and how fun it manages to be. What an accomplishment! Full Article
j June 2024 By radar.spacebar.org Published On :: Sun, 30 Jun 2024 21:56:21 -0400 As predicted, I posted my new video called Badness 0. If you are waiting for me to post the video here, you are a poor detective! I think it's best without spoilers, which is why the title and thumbnail have very little useful information in them, although the thumbnail is intended to be an attractive nuisance for people with eyes/brains like mine: Badness O Of course the whole system is set up to punish you if you don't have a clickbait title with a human face making an astonished look and an arrow at something in the video with some bold text that says "OVERSTATED PREMISE!" So if you did like it, please share the old fashioned way. Someone plausibly told me that they showed it to Knuth, which I choose to believe is true. The video was not really that much more work than usual (although I am practicing new techniques and using new equipment) but since it came after several rounds of crunch on the same project (papers, SIGBOVIK talk, NYC talk) I did rather feel like a break. But a few bugs and unfinished things in BoVeX were haunting me, so I got sucked back into programming this month, although at a relaxed pace. I fixed the bug reported in previous comments where the files wouldn't render on some platforms, or would have really screwed up kerning. I added compression, so that you can't see my unoptimized PDF code if you open it in a text editor. I fixed the bugs with mutually recursive function bundles that capture polymorphic variables. I fixed the bug where the internal bytecode routine that creates nodes always flattens them into normal form, which fixes the weird spaces in some situations. I got it compiling in recent GCCs. I think I'm successfully done hacking on it for now, although I suspect I will use BoVeX for future papers, so I will be back! Other things: I let myself play video games and promptly got addicted to Hades, which is excellent, as you probably know. I have "beaten" it but I'm not really finished; a more detailed review in a future post. Right now we are working on the 2024 ICFP Programming Contest so I should probably get back to that. I am enjoying this one, not only because it continues the story of the 2006 contest that I led (it still works! and is also best without spoilers!). I'll write about this too, but there's still 10 hours left in the contest so fair play forbids me from showing any images until after. (Not that we are doing great or anything, but we're pretty close to solving every puzzle, at least!) So I should probably get back to that! Full Article
j Of all homonymic months, August is the most majestic By radar.spacebar.org Published On :: Sat, 31 Aug 2024 10:11:27 -0400 I’m traveling for the long weekend. Either I’m having bad luck with the epic heat waves or there have been a lot of epic heat waves, because again the short road trip threatens to be tyrannized by the hot air. It did at least touch 100°F this time, so at least it is a proper respectable heat wave. We are in a place called Hocking Hills, whose AirBnB has these OBX-style stickers that say “HHO”, which could either be confusingly “Hills, HOcking,” or perhaps “Hocking Hills, Ohio”, but not “Hocking hills OHio” as one might expect. I plan to stick the sticker upside-down for “OHH”, as in “Ohh yeah, I need to write a post on Tom 7 Radar for the month of August, and I need to do it on this mediocre wi-fi which Google Internet Speed Test describes as ‘fine’ while everyone else drinks beers outside.” Fair enough: This is a self-imposed curse and one that’s easily tended to at any time during the month. During the month: I worked again on making my own video codec, which is a very bad way to spend one’s time, but I don’t think there are any modern lossless codecs that would be suitable for my use case. And I do like a data compression project because of the inherent benchmarkability. The use case is for the increasingly common situation where I have a program generating a series of video frames (e.g. BoVeX is making an animation), which I usually do by writing a sequence of PNG files to disk. I’m way ahead of PNG files so far even without doing any inter-frame stuff, which is not impressive, but does make me feel like it’s at least not totally pointless. (Still, it’s quite pointless: Sure I can make these files smaller at significant cost of complexity and encoding times, but these animations typically use space similar to like one second of 4K 60fps XF-AVC footage.) Sometimes programming your own lossless video codec is a bit too fast-paced so you need to write a Wikipedia article from scratch about Clairton Coke Works by digging through newspaper archives. I haven't even gotten to the last 30 years of its history yet! I also rounded out the Cyrillic in FixederSys though I don't think I've uploaded a new version of that yet. As usual I did some hacking on secret projects. UHH, elsewise, I did finish off Animal Well which I liked very much. My spoilerless advice to you is: Don't try to 100% this game without at least looking at a spoiler-controlled guide! But I did have fun once I felt like I was stuck-ish finishing the remaining postgame puzzles. I have also been playing Chippy, a bullet-hell twin-stick shooter that is quite hard (I usually feel good at this genre) and has several new good ideas in it. It's essentially all boss fights, and the chief innovation is that you fight the giant bosses by disconnecting pieces of them. I'm on the last boss so I will probably finish that one soon. As I have confessed many times, I like dumb first-person shooter games, and I played through Trepang 2 this month as well. It does have a few moments, but it was mostly pretty dumb, like I wanted. And then I started Touhou Luna Nights, which is a "Metroidvania" fan-game with great pixel art and music. OK, I should get back to this vacation! Full Article
j Joined Up? By magistratesblog.blogspot.com Published On :: Tue, 22 Nov 2016 20:45:00 +0000 According to the news on my radio today there are calls to make the wearing of military decorations that have not been legitimately earned punishable by imprisonment and/or a fine. Of course we must treat our old soldiers with dignity and respect their awards, but is this really a sensible use of the scarce and costly prison system? Since I joined the Bench in 1985 the prison population has soared to its current 85,000 or so. Posing as a decorated old soldier is more sad than evil, and there is no tangible victim involved. Expose the perpetrators in their local paper for the pathetic poseurs that they are, but prison? No. Full Article
j Pizza a Day Diet Archive [January 2015 Edition]: Hoboken Pie By greglsblog.blogspot.com Published On :: Tue, 12 Jan 2016 17:55:00 +0000 This is a post I originally put only on Facebook in January 2015. Click here for background. And the first pizza of the January 2015 #PizzaADayDiet comes from Hoboken Pie! A thin crust sausage, mushroom, and green pepper -- all the ingredients were fresh and in abundance. The sausage and sauce were slightly spicy and the crust was really thin. It could have had a tad more body, but I liked the fact that it didn't feel like I was filling up on bread. Delivery was prompt and the pizza was warm out of the box. I will definitely order from them again. Full Article pizza a day Pizza a Day Diet
j Pizza A Day Diet Archive [January 2015 Edition]: Southside Flying Pizza By greglsblog.blogspot.com Published On :: Tue, 26 Jan 2016 13:17:00 +0000 Day 8 of #PizzaADayDiet is another thin crust, this one from Southside Flying Pizza. They call it “Neapolitan style,” which I guess is a really thin crust. I chose the whole wheat crust and it was pretty good – it stood up to the ingredients but I wouldn't have minded if it had been a tad crisper. The cheese was thoroughly melted and excellent, though, as were the toppings. The sausage had a good flavor and the peppers were nicely al dente. And the side salad was really good, as well. Full Article pizza a day Pizza a Day Diet
j Pizza a Day Diet Archive [January 2015 Edition]: Home Slice Pizza By greglsblog.blogspot.com Published On :: Wed, 27 Jan 2016 13:20:00 +0000 Today's #PizzaADayDiet occurred at Home Slice Pizza -- Don Tate joined me for the sausage, mushroom, and green pepper pie! This was the thickest thin crust I've had so far, and was sufficient to be not -floppy, yet not doughy, with a good, chewy texture. The cheese was flavorful and the toppings were each present in every bite. Altogether, a most excellent pizza -- and they put the leftovers in a tinfoil swan (I've never seen that before in real life :-)). Full Article pizza a day Pizza a Day Diet
j Why does Jupiter spin so fast? By www.planetary.org Published On :: Thu, 25 Jul 2024 07:00:00 -0700 The gas giant is the Solar System's largest planet. Here's why it's also the fastest-spinning planet. Full Article
j Serendipity, a super-Jupiter, and saving VIPER By www.planetary.org Published On :: Fri, 26 Jul 2024 07:30:00 -0700 This was a big week in space, from Curiosity stumbling upon sulfur crystals to an exoplanet discovery and a major advocacy effort. Full Article
j Does Jupiter protect Earth from asteroids and comets? By www.planetary.org Published On :: Tue, 30 Jul 2024 07:00:00 -0700 Jupiter has often been thought to protect the inner Solar System from asteroids and comets, but new research has shown that the giant planet may actually increase the risk of an impact. Full Article
j Europa Clipper launches on its journey to Jupiter’s icy moon By www.planetary.org Published On :: Mon, 14 Oct 2024 00:00:00 -0700 NASA’s Europa Clipper spacecraft launched today aboard a SpaceX Falcon Heavy rocket from NASA’s Kennedy Space Center in Cape Canaveral, Florida. Full Article
j Journeys worth making By www.planetary.org Published On :: Fri, 01 Nov 2024 07:30:00 -0700 Perseverance faces a hard climb, but New Horizons proves it’s worth going the distance. Full Article
j The James Brand × Timex Automatic GMT Watch By uncrate.com Published On :: Tue, 12 Nov 2024 12:18:54 -0500 Full Article Watches
j Vollebak Eiderdown Puffer Jacket By uncrate.com Published On :: Tue, 12 Nov 2024 14:20:58 -0500 Full Article Outerwear
j Christmas jewelry in progress. By maryannemohanraj.com Published On :: Sat, 09 Nov 2024 21:02:00 +0000 Sneak peek — Christmas jewelry in progress. Full Article Berwyn Shops Serendib House
j Joe Marshall: Lisp vs. golang By funcall.blogspot.com Published On :: Thu, 17 Oct 2024 02:17:00 GMT It's no secret that I'm an aficionado of Lisp. It's my go to language, especially when I don't know what I'm doing. I call it research and prototyping, but it's really just playing around until something works. We had a need for some auditing of some of our databases at work. They ought to agree with each other and with what GitHub and CircleCI think. It took a couple of weeks part time to prototype a solution in Common Lisp. It showed that the databases were in 99% agreement and found the few points of disagreement and anomalies that we ought to fix or look out for. I want to integrate this information into a dashboard on one of our tools. I prototyped this by spinning up a Common Lisp microservice that returns the information in JSON format. But management prefers that new services are written in golang. It would be easier for me to rewrite the service in golang than to try to persuade others to use Common Lisp. It also gives me the opportunity to compare the two languages head to head on a real world problem. No, this is not a fair comparison. When I wrote the Lisp code I was exploring the problem space and prototyping. I'm much more experienced with Lisp than with golang. The golang version has the advantage that I know what I want to do and how to do it. In theory, I can just translate the Common Lisp code into golang. But then again, this is a “second system” which is not a prototype and has slightly larger scope and fuller requirements. So this cannot be a true head to head comparison. The first point of comparison is macros (or lack thereof). I generally don't use a lot of macros in Common Lisp, but they come in handy when I do use them. One macro I wrote is called audit-step, which you can wrap around any expresion and it prints out a message before and after the expression is evaluated. The steps are numbered in sequence, and nested steps get nested numbers (like step 2.3.1). If you wrap the major function bodies with this macro, you get a nice trace of the call sequence in the log. Golang doesn't have macros, but it has first class functions. It's easy enough to write a function that takes a function as an argument and wraps it to output the trace messages. In fact, the macro version in Common Lisp just rewrites the form into such a function call. But the macro version hides a level of indentation and a lambda. In golang, my major functions all start with func MajorFunction (args) int { return AuditStep("MajorFunction", "aux message", func() int { // body of MajorFunction // Actual code goes here. }) } The bodies of all my major functions are indented by 16 spaces, which is a little much. I like higher order functions. I can write one higher order function and parameterize it with functions that handle the specific cases. In my auditing code, one such workhorse function is called collate. It takes a list of objects and creates a table that maps values to all objects in the list that contain that value. To give an example, imaging you have a list of objects that all have a field called foo. The foo field is a string. The collate function can return a table that maps strings to all objects that have that string in the foo field. collate is very general. It takes a list of objects and four keyword arguments. The :key argument is a function that extracts the value to collate on. The :test argument is a function that compares two keys (it defaults to eql if not specified). The :merger argument is a function to add the mapped object to its appropriate collection in the table (it defaults to adjoin). The :default argument specifies the initial value of a collection in the table (it defaults to nil). The :merger function is the most interesting. It takes the key and the object and the current value of the table at that key. It returns the new value of the table at that key. The default merger function is adjoin, which adds the object to the collection at the key if it is not already there. But you can specify a different merger function. For example, if you want to count the number of objects at each key, you can specify a merger function that increments a counter. The functional arguments to the collate function are often the results of other higher order functions. For example, the :key argument is often the result of composing selector functions. The :merger argument is often the result of composing a binary merge function with a unary transformer function. The transformer function is often the result of composing a number of primitive selectors and transformers. In Common Lisp, it is quite easy to write these higher order functions. We can compose two unary functions with the compose2 function: (defun compose2 (f g) (lambda (x) (funcall f (funcall g x))) and then compose as many functions as we like by fold-left of compose2 starting with the identity function: (defun compose (&rest fs) (fold-left #'compose2 #'identity fs))We can compose a binary function with a unary function in three ways: we can pipe the output of the binary function into the unary function, or we can pipe the output of the unary function into one or the other of the inputs of the binary function. (defun binary-compose-output (f g) (lambda (x y) (funcall f (funcall g x y)))) (defun binary-compose-left (f g) (lambda (x y) (funcall f (funcall g x) y))) (defun binary-compose-right (f g) (lambda (x y) (funcall f x (funcall g y)))) The collate function can now assume that a lot of the work is done by the :key and :merger functions that are passed in. It simply builds a hash table and fills it: (defun collate (item &key (key #'identity) (test #'eql) (merger (merge-adjoin #'eql)) (default nil)) (let ((table (make-hash-table :test test))) (dolist (item items table) (let ((k (funcall key item))) (setf (gethash k table) (funcall merger (gethash k table default) item)))))) (defun merge-adjoin (test) (lambda (collection item) (adjoin item collection :test test))) So suppose, for example, that we have a list of records. Each record is a three element list. The third element is a struct that contains a string. We want a table mapping strings to the two element lists you get when you strip out the struct. This is easily done with collate: (collate records :key (compose #'get-string #'third) :test #'equal ; or #'string= if you prefer :merger (binary-compose-right (merge-adjoin #'equal) #'butlast)) The audit code reads lists of records from the database and from GitHub and from CircleCI and uses collate to build hash tables we can use to quickly walk and validate the data. Translating this into golang isn't quite so easy. Golang has first class function, true, but golang is a statically typed language. This causes two problems. First, the signature of the higher order functions includes the types of the arguments and the return value. This means you cannot just slap on the lambda symbol, you have to annotate each argument and the return value. This is far more verbose. Second, higher order functions map onto parameterized (generic) types. Generic type systems come with their own little constraint language so that the computer can figure out what concrete types can correctly match the generic types. This makes higher order functions fairly unweildy. Consider compose2. The functions f and g each have an input and output type, but the output type of g is the input type of f so only three types are involved func Compose2[T any, U any, V any](f func(U) V, g func(T) U) func(T) V { return func(x T) V { return f(g(x)) } } If want to compose three functions, we can write this: func Compose3[T any, U any, V any, W any](f func(V) W, g func(U) V, h func(T) U) func(T) W { return func(x T) W { return f(g(h(x))) } } The generic type specifiers take up as much space as the code itself. I don't see a way to write an n-ary compose function. It would have to be dynamically parameterized by the intermediate types of all the functions it was composing. For the collate function, we can write this: func Collate[R any, K comparable, V any]( list *Cons[R], keyfunc func(R) K, merger func(V, R) V, defaultValue V) map[K]V { answer := make(map[K]V) for list != nil { key := keyfunc(list.Car) probe, ok := answer[key] if !ok { probe = defaultValue } answer[key] = merger(probe, list.Car) list = list.Cdr } return answer } We have three types to parameterize over: the type of the list elements (i.e. the record type) R, the type of the key K, and the type of the value V. The key type is needs to be constrained to be a valid key in a map, so we use the comparable constraint. Now that we have the types, we can annotate the arguments and return value. The list we are collating is a list of R elements. The key function takes an R and returns a K. The merger takes an existing value of type V and the record of type R and returns a new value of type V. The magic of type inference means that I do not have to annotate all the variables in the body of the function, but the compiler cannot read my mind and infer the types of the arguments and return value. Golang forces you to think about the types of arguments and return values at every step of the way. Yes, one should be aware of what types are being passed around, but it is a burden to have to formally specify them at every step. I could write the Common Lisp code without worrying too much about types. Of couse the types would have to be consistent at runtime, but I could write the code just by considering what was connected to what. In golang, the types are in your face at every function definition. You not only have to think about what is connected to what, you have to think about what sort of thing is passed through the connection. I'm sure that many would argue that type safety is worth the trouble of annotation. I don't want to argue that it isn't. But the type system is cumbersome, awkward, and unweildy, especially when you are trying to write higher order functions. It is taking me longer to write the golang version of the audit service than it did to write the Common Lisp version. There are several reasons. First, I am more experienced with Common Lisp than golang, so the right Common Lisp idioms just come to mind. I have to look up many of the golang idioms. Second, the golang code is trying to do more than the Common Lisp code. But third, golang itself introduces more friction than Common Lisp. Programs have to do more than express the algorithm, they have to satisfy the type system. There are more points of comparison between the two languages. When I get frustrated enough, I'll probably write another post. Full Article
j Joe Marshall: Don't Try to Program in Lisp By funcall.blogspot.com Published On :: Sat, 02 Nov 2024 17:12:00 GMT A comment on my previous post said, The most difficult thing when coming to a different language is to leave the other language behind. The kind of friction experienced here is common when transliterating ideas from one language to another. Go (in this case) is telling you it just doesn't like to work like this. Try writing simple Go, instead of reaching for Lisp idioms. Then find the ways that work for Go to express the concepts you find. That's not at all how I approach programming. A friend of mine once paid me a high compliment. He said, “Even your C code looks like Lisp.” When I write code, I don't think in terms of the language I'm using, I think in terms of the problem I'm solving. I'm a mostly functional programmer, so I like to think in terms of functions and abstractions. I mostly reason about my code informally, but I draw upon the formal framework of Lambda Calculus. Lambda Calculus is a simple, but powerful (and universal) model of computation. Programming therefore becomes a matter of expressing the solution to a problem with the syntax and idioms of the language I'm using. Lisp was inspired by Lambda Calculus, so there is little friction in expressing computations in Lisp. Lisp is extensible and customizable, so I can add new syntax and idioms as desired. Other languages are less accommodating. Some computations are not easily expressable in the syntax of the language, or the semantics of the language are quirky and inconsistent. Essentially, every general purpose fourth generation programming language can be viewed as a poorly-specified, half-assed, incomplete, bug-ridden implementation of half of Common Lisp. The friction comes from working around the limitations of the language. Full Article
j TurtleWare: Dynamic Vars - Return of the Jedi By turtleware.eu Published On :: Mon, 04 Nov 2024 00:00:00 GMT Table of Contents The protocol Control operators Synchronized hash tables with weakness First-class dynamic variables STANDARD-DYNAMIC-VARIABLE SURROGATE-DYNAMIC-VARIABLE Thread-local variables The protocol The implementation Thread-local slots What can we use it for? In the previous two posts I've presented an implementation of first-class dynamic variables using PROGV and a surrogate implementation for SBCL. Now we will double down on this idea and make the protocol extensible. Finally we'll implement a specialized version of dynamic variables where even the top level value of the variable is thread-local. The protocol Previously we've defined operators as either macros or functions. Different implementations were protected by the feature flag and symbols collided. Now we will introduce the protocol composed of a common superclass and functions that are specialized by particular implementations. Most notably we will introduce a new operator CALL-WITH-DYNAMIC-VARIABLE that is responsible for establishing a single binding. Thanks to that it will be possible to mix dynamic variables of different types within a single DLET statement. (defclass dynamic-variable () ()) (defgeneric dynamic-variable-bindings (dvar)) (defgeneric dynamic-variable-value (dvar)) (defgeneric (setf dynamic-variable-value) (value dvar)) (defgeneric dynamic-variable-bound-p (dvar)) (defgeneric dynamic-variable-makunbound (dvar)) (defgeneric call-with-dynamic-variable (cont dvar &optional value)) Moreover we'll define a constructor that is specializable by a key. This design will allow us to refer to the dynamic variable class by using a shorter name. We will also define the standard class to be used and an matching constructor. (defparameter *default-dynamic-variable-class* #-fake-progv-kludge 'standard-dynamic-variable #+fake-progv-kludge 'surrogate-dynamic-variable) (defgeneric make-dynamic-variable-using-key (key &rest initargs) (:method (class &rest initargs) (apply #'make-instance class initargs)) (:method ((class (eql t)) &rest initargs) (apply #'make-instance *default-dynamic-variable-class* initargs)) (:method ((class null) &rest initargs) (declare (ignore class initargs)) (error "Making a dynamic variable that is not, huh?"))) (defun make-dynamic-variable (&rest initargs) (apply #'make-dynamic-variable-using-key t initargs)) Control operators Control operators are the same as previously, that is a set of four macros that consume the protocol specified above. Note that DYNAMIC-VARIABLE-PROGV expands to a recursive call where each binding is processed separately. (defmacro dlet (bindings &body body) (flet ((pred (binding) (and (listp binding) (= 2 (length binding))))) (unless (every #'pred bindings) (error "DLET: bindings must be lists of two values.~%~ Invalid bindings:~%~{ ~s~%~}" (remove-if #'pred bindings)))) (loop for (var val) in bindings collect var into vars collect val into vals finally (return `(dynamic-variable-progv (list ,@vars) (list ,@vals) ,@body)))) (defmacro dset (&rest pairs) `(setf ,@(loop for (var val) on pairs by #'cddr collect `(dref ,var) collect val))) (defmacro dref (variable) `(dynamic-variable-value ,variable)) (defun call-with-dynamic-variable-progv (cont vars vals) (flet ((thunk () (if vals (call-with-dynamic-variable cont (car vars) (car vals)) (call-with-dynamic-variable cont (car vars))))) (if vars (call-with-dynamic-variable-progv #'thunk (cdr vars) (cdr vals)) (funcall cont)))) (defmacro dynamic-variable-progv (vars vals &body body) (let ((cont (gensym))) `(flet ((,cont () ,@body)) (call-with-dynamic-variable-progv (function ,cont) ,vars ,vals)))) Synchronized hash tables with weakness Previously we've used SBCL-specific options to define a synchronized hash table with weak keys. This won't do anymore, because we will need a similar object to implement the thread-local storage for top level values. trivial-garbage is a portability layer that allows to define hash tables with a specified weakness, but it does not provide an argument that would abstract away synchronization. We will ensure thread-safety with locks instead. (defclass tls-table () ((table :initform (trivial-garbage:make-weak-hash-table :test #'eq :weakness :key)) (lock :initform (bt:make-lock)))) (defun make-tls-table () (make-instance 'tls-table)) (defmacro with-tls-table ((var self) &body body) (let ((obj (gensym))) `(let* ((,obj ,self) (,var (slot-value ,obj 'table))) (bt:with-lock-held ((slot-value ,obj 'lock)) ,@body)))) First-class dynamic variables STANDARD-DYNAMIC-VARIABLE Previously in the default implementation we've represented dynamic variables with a symbol. The new implementation is similar except that the symbol is read from a STANDARD-OBJECT that represents the variable. This also enables us to specialize the function CALL-WITH-DYNAMIC-VARIABLE: (defclass standard-dynamic-variable (dynamic-variable) ((symbol :initform (gensym) :accessor dynamic-variable-bindings))) (defmethod dynamic-variable-value ((dvar standard-dynamic-variable)) (symbol-value (dynamic-variable-bindings dvar))) (defmethod (setf dynamic-variable-value) (value (dvar standard-dynamic-variable)) (setf (symbol-value (dynamic-variable-bindings dvar)) value)) (defmethod dynamic-variable-bound-p ((dvar standard-dynamic-variable)) (boundp (dynamic-variable-bindings dvar))) (defmethod dynamic-variable-makunbound ((dvar standard-dynamic-variable)) (makunbound (dynamic-variable-bindings dvar))) (defmethod call-with-dynamic-variable (cont (dvar standard-dynamic-variable) &optional (val nil val-p)) (progv (list (dynamic-variable-bindings dvar)) (if val-p (list val) ()) (funcall cont))) SURROGATE-DYNAMIC-VARIABLE The implementation of the SURROGATE-DYNAMIC-VARIABLE is almost the same as previously. The only difference is that we use the previously defined indirection to safely work with hash tables. Also note, that we are not add the feature condition - both classes is always created. (defvar +fake-unbound+ 'unbound) (defvar +cell-unbound+ '(no-binding)) (defclass surrogate-dynamic-variable (dynamic-variable) ((tls-table :initform (make-tls-table) :reader dynamic-variable-tls-table) (top-value :initform +fake-unbound+ :accessor dynamic-variable-top-value))) (defmethod dynamic-variable-bindings ((dvar surrogate-dynamic-variable)) (let ((process (bt:current-thread))) (with-tls-table (tls-table (dynamic-variable-tls-table dvar)) (gethash process tls-table +cell-unbound+)))) (defmethod (setf dynamic-variable-bindings) (value (dvar surrogate-dynamic-variable)) (let ((process (bt:current-thread))) (with-tls-table (tls-table (dynamic-variable-tls-table dvar)) (setf (gethash process tls-table) value)))) (defun %dynamic-variable-value (dvar) (let ((tls-binds (dynamic-variable-bindings dvar))) (if (eq tls-binds +cell-unbound+) (dynamic-variable-top-value dvar) (car tls-binds)))) (defmethod dynamic-variable-value ((dvar surrogate-dynamic-variable)) (let ((tls-value (%dynamic-variable-value dvar))) (when (eq tls-value +fake-unbound+) (error 'unbound-variable :name "(unnamed)")) tls-value)) (defmethod (setf dynamic-variable-value) (value (dvar surrogate-dynamic-variable)) (let ((tls-binds (dynamic-variable-bindings dvar))) (if (eq tls-binds +cell-unbound+) (setf (dynamic-variable-top-value dvar) value) (setf (car tls-binds) value)))) (defmethod dynamic-variable-bound-p ((dvar surrogate-dynamic-variable)) (not (eq +fake-unbound+ (%dynamic-variable-value dvar)))) (defmethod dynamic-variable-makunbound ((dvar surrogate-dynamic-variable)) (setf (dynamic-variable-value dvar) +fake-unbound+)) ;;; Apparently CCL likes to drop^Helide some writes and that corrupts bindings ;;; table. Let's ensure that the value is volatile. #+ccl (defvar *ccl-ensure-volatile* nil) (defmethod call-with-dynamic-variable (cont (dvar surrogate-dynamic-variable) &optional (val +fake-unbound+)) (push val (dynamic-variable-bindings dvar)) (let (#+ccl (*ccl-ensure-volatile* (dynamic-variable-bindings dvar))) (unwind-protect (funcall cont) (pop (dynamic-variable-bindings dvar))))) Thread-local variables We've refactored the previous code to be extensible. Now we can use metaobjects from the previous post without change. We can also test both implementations in the same process interchangeably by customizing the default class parameter. It is the time now to have some fun and extend dynamic variables into variables with top value not shared between different threads. This will enable ultimate thread safety. With our new protocol the implementation is trivial! The protocol First we will define the protocol class. THREAD-LOCAL-VARIABLE is a variant of a DYNAMIC-VARIABLE with thread-local top values. We specify initialization arguments :INITVAL and :INITFUN that will be used to assign the top value of a binding. The difference is that INITVAL specifies a single value, while INITFUN can produce an unique object on each invocation. INITARG takes a precedence over INTIFUN, and if neither is supplied, then a variable is unbound. We include the constructor that builds on MAKE-DYNAMIC-VARIABLE-USING-KEY, and macros corresponding to DEFVAR and DEFPARAMETER. Note that they expand to :INITFUN - this assures that the initialization form is re-evaluated for each new thread where the variable is used. (defclass thread-local-variable (dynamic-variable) ()) (defmethod initialize-instance :after ((self thread-local-variable) &key initfun initval) (declare (ignore self initfun initval))) (defparameter *default-thread-local-variable-class* #-fake-progv-kludge 'standard-thread-local-variable #+fake-progv-kludge 'surrogate-thread-local-variable) (defun make-thread-local-variable (&rest initargs) (apply #'make-dynamic-variable-using-key *default-thread-local-variable-class* initargs)) (defmacro create-tls-variable (&optional (form nil fp) &rest initargs) `(make-thread-local-variable ,@(when fp `(:initfun (lambda () ,form))) ,@initargs)) (defmacro define-tls-variable (name &rest initform-and-initargs) `(defvar ,name (create-tls-variable ,@initform-and-initargs))) (defmacro define-tls-parameter (name &rest initform-and-initargs) `(defparameter ,name (create-tls-variable ,@initform-and-initargs))) Perhaps it is a good time to introduce a new convention for tls variable names. I think that surrounding names with the minus sign is a nice idea, because it signifies, that it is something less than a global value. For example: DYNAMIC-VARS> (define-tls-variable -context- (progn (print "Initializing context!") (list :context))) -CONTEXT- DYNAMIC-VARS> -context- #<a EU.TURTLEWARE.DYNAMIC-VARS::STANDARD-THREAD-LOCAL-VARIABLE 0x7f7636c08640> DYNAMIC-VARS> (dref -context-) "Initializing context!" (:CONTEXT) DYNAMIC-VARS> (dref -context-) (:CONTEXT) DYNAMIC-VARS> (dset -context- :the-new-value) :THE-NEW-VALUE DYNAMIC-VARS> (dref -context-) :THE-NEW-VALUE DYNAMIC-VARS> (bt:make-thread (lambda () (print "Let's read it!") (print (dref -context-)))) #<process "Anonymous thread" 0x7f7637a26cc0> "Let's read it!" "Initializing context!" (:CONTEXT) DYNAMIC-VARS> (dref -context-) :THE-NEW-VALUE The implementation You might have noticed the inconspicuous operator DYNAMIC-VARIABLE-BINDINGS that is part of the protocol. It returns an opaque object that represents values of the dynamic variable in the current context: for STANDARD-DYNAMIC-VARIABLE it is a symbol for SURROGATE-DYNAMIC-VARIABLE it is a thread-local list of bindings In any case all other operators first take this object and then use it to read, write or bind the value. The gist of the tls variables implementation is to always return an object that is local to the thread. To store these objects we will use the tls-table we've defined earlier. (defclass thread-local-variable-mixin (dynamic-variable) ((tls-table :initform (make-tls-table) :reader dynamic-variable-tls-table) (tls-initfun :initarg :initfun :initform nil :accessor thread-local-variable-initfun) (tls-initval :initarg :initval :initform +fake-unbound+ :accessor thread-local-variable-initval))) For the class STANDARD-THREAD-LOCAL-VARIABLE we will simply return a different symbol depending on the thread: (defclass standard-thread-local-variable (thread-local-variable-mixin thread-local-variable standard-dynamic-variable) ()) (defmethod dynamic-variable-bindings ((tvar standard-thread-local-variable)) (flet ((make-new-tls-bindings () (let ((symbol (gensym)) (initval (thread-local-variable-initval tvar)) (initfun (thread-local-variable-initfun tvar))) (cond ((not (eq +fake-unbound+ initval)) (setf (symbol-value symbol) initval)) ((not (null initfun)) (setf (symbol-value symbol) (funcall initfun)))) symbol))) (let ((key (bt:current-thread))) (with-tls-table (tls-table (dynamic-variable-tls-table tvar)) (or (gethash key tls-table) (setf (gethash key tls-table) (make-new-tls-bindings))))))) And for the class SURROGATE-THREAD-LOCAL-VARIABLE the only difference from the SURROGATE-DYNAMIC-VARIABLE implementation is to cons a new list as the initial value (even when it is unbound) to ensure it is not EQ to +CELL-UNBOUND+. (defclass surrogate-thread-local-variable (thread-local-variable-mixin thread-local-variable surrogate-dynamic-variable) ()) (defmethod dynamic-variable-bindings ((tvar surrogate-thread-local-variable)) (flet ((make-new-tls-bindings () (let ((initval (thread-local-variable-initval tvar)) (initfun (thread-local-variable-initfun tvar))) (cond ((not (eq +fake-unbound+ initval)) (list initval)) ((not (null initfun)) (list (funcall initfun))) (t (list +fake-unbound+)))))) (let ((key (bt:current-thread))) (with-tls-table (tls-table (dynamic-variable-tls-table tvar)) (or (gethash key tls-table) (setf (gethash key tls-table) (make-new-tls-bindings))))))) That's all, now we have two implementations of thread-local variables. Ramifications are similar as with "ordinary" dynamic variables - the standard implementation is not advised for SBCL, because it will crash in LDB. Thread-local slots First we are going to allow to defined dynamic variable types with an abbreviated names. This will enable us to specify in the slot definition that type, for example (MY-SLOT :DYNAMIC :TLS :INITFORM 34) ;;; Examples how to add shorthand type names for the dynamic slots: (defmethod make-dynamic-variable-using-key ((key (eql :tls)) &rest initargs) (apply #'make-dynamic-variable-using-key *default-thread-local-variable-class* initargs)) (defmethod make-dynamic-variable-using-key ((key (eql :normal-tls)) &rest initargs) (apply #'make-dynamic-variable-using-key 'standard-thread-local-variable initargs)) (defmethod make-dynamic-variable-using-key ((key (eql :kludge-tls)) &rest initargs) (apply #'make-dynamic-variable-using-key 'surrogate-thread-local-variable initargs)) ;;; For *DEFAULT-DYNAMIC-VARIABLE* specify :DYNAMIC T. (defmethod make-dynamic-variable-using-key ((key (eql :normal-dyn)) &rest initargs) (apply #'make-dynamic-variable-using-key 'standard-dynamic-variable initargs)) (defmethod make-dynamic-variable-using-key ((key (eql :kludge-dyn)) &rest initargs) (apply #'make-dynamic-variable-using-key 'surrogate-dynamic-variable initargs)) In order to do that, we need to remember he value of the argument :DYNAMIC. We will read it with DYNAMIC-VARIABLE-TYPE and that value will be available in both direct and the effective slot: ;;; Slot definitions ;;; There is a considerable boilerplate involving customizing slots. ;;; ;;; - direct slot definition: local to a single defclass form ;;; ;;; - effective slot definition: combination of all direct slots with the same ;;; name in the class and its superclasses ;;; (defclass dynamic-direct-slot (mop:standard-direct-slot-definition) ((dynamic :initform nil :initarg :dynamic :reader dynamic-variable-type))) ;;; The metaobject protocol did not specify an elegant way to communicate ;;; between the direct slot definition and the effective slot definition. ;;; Luckily we have dynamic bindings! :-) (defvar *kludge/mop-deficiency/dynamic-variable-type* nil) ;;; DYNAMIC-EFFECTIVE-SLOT is implemented to return as slot-value values of the ;;; dynamic variable that is stored with the instance. ;;; ;;; It would be nice if we could specify :ALLOCATION :DYNAMIC for the slot, but ;;; then STANDARD-INSTANCE-ACCESS would go belly up. We could make a clever ;;; workaround, but who cares? (defclass dynamic-effective-slot (mop:standard-effective-slot-definition) ((dynamic :initform *kludge/mop-deficiency/dynamic-variable-type* :reader dynamic-variable-type))) Moreover we specialize the function MAKE-DYNAMIC-VARIABLE-USING-KEY to the effective slot class. The initargs in this method are meant for the instance. When the dynamic variable is created, we check whether it is a thread-local variable and initialize its INITVAL and INITFUN to values derived from INITARGS, MOP:SLOT-DEFINITION-INITARGS and MOP:SLOT-DEFINITION-INITFUN: (defmethod make-dynamic-variable-using-key ((key dynamic-effective-slot) &rest initargs) (let* ((dvar-type (dynamic-variable-type key)) (dvar (make-dynamic-variable-using-key dvar-type))) (when (typep dvar 'thread-local-variable) (loop with slot-initargs = (mop:slot-definition-initargs key) for (key val) on initargs by #'cddr when (member key slot-initargs) do (setf (thread-local-variable-initval dvar) val)) (setf (thread-local-variable-initfun dvar) (mop:slot-definition-initfunction key))) dvar)) The rest of the implementation of DYNAMIC-EFFECTIVE-SLOT is unchanged: (defmethod mop:slot-value-using-class ((class standard-class) object (slotd dynamic-effective-slot)) (dref (slot-dvar object slotd))) (defmethod (setf mop:slot-value-using-class) (new-value (class standard-class) object (slotd dynamic-effective-slot)) (dset (slot-dvar object slotd) new-value)) (defmethod mop:slot-boundp-using-class ((class standard-class) object (slotd dynamic-effective-slot)) (dynamic-variable-bound-p (slot-dvar object slotd))) (defmethod mop:slot-makunbound-using-class ((class standard-class) object (slotd dynamic-effective-slot)) (dynamic-variable-makunbound (slot-dvar object slotd))) The implementation of CLASS-WITH-DYNAMIC-SLOTS is also very similar. The first difference in that ALLOCATE-INSTANCE calls MAKE-DYNAMIC-VARIABLE-USING-KEY instead of MAKE-DYNAMIC-VARIABLE and supplies the effective slot definition as the key, and the instance initargs as the remaining arguments. Note that at this point initargs are already validated by MAKE-INSTANCE. The second difference is that MOP:COMPUTE-EFFECTIVE-SLOT-DEFINITION binds the flag *KLUDGE/MOP-DEFICIENCY/DYNAMIC-VARIABLE-TYPE* to DYNAMIC-VARIABLE-TYPE. ;;; This is a metaclass that allows defining dynamic slots that are bound with ;;; the operator SLOT-DLET, and, depending on the type, may have thread-local ;;; top value. ;;; ;;; The metaclass CLASS-WITH-DYNAMIC-SLOTS specifies alternative effective slot ;;; definitions for slots with an initarg :dynamic. (defclass class-with-dynamic-slots (standard-class) ()) ;;; Class with dynamic slots may be subclasses of the standard class. (defmethod mop:validate-superclass ((class class-with-dynamic-slots) (super standard-class)) t) ;;; When allocating the instance we initialize all slots to a fresh symbol that ;;; represents the dynamic variable. (defmethod allocate-instance ((class class-with-dynamic-slots) &rest initargs) (let ((object (call-next-method))) (loop for slotd in (mop:class-slots class) when (typep slotd 'dynamic-effective-slot) do (setf (mop:standard-instance-access object (mop:slot-definition-location slotd)) (apply #'make-dynamic-variable-using-key slotd initargs))) object)) ;;; To improve potential composability of CLASS-WITH-DYNAMIC-SLOTS with other ;;; metaclasses we treat specially only slots that has :DYNAMIC in initargs, ;;; otherwise we call the next method. (defmethod mop:direct-slot-definition-class ((class class-with-dynamic-slots) &rest initargs) (loop for (key) on initargs by #'cddr when (eq key :dynamic) do (return-from mop:direct-slot-definition-class (find-class 'dynamic-direct-slot))) (call-next-method)) (defmethod mop:compute-effective-slot-definition ((class class-with-dynamic-slots) name direct-slotds) (declare (ignore name)) (let ((latest-slotd (first direct-slotds))) (if (typep latest-slotd 'dynamic-direct-slot) (let ((*kludge/mop-deficiency/dynamic-variable-type* (dynamic-variable-type latest-slotd))) (call-next-method)) (call-next-method)))) (defmethod mop:effective-slot-definition-class ((class class-with-dynamic-slots) &rest initargs) (declare (ignore initargs)) (if *kludge/mop-deficiency/dynamic-variable-type* (find-class 'dynamic-effective-slot) (call-next-method))) Finally the implementation of SLOT-DLET does not change: ;;; Accessing and binding symbols behind the slot. We don't use SLOT-VALUE, ;;; because it will return the _value_ of the dynamic variable, and not the ;;; variable itself. (defun slot-dvar (object slotd) (check-type slotd dynamic-effective-slot) (mop:standard-instance-access object (mop:slot-definition-location slotd))) (defun slot-dvar* (object slot-name) (let* ((class (class-of object)) (slotd (find slot-name (mop:class-slots class) :key #'mop:slot-definition-name))) (slot-dvar object slotd))) (defmacro slot-dlet (bindings &body body) `(dlet ,(loop for ((object slot-name) val) in bindings collect `((slot-dvar* ,object ,slot-name) ,val)) ,@body)) Finally we can define a class with slots that do not share the top value: DYNAMIC-VARS> (defclass c1 () ((slot1 :initarg :slot1 :dynamic nil :accessor slot1) (slot2 :initarg :slot2 :dynamic t :accessor slot2) (slot3 :initarg :slot3 :dynamic :tls :accessor slot3)) (:metaclass class-with-dynamic-slots)) #<The EU.TURTLEWARE.DYNAMIC-VARS::CLASS-WITH-DYNAMIC-SLOTS EU.TURTLEWARE.DYNAMIC-VARS::C1> DYNAMIC-VARS> (with-slots (slot1 slot2 slot3) *object* (setf slot1 :x slot2 :y slot3 :z) (list slot1 slot2 slot3)) (:X :Y :Z) DYNAMIC-VARS> (bt:make-thread (lambda () (with-slots (slot1 slot2 slot3) *object* (setf slot1 :i slot2 :j slot3 :k) (print (list slot1 slot2 slot3))))) #<process "Anonymous thread" 0x7f76424c0240> (:I :J :K) DYNAMIC-VARS> (with-slots (slot1 slot2 slot3) *object* (list slot1 slot2 slot3)) (:I :J :Z) What can we use it for? Now that we know how to define thread-local variables, we are left with a question what can we use it for. Consider having a line-buffering stream. One possible implementation could be sketched as: (defclass line-buffering-stream (fancy-stream) ((current-line :initform (make-adjustable-string) :accessor current-line) (current-ink :initform +black+ :accessor current-ink))) (defmethod stream-write-char ((stream line-buffering-stream) char) (if (char= char # ewline) (terpri stream) (vector-push-extend char (current-line stream)))) (defmethod stream-terpri ((stream line-buffering-stream)) (%put-line-on-screen (current-line stream) (current-ink stream)) (setf (fill-pointer (current-line stream)) 0)) If this stream is shared between multiple threads, then even if individual operations and %PUT-LINE-ON-SCREEN are thread-safe , we have a problem. For example FORMAT writes are not usually atomic and individual lines are easily corrupted. If we use custom colors, these are also a subject of race conditions. The solution is as easy as making both slots thread-local. In that case the buffered line is private to each thread and it is put on the screen atomically: (defclass line-buffering-stream (fancy-stream) ((current-line :initform (make-adjustable-string) :accessor current-line :dynamic :tls) (current-ink :initform +black+ :accessor current-ink :dynamic :tls)) (:metaclass class-with-dynamic-slots)) Technique is not limited to streams. It may benefit thread-safe drawing, request processing, resource management and more. By subclassing DYNAMIC-VARIABLE we could create also variables that are local to different objects than processes. I hope that you've enjoyed reading this post as much as I had writing it. If you are interested in a full standalone implementation, with tests and system definitions, you may get it here. Cheers! Full Article
j Why Virat Kohli, Jasprit Bumrah were missing from Perth nets; India ramp up privacy amid Manchester United-like security - Hindustan Times By news.google.com Published On :: Wed, 13 Nov 2024 04:53:31 GMT Why Virat Kohli, Jasprit Bumrah were missing from Perth nets; India ramp up privacy amid Manchester United-like security Hindustan TimesVirat Kohli in focus: Intense net session begins for upcoming Test series against Australia The Times of IndiaVirat Kohli in Australia for BGT: A timeline India TodayBlack veil of secrecy: India begin training in privacy in Perth ESPNcricinfoIndia to play intra-squad warm-up match at WACA on Friday ahead of Australia Tests but BCCI denies public viewing Hindustan Times Full Article
j Melania Trump's 'I am the most bullied person' video viral as she 'rejects' Jill Biden's tea invite - The Times of India By news.google.com Published On :: Tue, 12 Nov 2024 19:44:00 GMT Melania Trump's 'I am the most bullied person' video viral as she 'rejects' Jill Biden's tea invite The Times of IndiaMelania Trump declines invite to meet Jill Biden over Mar-a-Lago raids when FBI ’snooped through her wardrobe’ MintJimmy Kimmel again mocks Donald Trump for Melania's ‘interesting’ decision to… Hindustan TimesBiden Invites Trump To White House, But Why Is Melania Refusing To Go? News18Melania Trump To Skip White House Meeting With Jill Biden: Report NDTV Full Article
j Eight injured in explosion at oil refinery in UP's Mathura - ANI News By news.google.com Published On :: Tue, 12 Nov 2024 23:00:00 GMT Eight injured in explosion at oil refinery in UP's Mathura ANI News8 injured, three critical in major explosion at Indian Oil plant in UP's Mathura India TodayEight injured in fire at IndianOil’s Mathura refinery BusinessLineMathura refinery blast: Indian Oil refinery explosion injures 12 people The Financial ExpressAt least 8 injured in explosion at Mathura refinery The Indian Express Full Article
j 3 Children, 3 Women Missing After 10 Suspected Kuki Militants Killed In Encounter In Manipur's Jiribam - NDTV By news.google.com Published On :: Tue, 12 Nov 2024 11:11:01 GMT 3 Children, 3 Women Missing After 10 Suspected Kuki Militants Killed In Encounter In Manipur's Jiribam NDTVManipur on boil: 2 more bodies found, 6 missing The Times of IndiaAdditional paramilitary forces rushed to Manipur amid spike in ethnic violence Hindustan TimesLetters to The Editor — November 13, 2024 The Hindu2 men found dead, 6 of family missing day after militants killed in Manipur India Today Full Article
j ouija message received By www.marriedtothesea.com Published On :: Sun, 01 Jan 2023 04:00:00 EST Today on Married To The Sea: ouija message receivedThis RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see! Full Article autogen_comic
j just shut the fuck up By www.marriedtothesea.com Published On :: Wed, 15 Mar 2023 04:00:00 EDT Today on Married To The Sea: just shut the fuck upThis RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see! Full Article autogen_comic
j okay joseph By www.marriedtothesea.com Published On :: Wed, 03 Jan 2024 04:00:00 EST Today on Married To The Sea: okay josephThis RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see! Full Article autogen_comic
j put that back jason By www.marriedtothesea.com Published On :: Wed, 02 Oct 2024 04:00:00 EDT Today on Married To The Sea: put that back jasonThis RSS feed is brought to you by Drew and Natalie's podcast Garbage Brain University. Our new series Everything Is Real explores the world of cryptids, aliens, quantum physics, the occult, and more. If you use this RSS feed, please consider supporting us by becoming a patron. Patronage includes membership to our private Discord server and other bonus material non-patrons never see! Full Article autogen_comic
j Chantal (56) heeft coeliakie, hoe herken je de ziekte? “Ik kan nooit zomaar brood of koffiekoeken eten, elke kruimel zorgt voor krampen” - Het Laatste Nieuws By news.google.com Published On :: Tue, 12 Nov 2024 08:55:00 GMT Chantal (56) heeft coeliakie, hoe herken je de ziekte? “Ik kan nooit zomaar brood of koffiekoeken eten, elke kruimel zorgt voor krampen” Het Laatste Nieuws Full Article
j Hét Product: Genks supplement jaagt suiker schrik aan - Made in By news.google.com Published On :: Tue, 12 Nov 2024 23:42:44 GMT Hét Product: Genks supplement jaagt suiker schrik aan Made in Full Article
j Peter Vandenbempt neemt praktijk op de korrel die steeds meer aan populariteit wint: "Gewoon geel geven, en een paar keer na elkaar" - Voetbalkrant.com By news.google.com Published On :: Tue, 12 Nov 2024 16:40:00 GMT Peter Vandenbempt neemt praktijk op de korrel die steeds meer aan populariteit wint: "Gewoon geel geven, en een paar keer na elkaar" Voetbalkrant.com"Je lacht gewoon iedereen uit": Peter Vandenbempt hekelt "blessures bij doelmannen" en komt met oplossing sporza.beDelanghe onder vuur na acteren tegen RSC Anderlecht: “Lacht iedereen uit” VoetbalPrimeur.beAlle middelen zijn goed: de 'gouden' truc die Cercle Brugge toepaste tegen RSC Anderlecht krijgt (voorlopig) geen staartje Voetbalkrant.comLoopje met de sportiviteit, Delanghe faket blessure tegen Anderlecht VoetbalPrimeur.be Full Article
j Heeft nieuwe eigenaar van SK Deinze centen? Spelers zijn ongerust en verschenen niet op het oefenveld - Het Laatste Nieuws By news.google.com Published On :: Tue, 12 Nov 2024 16:21:00 GMT Heeft nieuwe eigenaar van SK Deinze centen? Spelers zijn ongerust en verschenen niet op het oefenveld Het Laatste NieuwsValse (door)start in Deinze: club krijgt puntenaftrek en ontkent "staking" van de spelers sporza.beSpelers Deinze staken omdat nieuwe overnemer niet betaalt, puntenaftrek dreigt Het Laatste NieuwsEven hol als hoopvol: het overnamedossier van Deinze doorgelicht De StandaardDeinze reageert misnoegd na puntenaftrek en is scherp voor media: “Fake news om de club te destabiliseren” Het Nieuwsblad Full Article
j Een Franse "alleskunner" boezemt iedereen angst in op Gentse Zesdaagse: "Zelfs als renner kijk je naar hem op" - sporza.be By news.google.com Published On :: Wed, 13 Nov 2024 07:12:00 GMT Een Franse "alleskunner" boezemt iedereen angst in op Gentse Zesdaagse: "Zelfs als renner kijk je naar hem op" sporza.beDe Vylder en Ghys sluiten als leiders de eerste dag van Gentse Zesdaagse af sporza.beMinder volks, minder spektakel, maar sneller dan ooit: hoe de Zesdaagse van Gent echt specialistenwerk is geworden De StandaardLindsay De Vylder, wereldkampioen op ontdekkingstocht: “Ik ga dringend beter moeten leren onderhandelen” Het Laatste NieuwsKoen Crucke geeft al zingend het startschot van 6 dagen volksfeest en wielerspektakel in ’t Kuipke Het Nieuwsblad Full Article
j Gladiator 2: De langstverwachte film van het jaar is een mission impossible - VRT.be By news.google.com Published On :: Wed, 13 Nov 2024 04:30:06 GMT Gladiator 2: De langstverwachte film van het jaar is een mission impossible VRT.beHele verhaal bekijken via Google Nieuws Full Article
j ‘Sexiest man alive’ is... alweer niet zo sexy: John Krasinski pronkt op cover van ‘People’ - Het Laatste Nieuws By news.google.com Published On :: Wed, 13 Nov 2024 08:00:16 GMT ‘Sexiest man alive’ is... alweer niet zo sexy: John Krasinski pronkt op cover van ‘People’ Het Laatste NieuwsActeur John Krasinski is volgens People meest sexy man ter wereld NU.nlJohn Krasinski uitgeroepen tot meest sexy man op aarde Het Nieuwsblad Full Article
j Matteo Simoni over geschrapte naaktscènes in ‘Callboys’: “Jan Eelen pakte mijn ‘jos’ en zwierde hem weg” - Het Laatste Nieuws By news.google.com Published On :: Wed, 13 Nov 2024 05:52:00 GMT Matteo Simoni over geschrapte naaktscènes in ‘Callboys’: “Jan Eelen pakte mijn ‘jos’ en zwierde hem weg” Het Laatste Nieuws Full Article
j Belgische architecte: 'We kunnen veel van de Chinezen leren' - De Tijd By news.google.com Published On :: Wed, 13 Nov 2024 06:00:23 GMT Belgische architecte: 'We kunnen veel van de Chinezen leren' De Tijd Full Article
j “Alan Wake II: The Lake House houdt je op het puntje van je stoel” - Pragalicious By news.google.com Published On :: Wed, 13 Nov 2024 07:23:00 GMT “Alan Wake II: The Lake House houdt je op het puntje van je stoel” Pragalicious Full Article
j “Absurde toestanden” bij verplichting zonnepanelen voor grote verbruikers: “Zelfs bedrijf dat niets meer produceert, moet er leggen” - Het Laatste Nieuws By news.google.com Published On :: Wed, 13 Nov 2024 05:00:00 GMT “Absurde toestanden” bij verplichting zonnepanelen voor grote verbruikers: “Zelfs bedrijf dat niets meer produceert, moet er leggen” Het Laatste Nieuws Full Article
j Diepenbeek start onderzoek naar fraude door adjunct-financieel directeur: geld van lokaal bestuur verduisterd - Het Nieuwsblad By news.google.com Published On :: Wed, 13 Nov 2024 06:32:27 GMT Diepenbeek start onderzoek naar fraude door adjunct-financieel directeur: geld van lokaal bestuur verduisterd Het Nieuwsblad Full Article
j Prijsstijging energie-eiland voor kust kan huishoudens jaarlijks "20 euro" extra kosten - VRT.be By news.google.com Published On :: Tue, 12 Nov 2024 16:50:46 GMT Prijsstijging energie-eiland voor kust kan huishoudens jaarlijks "20 euro" extra kosten VRT.beKosten energie-eiland in Noordzee lopen op tot 630 miljoen euro per jaar De TijdKamerleden willen uitstel van miljardencontract voor energie-eiland De StandaardKamerleden willen uitstel voor toewijzing duur contract energie-eiland Knack.beVan der Straeten: “Voorbarig om stekker uit energie-eiland te trekken” Het Belang van Limburg Full Article
j Amerikaanse militair Jack Teixeira (22), die geheime informatie over oorlog lekte, krijgt 15 jaar cel - Het Nieuwsblad By news.google.com Published On :: Wed, 13 Nov 2024 06:22:28 GMT Amerikaanse militair Jack Teixeira (22), die geheime informatie over oorlog lekte, krijgt 15 jaar cel Het NieuwsbladJonge Amerikaanse militair die Pentagon-documenten lekte veroordeeld tot 15 jaar cel VRT.beLive - Oorlog in Oekraïne. Jack Teixeira, die geheime documenten over oorlog lekte, veroordeeld tot 15 jaar cel • Noord-Koreaanse soldaten betrokken bij gevechten, zeggen VS De Morgen15 jaar cel voor Amerikaanse militair die geheime documenten lekte NOS15 jaar cel voor Amerikaanse militair die geheime informatie op internet deelde NU.nl Full Article
j ▶ President van gastland Azerbeidzjan noemt olie en gas ‘godsgeschenk’ tijdens klimaattop - De Morgen By news.google.com Published On :: Tue, 12 Nov 2024 16:05:00 GMT ▶ President van gastland Azerbeidzjan noemt olie en gas ‘godsgeschenk’ tijdens klimaattop De MorgenLIVE Klimaatconferentie - Spaanse premier dringt aan op meer klimaatactie om rampen als in Valencia te vermijden VRT.be"Olie en gas zijn godsgeschenk”: ambities klimaattop krijgen nieuwe klap na uitspraken president van gastland Azerbeidzjan Het Laatste NieuwsVeel Europese leiders slaan de klimaattop dit jaar over: zijn de hoogdagen van Europa’s groene politiek voorbij? De MorgenCOP29: Wil de spaarder investeren in het klimaatbeleid? De Standaard Full Article
j Man die slapende dakloze in Rotterdam ernstig verwondde met steen mogelijk aangehouden in Franse stad Toulon - VRT.be By news.google.com Published On :: Wed, 13 Nov 2024 05:25:27 GMT Man die slapende dakloze in Rotterdam ernstig verwondde met steen mogelijk aangehouden in Franse stad Toulon VRT.beMan die zware tegel op hoofd van slapende dakloze gooide mogelijk gearresteerd in Frankrijk Het Laatste NieuwsVerdachte (32) van aanval met betonblok op slapende dakloze in Rotterdam opgepakt in Franse stad Toulon Het NieuwsbladPoging moord op slapende, dakloze man Opsporing VerzochtArrestatie in Frankrijk na dood dakloze, link met Rotterdamse zaak onderzocht NOS Full Article
j Keuze voor hondstrouwe hardliners illustreert welke koers Trump wil varen - De Tijd By news.google.com Published On :: Tue, 12 Nov 2024 18:28:42 GMT Keuze voor hondstrouwe hardliners illustreert welke koers Trump wil varen De TijdTrumps buitenlandteam zoekt snelle deal in Oekraïne en wil druk op Iran verhogen De StandaardWie zit (voorlopig) op welke stoel in het team van verkozen VS-president Donald Trump? VRT.beMarco Rubio genoemd als nieuwe minister van Buitenlandse Zaken van de VS Het NieuwsbladElon Musk wordt ‘minister van Overheidsefficiëntie’: Trumps ‘dreamteam’ begint snel vorm te krijgen AD Full Article
j Kinderopvang wordt duurder in Bilzen-Hoeselt: “Daarvoor zijn we geen fusie aangegaan” - Het Belang van Limburg By news.google.com Published On :: Mon, 11 Nov 2024 15:51:11 GMT Kinderopvang wordt duurder in Bilzen-Hoeselt: “Daarvoor zijn we geen fusie aangegaan” Het Belang van LimburgHele verhaal bekijken via Google Nieuws Full Article
j Overleden vrouw aangetroffen op oprit van woning in Zwijndrecht, parket opent onderzoek - VRT.be By news.google.com Published On :: Wed, 13 Nov 2024 08:02:08 GMT Overleden vrouw aangetroffen op oprit van woning in Zwijndrecht, parket opent onderzoek VRT.beVrouw vermoord op oprit van woning in Zwijndrecht bij Antwerpen: schedel van slachtoffer werd ingeslagen Het Laatste NieuwsVrouw dood aangetroffen op oprit van een woning in Zwijndrecht, parket start onderzoek naar gewelddadig overlijden Het NieuwsbladVermoorde vrouw aangetroffen voor woning in Zwijndrecht: parket start onderzoek Gazet van AntwerpenLevenloos lichaam van vrouw gevonden op oprit van woning in Zwijndrecht: schedel van slachtoffer werd ingeslagen Het Laatste Nieuws Full Article
j Petra De Sutter is geen kandidaat-voorzitter Groen: "Partij heeft nu iemand nodig die tanden laat zien" - VRT.be By news.google.com Published On :: Wed, 13 Nov 2024 04:25:41 GMT Petra De Sutter is geen kandidaat-voorzitter Groen: "Partij heeft nu iemand nodig die tanden laat zien" VRT.bePetra De Sutter geen kandidaat-voorzitter voor Groen - Musk gaat onder Trump ministerie voor ‘overheidsefficiëntie’ leiden De Standaard“Andere partijen zijn geoliede machines, wij vergaderen ons dood”: Groen snakt naar nieuwe voorzitter en heeft topfavoriet, maar wil Petra De Sutter ook? Het NieuwsbladNeen, Petra De Sutter wordt geen voorzitter van Groen. In dit interview legt ze uit waarom De Morgen Full Article
j Nu Bart De Wever (N-VA) aan zet blijft als formateur: krijgt hij in 2 weken rond wat al 5 maanden niet lukt? - VRT.be By news.google.com Published On :: Tue, 12 Nov 2024 17:14:50 GMT Nu Bart De Wever (N-VA) aan zet blijft als formateur: krijgt hij in 2 weken rond wat al 5 maanden niet lukt? VRT.be“De Wever wil Open Vld én Vooruit in federale regering” Het Laatste NieuwsDe Wever wil Arizona nog eens reanimeren met ‘trucje’, maar of Vooruit deze keer hapt? Het Laatste NieuwsDe Wever grijpt naar beproefd recept om Vooruit snel weer aan tafel te krijgen: het ‘saucissoneren’ De MorgenFormatie: ‘Bart De Wever voert een toneeltje op’ Knack.be Full Article