Why do most programming languages only return a single value from a function? - <AUTHOR> http://arstechnica.com/information-technology/2013/12/why-do-most-programming-languages-only-return-a-single-value-from-a-function/

<comment><USER3> Common Lisp has multiple return values and it's quite useful:

       (let x (f 12) ...)  ; bind x to the first value returned by (f 12) and silently drop the others

       (let (x y) (f 12) ...) ; bind x to the first value and y to the second.

That way, I can return more information without breaking existing code. That point is really important: in Python I can gracefully add an extra argument, from

       def foo(x):
           ...

to

       def foo(x, y=None):
           ...

but I can't return an extra value without changing (and uglifying!) all calling code to handle the tuple.

The answer to the OP is probably that all computer languages derive from Fortran, and Fortran derived from maths, so it chose f(x, y) as the notation for function application. With that notation, there's no elegant way of handling more return values, and language designers might feel that the extra complexity/ugliness isn't worth it. That, and intellectual inertia.

<comment><USER4> Those let forms ares not Common Lisp. However, they could be mplemented by a user with a lisp macro.

</comment></comment><comment><USER5> Link to the actual page, instead of the blogspam version: [http://programmers.stackexchange.com/questions/203471/why- do...](http://programmers.stackexchange.com/questions/203471/why-do-most- programming-languages-only-support-returning-a-single-value-from-a-f)

<comment><USER6> I am not sure whether I would call this specific instance blogspam. It is a curated series arstechnica runs together with stackoverflow that presents the most interesting excerpts.

<comment><USER7> It's pretty worthless, whatever you choose to call it. For one, it adds nothing to the original SO page - no commentary, insight, etc. For another, it doesn't update dynamically, so is already out of date. It's now just duplicating information that will no doubt be refined, so is pretty much having a net-negative effect - exactly the kind of content SO was originally set up to improve upon / obsolete.

<comment><USER8> I'm unfortunately finding Ars more and more like this. Where I once went for novel tech insight and reviews, I now see posts ''curated'' from around the web, and a growing lifehacker-esque quality.

<comment><USER9> Curation is fine, it's hyperbolic posts like this one [1] that appear to value publishing first of getting it right.

[1] [https://news.ycombinator.com/item?id=6896378](https://news.ycombinator.com/item?id=6896378)

</comment></comment></comment></comment></comment><comment><USER10> The given answer is a hack.

The real answer is "most languages _can_ return multiple values", since whenever structs were introduced. And if you're bugged by the fact that there are multiple input parameters, well, just think of the list of params as a tuple. Which you could picture as anonymous structs anyways.

So that in the end, all functions take one tuple and return one tuple, where tuples can be called structs, classes, or, well, tuples.

The _real_ question being, why is it that there is a syntactic sugar for anonymous _input_ structs but that the sugar for _output_ structs is just being introduced.

And there I have to admit I have no idea why.

</comment><comment><USER11> A proof by contradiction:

Assume a language where functions do not only return one value. Now, consider each function in this language. It either returns the same number of values each time, where each has a specific meaning, and they are distinguished either by order or by name. Or it returns an arbitrary number of values, where the semantics of each are the same. But that means the return values are equivalent to a tuple, a dictionary, or an array, which are single values. Therefore we have a contradiction and such a language does not exist. (Yes, I know about values in Lisp and this can be a bit nice. Mostly joking.)

More seriously, ask the question: what relationship between multiple values is useful for returning from functions but not useful enough to be a data structure that can be used in other parts of code?

<comment><USER12> > More seriously, ask the question: what relationship between multiple values > is useful for returning from functions but not useful enough to be a data > structure that can be used in other parts of code?

Sometimes there are pieces of data which are hard to create a cohesive type around. That is, you can compose an new type from other types, but you can't really add any behavior to that new type. This is exemplified by the Tuple type in many languages: it's basically a hack to treat disparate pieces of data as one, and it doesn't offer any way to operate on its own data.

Here's an example from a relatively typical idiom of parsing an int from a string:

        int parsedInt;
        if(int.TryParse(s, out parsedInt))
        {
            Console.WriteLine("Parsed {0}",parsedInt);
        }
        else
        {
            Console.WriteLine("{0} was not an integer",s);
        }

The problem here is that TryParse() really returns two values, one of which will be tested to see if the parse was successful, and the other of which is assigned to parseInt. You could test that the string can be parsed and then get the parsed value in two separate functions, but this would be inefficient because you'd essentially have to parse the string twice. I'm on my Mac so I'm not sure I'm remembering this correctly, but I think C# forces you to put the "out" there, which I think is good because it clarifies that parsedInt will be assigned. However, I think there are a number of ways in which the following (hypothetical) redefinition of TryParse (and C# syntax) feels a lot clearer:

        var parseSucceeded, parsedInt = int.TryParse(s);

        if(parseSucceeded)
        {
            Console.WriteLine("Parsed {0}",parsedInt);
        }
        else
        {
            Console.WriteLine("{0} was not an integer",s);
        }

First of all, the programmer has been forced to assign the success boolean to a clarifying variable. Second, the call has a clearer structure: the input are on the right side of the = and the outputs are on the left.

Let's look at some other possible solutions here:

        var parseTuple = int.TryParse(s);

        if(parseTuple.Item1)
        {
            Console.WriteLine("Parsed {0}",parseTuple.Item2);
        }
        else
        {
            Console.WriteLine("{0} was not an integer",s);
        }

This results in some confusing code. Item1 and Item2 are very poor names for the things they represent.

        IntegerParseResult parseResult = int.TryParse(s); // Didn't use var here to clarify what this code means.

        if(parseResult.ParseSucceeded)
        {
            Console.WriteLine("Parsed {0}",parseTuple.ParsedInt);
        }
        else
        {
            Console.WriteLine("{0} was not an integer",s);
        }

This is a little better, but the creation of a whole new type seems heavyweight, especially given that this new type provides no real functionality. It's tying together two pieces of data which are about to be separated and never used together again (consider, for example, that instead of printing to the console it might return).

I guess the argument I'm making here is that just because a function returns to outputs doesn't mean those outputs have a meaningful relationship that would justify having a new type.

<comment><USER13> I think that's a bad example, because your TryParse function can be thought of as returning a value wrapped in a monad. A Maybe monad, to be specific. In Haskell:

        case (tryParse s) of
          Just n -> putStrLn "Parsed " ++ (show n)
          Nothing -> putStrLn (s ++ " was not an integer")

Nothing is a very convenient little concept: It's a value which isn't a 'legitimate' value in any context. It's always a flag value. In C, for example, there's no way to have a flag value of type int in this context, because tryParse could conceivably return any value of type int as its legitimate result. It's also wonderfully conceptually clean: The function either just returns a legitimate value or it returns nothing legitimate at all, and you always know which it did. The point is, however, it only returns _one_ value, and doesn't rely on any out-of-band communications through errno or similar.

If you want to get fancy, you can use the Either monad. This can allow you to say _why_ a parse failed, for example:

        case (tryParse s) of
          Left n -> putStrLn "Parsed " ++ (show n)
          Right m -> putStrLn "Parse of " ++ s ++ " failed because " ++ m

In this case, tryParse would have the type:

        tryParse :: String -> Either Int String

The point here is, you still only return one value, but they can be either of two different _kinds_ of value, as distinguished by being tagged either Left or Right, and can even be different types. Again, one value, no out-of-band signalling.

And, of course, Haskell has tuples. You can do interesting things without them, however.

<comment><USER14> C# has kind of an equivalent of that, at least for this purpose, of nullable value types. Thus, you could do:

        int? result = int.TryParse(s);

        if(result.HasValue)
        {
            Console.WriteLine("Parsed {0}",result.Value);
        }
        else
        {
            Console.WriteLine("{0} was not an integer",s);
        }

And in C#, you could do the second kinda like:

        object result = int.TryParse(s);

        if(result is int)
        {
            Console.WriteLine("Parsed {0}",result);
        }
        else
        {
            Console.WriteLine("{0} was not an integer",s);
        }

Though there's nowhere simple to make it clear that this TryParse either returns the parsed int, or a string describing why the parse failed. And returning object kinda goes against the spirit of the language, IMHO.

</comment></comment></comment></comment><comment><USER15> The stated reasons are all stupid. The real answer is likely that programming language design is largely a cargo cult exercise and early languages only had single return values, which are easier to implement.

<comment><USER16> Considering there's an entire academic discipline of programming theory I strongly disagree with the description of language design as "cargo-cultism".

<comment><USER17> It is considered cargo-cultism mostly because none of the languages ever have any scientific data to support decisions on various syntax choices. There are some very obvious bad choices of course, because of the large amount of bugs involving them, like manual memory management and pointer arithmetic, but other than that it's all just a hunch.

<comment><USER18> Cargo-cultism is the duplication of the appearance of functioning systems or structures in a context where they are nonfunctional or incorrectly functional. Copying the functionality of an existing system isn't a cargo cult.

The persistence of features in programming languages you're describing isn't a cargo cult because the resulting products work. In addition, there's several benefits of conservative language development: it's generally easier to write compilers; existing programmers will find it easier to adopt a language that mostly resembles ones they already know; and some unfashionable but useful features may be retained.

This is more of a "worse is better" situation than a "cargo cult" one.

</comment></comment></comment></comment><comment><USER19> To answer the question, one has to define precisely what "returning multiple values" should mean.

It's hard to see how this is indistinguishable from returning a list/array/tuple plus supporting list destructuring syntactically, even in a limited way. This works in Ruby, for example:

        name, email = ["Jesse Farmer", "firstname.lastname@example.com"]

So, you can have a function which returns an Array and the caller can "act" as if it's returning multiple values of mixed types. Python can do the same thing. Does this count as supporting "multiple return values?"

One might think about this mathematically "as if" returning multiple values were the (functional) composition of returning a list and list destructuring. If your language supports lists, you'll always have the ability to return a list, so in a world where one wants to support returning multiple values, why add support for it "directly" when you can add support for something simpler and more broadly applicable and get the same results?

I think that's the practical, language-designy answer. I don't like appealing to the mathematical definition of a function, since that doesn't account for languages like Ruby and Python which presumably wouldn't fall into the original poster's bucket of languages that support "returning multiple values."

And yet, I could (in principle) return a tuple of a different length each time I called a function in either language. This means functions in Python and Ruby are about as far away from the mathematical definition of a function as one can get, so that couldn't be why they don't support multiple return values in the sense that the original poster meant.

Lua is one of the few languages I know which differentiates both syntactically and semantically between "returning a list" and "returning multiple values."

        function return_multiple()
          return 1,2,3
        end

        function return_list()
          return {1,2,3}
        end

        a,b,c = return_multiple()
        print(a) -- prints out "1"

        a,b,c = return_list()
        print(a) -- prints out, e.g., "table: 0x7fc991500d20"

Note that I'm using the word "list" where Lua would use the word "table" and using the word "multiple return values" where Lua would use the word "list." That is, in Lua "return 1,2,3" is "returning a list" and "return {1,2,3}" is "returning a table." However, lists aren't values in Lua, i.e., I can't assign a Lua-list to a variable and pass it around, so for clarity's sake I'm using terms that make more sense in non-Lua languages.

The interesting thing about Lua's "multiple return values" is that they almost behave like splatted lists in Ruby — like a chunk of syntax.

        function add(a,b)
          return a + b
        end

        function return_multiple()
          return 1,2
        end

        sum = add(return_multiple())
        -- sum is now 3
        -- add({1,2}) would throw an error, however

In Lua, one can use "unpack" to destructure/splat lists like {1,2,3}, so

        sum = add(unpack({1,2}))

would work.

At the end of the day, these approaches all tend to be isomorphic to each other. Given Lua's design considerations (small, fast, easy to move in and out of C, etc.) I'm guessing it makes these distinctions for performance/memory management reasons, but I don't know enough about Lua's internals to say whether that's the actual justification. Outside of that I think Lua's choices are strange since you now have functions which don't return _a_ particular value, but rather these non-syntactic entities called "multiple return values."

<comment><USER20> Lua's weird return values are basically just exposing the fact that it's a stack-based VM and letting the user take advantage of that. foo(1, return_two_values(arg), 2) pushes 1 onto the stack, pushes arg onto the stack, calls return_two_values (which pops one value from the stack and pushes two new ones), pushes 2 onto the stack, and then calls foo, resulting in foo being called with four arguments.

With this design you get zero-overhead (you save the construction of a table) multiple return values for free, since it simply requires a trivial bit of syntax and no error checking to verify that a function only left zero or one values on the stack. Lists aren't exposed as concrete things that can be passed around because the really aren't things at all.

<comment><USER21> Actually, foo(1, return_two_values(arg), 2) will call foo with only three values. The , truncates (or extends) the left expression to exactly one value.

      > return (function() end)(), 5
      nil	5
      > return (function() return 1,2,3,4 end)(), 5
      1	5
      > return 5, (function() end)()
      5
      > return 5, (function() return 1,2,3,4 end)()
      5	1	2	3	4
      > return 5, (function() return nil end)()
      5	nil

</comment></comment></comment><comment><USER22> Perl's context addresses this in a useful way; a function can be called in a void context (no value expected), a scalar context (one value expected) or a list context (multiple values expected.) The function can detect which context it's being called in and alter it's response accordingly.

List context works really well with list assignment, which lets you assign multiple return values directly to muliple scalar variables. It also works well with passing multiple return values to the input of another function, of course.

</comment><comment><USER23> Racket can actually return multiple values rather than a product type, which is what Python does. However people don't usually use it because it's easier to just return a pair or whatever and then pattern match on it.

[http://docs.racket-lang.org/reference/eval- model.html#%28par...](http://docs.racket-lang.org/reference/eval- model.html#%28part._values-model%29)

<comment><USER13> Common Lisp can do the same thing, and people typically prefer returning a product type because _capturing_ multiple return values invariably introduces some extra syntax.

Forth functions (or words, if you insist) can return multiple values as easily as they can return a single value, but the stack metaphor makes this a lot more natural. This is also true of Joy and RPL and other languages which are conceptually organized around mutating a (notional) stack. Multiple return values only become unnatural when you choose an abstraction other than the stack.

<comment><USER23> I have used RPL (I have an HP 50G) and yeah, you can do some fun stuff with the stack. Although I wish they would just port Factor to it already :P

</comment></comment></comment><comment><USER24> In low level languages such as C, I imagine it was an attempt to map to the machines of the day. It isn't hard to come up with an ABI that allows for returning multiple values, and with registers being thrown into CPUs left and right now days, using 1 more register to allow two return parameters would actually be really nice.

(Of course you'd have to dump anything beyond that onto the stack!)

I imagine the world would be a lot different (or at least a bit less buggy!) if C had allowed for returning an error code in addition to a return value.

Once you get to higher level languages though, the need sort of falls away. Put data into a container of some type, call it a day.

</comment><comment><USER25> I use multiple return values in Python all the time. Returning tuples (which due to multiple assignment actually work / appear as multiple return values). And using continuations, generator functions, etc.

</comment><comment><USER26> Perhaps the more interesting question is why do most programming languages allow several input values?

I'll make the argument that in Haskell, functions BOTH support only a single input value and a single output value. For example, consider the function (+) which takes two numbers and returns their sum. The type of (+) is (+) :: Num a => a -> (a -> a). I have added the parentheses to emphasize the syntax of the type. (+) is a function which takes a single number as input and gives a single function as output!

Now, we can do something like f :: (a,b) -> (x,y,z) and write:

      let (x0,y0,z0) = f (a0,b0)

But this isn't really multiple input or return values. We are just inputting or returning a struct (with constructor (,) or (,,), respectively), and we can pattern match against it for the return value.

I think that any elegant language should support as few "primitive features" as possible - it should be simple, and let a few powerful ideas (e.g., first- class functions, currying, and pattern matching) let the rest fall out. I think Haskell really embodies this idea.

<comment><USER27> I've thought about switching to only one input value for Rust, but it's needed for the FFI, so once we're paying the complexity there we might as well pay it everywhere. Besides, it'll make it easier to add optional and named parameters if we ever do in the future.

<comment><USER28> Wouldn't memory layout on the stack be the same for a tuple vs a sequence of arguments?

<comment><USER27> Unfortunately calling conventions are hideously complex; some arguments go in registers, some go on the stack, some change depending on whether they're structs or floats or not…it's a giant mess :(

</comment></comment></comment></comment><comment><USER29> It seems to me that some domain-specific computations are better modeled with the ability to return multiple values. For example, digital signal processing - a handy abstraction in DSP is the idea of having "blocks" and simply connecting the outputs of some blocks to the inputs of other blocks. A block in this model can be viewed as a function which is executed continuously.

</comment><comment><USER14> I still haven't read a really good reason. I use Ruby for most of my personal work, which does infact let you return multiple values in a clean and straightforward way. Though being dynamically typed and not requiring variable declarations probably helps more with that.

I work mostly in C#, and the lack of multiple return values hits me about once a month or so, and I usually have to create a new class just for the purpose of returning two values from one function one time that will never be used again. There's several other possibilities, most of which are even more awkward and annoying - out and ref params, which need some variables declared separately; arrays, lists, and dictionaries, which need either the same type or casting and index by numbers or a string, and tuples, which have strong typing, but name everything Item1, Item2, etc. It might be a good solution if there was support for anonymous functions as return types, but I don't think you can do that right now without using dynamic.

<comment><USER18> Sounds like C# needs destructuring assignment. In Ruby, you're more or less just returning an array that gets destructured immediately -- "return a, b" works the same as "return [a, b]".

<comment><USER14> Yeah, I thought of that. The trouble is, in Ruby, that works nicely as syntactic sugar because of the dynamically typed nature of the language. Methods have no declared return types, variables also have no declared types, arrays and other data structures hold any kind of object, and you can try and do anything to any variable, and the interpreter will figure out at runtime if that's possible and throw if it can't do it. When you "return a, b", it's clearly an array of objects, since that's the only array Ruby has, and it doesn't matter what the types of a and b are, since the array can hold any type, and the return type is never declared anyways. When you go to use it, you can do "a, b = foo()", which is fine, since you don't have to declare types of variables anyways. You can try and do anything to those a and b after foo, and the interpreter figures it out at runtime.

In C#, and I expect Java and most other more statically typed languages, you run into all kinds of awkwardness doing this. Arrays and other data structures are strongly typed by default, and number and type of method returns must be declared. You could return a object[], which is easy enough to declare, but then on the call side, you'd have to declare a object[] to receive the return, then individually cast each element to whatever type it's supposed to be before you can do anything with it. Kinda awkward, and against the spirit of the language.

Declaring multiple returns of different types doesn't seem to help much, either, since you can't declare 2 variables of different types on the same line, so you have to declare them both somewhere else, making it about as awkward as using out params.

The best solution I can think of that fits with the spirit of the language is to use anonymous types. You can already do:

var something = new { Foo = a, Bar = b }; something.Foo.DoStuff(); something.Bar.DoStuff();

In that case, the compiler creates a class for "something" for you invisibly, based on the properties you assigned. What's neat about that is that it maintains strong typing of everything, since it figured out the types from the declaration, so you can still do things with the Foo and Bar properties, and it knows what types they are and enforces all of the standard compile-time type checking.

The downside is that you can't return these anonymous types from a method, as the method return type must normally be statically declared. You could return dynamic, but then you lose all of that static type checking, and are back to a slightly cleaner version of returning object[]. I suppose the language authors figured that it's too complex to return anonymous types from methods, as far as figuring out at compile-time what you're actually calling and what it would return.

And now that I think I've successfully argued myself out of what I originally wanted to do with a ridiculous number of words, I'll just give up.

</comment></comment></comment><comment><USER30> My thought was, values from function calls used to be returned in one dedicated CPU register (maybe two in some exceptional cases).

</comment><comment><USER31> "The one place they are pretty convenient is in languages (like Python) where multiple return values from one function can be used as multiple input parameters to another."

Python only returns a single value - a tuple. It's just that there is symantic sugar on the functions side to fold multiple values into a tuple, and on the side that's returned to, it's simple value unpacking.

You can validate this in the following way:

        >>> def foo():
        ...     return 1, 2
        >>> x = foo()
        >>> isinstance(x, tuple)
        True

The unpacking of tuples into arguments is simply more syntactic sugar, if very useful syntactic sugar.

In short, while I love Python, it's still returning just a single value - <USER2> tuple, that gives the appearance of returning multiple values.

</comment><comment><USER27> It's pretty simple IMO: supporting multiple return values constitutes unnecessary language complexity once you have tuples in your language (which you should, because they are extremely simple and generalize to many other patterns beyond returning multiple values).

<comment><USER21> Why support multiple arguments?

<comment><USER4> Indeed.

<comment><USER27> In many cases, I do think it's the right decision to only support one argument per function, but I explained why Rust doesn't do that here: [https://news.ycombinator.com/item?id=6949077](https://news.ycombinator.com/item?id=6949077)

</comment></comment></comment></comment><comment><USER32> This is an interesting question!

I've come across the thought myself from time to time... usually have to end up creating objects/structs to then return, though in the past when I've been lazy (on iOS) I've chunked things into NSArray/NSDictionary.

But darn, I can't remember specific examples right now, I know I've definitely had moments where returning multiple things would have been nice lol.

<comment><USER33> I've found returning type and boolean useful more than once, usually 'data of type and false if something went wrong or the return data is invalid, data of type and true if valid.'

std::pair<T, boolean> was like a gift from the gods when I found out about it

</comment></comment><comment><USER34> Generalizing, there's really a math relation but it's most because the language designer wanted this. Nobody wanted to add this feature (not so trivial to a compiler) if they just could return a struct.

</comment><comment><USER35> Most? Isn't "pass by reference" a feature of most languages? But yeah "mathematical constructs" don't most kids learn functions in elementary school? How is this front page news?

</comment><comment><USER36> Maybe because the dominant use pattern where return cannot be substituted by output parameters is in expressions. In other words if there were no expressions then return would not be needed at all.

</comment><comment><USER37> Because most programming languages are not that good.</comment>


The Beauty of Palm Leaf Manuscripts - <AUTHOR> http://britishlibrary.typepad.co.uk/asian-and-african/2014/11/the-beauty-of-palm-leaf-manuscripts-1-central-thailand.html

<comment><USER2> Would have been nice if there were some photos of a palm leaf manuscript in use or how the text is laid out. I can sort of guess, but it spends all its time talking about the cases and paintings...

<comment><AUTHOR> I found a pretty good overview here: [http://www.idc.iitb.ac.in/resources/dt- july-2009/Palm.pdf](http://www.idc.iitb.ac.in/resources/dt-july-2009/Palm.pdf)

</comment></comment><comment><USER3> I was a little surprised there is no mention of the Burmese script. The distinctive shape of Burmese (limited number of straight lines) is due to palm leaves being the standard medium on which it was written. Straight lines are more likely to split the leaves.</comment>


Ask HN: Awesome Mailing Lists? - <AUTHOR>

I have been lurking on the PLT Scheme mailing list for quite some time, and I am regularly impressed with what I discover from reading it.
For a contrast, the Rails mailing list is awful, so it isn't as simple as just finding a mailing lists on topics you enjoy.
What other mailing lists do you enjoy? <comment><USER2> Look into the public-facing (non-membership) mailing lists used by some of the hackerspaces. They all have their own passions and politics, so the ones I like won't likely be the ones you like. CCCKC has an information-security specific list that's just starting to get good. The main list may be too eclectic for most.

</comment><comment><USER3> If you like the PLT list, I've been a huge fan of the clojure google group. Little to no spam gets through thanks to moderation, and the people are friendly and helpful while talking about all the different topics related to clojure and using it on interesting problems.

</comment><comment><USER4> NANOG.</comment>


The Machine That Changed the World: Interview with Alan Kay (1990) - <AUTHOR> http://openvault.wgbh.org/catalog/V_D9DC82D997454711A71B586E17D23119 <comment><USER2> > my feeling is, is that anything that is larger human scale invokes > mechanisms concerned with religion so you have a priesthood with white > coats, you know all the paraphernalia were there and some people thought it > would take over the world and some people wanted it to take over the world, > and some people were afraid it would take over the world, and none of those > things happened.

Can things be said any more brilliantly, for all inclusive matters involving humans?

</comment><comment><USER3> > Kay: Total Recall, you know Total Recall, somebody said, if you like road > accidents, you'll love this picture. And the, that kind of stuff, you know, > where you have, you know, five people you have to kill every 30 seconds or > so is very easy to set up in virtual reality. I'm sure that a large > percentage of the population will enjoy it.

Now there's grand theft auto serie and others.

</comment><comment><USER4> I've been trying for a while to try to download this video... can't seem to grab the raw video file. Anyone have any ideas?

<comment><USER5> It's slightly tricky. The files are hosted on S3 but have some interesting referer and key restrictions. You can see the webm and mp4 URLs in the source but can't download them naively. But if you open Chrome's console and look at the Network tab you can right-click on something like a css file and choose "Copy as CURL". This produces a commandline spooge that has all the necessary stuff.

Paste that into a text file and replace the css URL with the URL of the video. Then add " > kay.video.mp4" to the end to pipe to a file, and paste it all into a Terminal window. Voila. The file is 577978075 bytes long.

<comment><USER6> The cleverest tip I've read today</comment></comment></comment>


How to Structure Django Projects - <AUTHOR> https://www.jamesbeith.co.uk/blog/how-to-structure-django-projects/ <comment><USER2> This is a totally acceptable approach but not one I personally would prefer.

One of the advantages of django apps is having cleanly divided responsibility. For example, I worked on a large django project that had 70+ apps and several dozen developers. Engineers were encouraged to create new apps for new functionality. In some cases apps could be cleanly pulled out of the code base and converted into a library. The ability to pull libraries out of the "main" repo also meant that certain teams could more easily "own" parts of the codebase. At a different company we actually decided to split our monolith into 3 separately deployed services and it was pretty easy for us to copy the appropriate Django apps into new services.

In general I've found that early in a company's life it is much easier to manage the complexity of a monolith and I've found that Django's app abstraction allows developers to communicate which parts of the codebase shouldn't be overly intimate with one another, which at least gives you a hope of breaking pieces into separately deployable libraries or services as the company/project scales up.

<comment><USER3> The problem I have with the multi-app approach is that it's really hard to change apps once you've defined them; migrating a model from one app to another is a massive PITA. Because of this, in my experience you pay a high price if you don't define the service boundaries correctly first try. The whole idea behind the "build the monolith first" advice is that in general you don't really know what the appropriate boundaries are going to be ahead of time, so I view this as problematic.

Also over the last few years I've hit multiple schema-migration bugs that only occur on relations spanning apps, and no such bugs within single apps, so there's definitely a "less well-trodden path" argument against multiple apps.

Finally migration squashing didn't work well when I tried it on my multiple- app project; it wasn't able to squash past the first foreign key to another app. This might have improved in the last couple releases.

I've not worked on a project as large as the one you describe, so I'm open to the possibility that at that scale there are new problems that crop up (e.g. managing a single migrations directory could be fun with that many developers), but I'd guess that most developers won't hit that scale, and yet the common wisdom for getting started is to try to split out small apps early, which I consider harmful.

<comment><USER4> (I'm working on a big Scala Application, but this was migrated from a large Django Application) well in a large project the migrations folder is not your problem. no matter if it is big or small. It's mostly the seperation of concern that can kill your ability to add code to your application. Once your application gets big it's really hard to have a good structure to scale further. The correct "app layout" is pretty important and I think the app structure is a good way to structure __most__ applications.

<comment><USER3> > Once your application gets big it's really hard to have a good structure to > scale further

Agreed - I would note that there is nothing stopping you from having good structure (with multiple independent/encapsulated services/apps) inside a single Django "app" (as the OP suggests).

</comment></comment></comment></comment><comment><USER5> As described by the documentation, Django applications are "a Python package that provides some set of features", reusable, and are "a combination of models, views, templates, …, URLs, etc". What this approach describes is not standard at all to the Django app structure. Some cons to this include: no ability to make new versions of an app and use them concurrently, removing set standards and confusing ANY new engineer that must work on the project, no compartmentalization of business logic, etc etc. There is a reason why Django is structured the way it is. Removing the battle tested skeleton may mean it is not the web framework for your particular project.

For a detailed explanation of what Django app's are and why they are structured the way they are please refer to the `2. Intro to Django Applications` section of [https://medium.com/@djstein/modern-django- part-2-rest-apis-a...](https://medium.com/@djstein/modern-django-part-2-rest- apis-apps-and-django-rest-framework-ea0cac5ab104)

For any new Django engineers reading this, I would point you towards [https://github.com/pydanny/cookiecutter- django](https://github.com/pydanny/cookiecutter-django) for the best / most complete structure.

<comment><USER3> > no compartmentalization of business logic, etc etc

The proposed design does compartmentalize business logic; it's all in the `domain` package, divided by business application/use-case. This looks to be to be inspired by the DDD approach.

> no ability to make new versions of an app and use them concurrently

Anecdotal, but I've never required this in my monolithic web app (6 developers), and I don't foresee requiring it any time soon.

> Removing the battle tested skeleton may mean it is not the web framework for > your particular project.

This is a bit dogmatic for my taste; Django is just a tool. If the default layout works for you, great. When your project outgrows that default, change it. (But I'd advise being sure that you really have outgrown the defaults before doing so).

</comment></comment><comment><USER6> Doesn't manage.py have expectations of where things are?

I also think it depends on the project. If your project has 12 apps, you might want to do it around the apps. If it has 3, you might do it around data, domain, and interfaces.

Why data domain and interfaces, btw?

<comment><USER3> > Doesn't manage.py have expectations of where things are?

Yes, but this is all configurable/remappable; FTA:

> One last note to add is that this project structure results in fewer > INSTALLED_APPS entries. The data/ directory, containing the models, and the > interfaces directories, containing templates, static files, management > commands, etc., all need to be included as entries.

Related; here's an example of an extreme surgery resulting in a single-file Django app:

[https://simpleisbetterthancomplex.com/article/2017/08/07/a-m...](https://simpleisbetterthancomplex.com/article/2017/08/07/a-minimal- django-application.html)

</comment></comment><comment><USER7> > Here are some notes on how to layout a Django project.

Step 0, don't use Django, use Pyramid, unless most of your app is DRF.</comment>


Aerosol and surface stability of HCoV-19 compared to SARS-CoV-1 [pdf] - <AUTHOR> https://www.medrxiv.org/content/10.1101/2020.03.09.20033217v1 <comment><USER3> From the paper: "Our results indicate that aerosol and fomite transmission of HCoV-19 is plausible, as the virus can remain viable in aerosols for multiple hours and on surfaces up to days."

This partially explains how quickly this virus spreads, and why such incredible measures are required to stop the spread.

<comment><USER4> > and why such incredible measures are required to stop the spread.

Since we're learning that the fatality rate is much lower than SARS, as was feared early on, and that it's much more mild of an illness -- and also that it's highly contagious and already widespread -- it strikes me that the opposite is true.

We should do everything we can to protect the elderly and ill, but a disease that is so mild that 85% of people over 80 still survive it, it doesn't strike me as something worth tanking the global economy over. If you're middle-aged or younger and you drive to work, travel internationally, drink alcohol, etc., you've taken similar risks as COVID-19 poses to you.

This is incredibly unpopular on HN, and I'm ok with that. Holing everyone up in their apartments for the next year would put almost everyone reading this out of a job, many without housing, and without healthcare. This is a "keep calm, wash your hands, and carry on" moment, and we're failing.

<comment><USER5> There are reports, that plenty of those "80%" mild cases have pneumonia and permanent lung scaring (aka, you will never be able to play intense sports), even though they don't end up in a tube/forced oxygenation....

Sorry, I'd rather take a 2 months economy hit, than a long term burn.... which will cause a longer term economic problem as well.

<comment><USER4> The decision isn't to either get it now or not at all. The decision if you'd like to get it now or later.

If you decide to get it now, you probably have a job. If you decide to get it later, you quite possibly don't.

<comment><USER6> And if everyone gets it now the health system collapses, 15% of the infected die and anyone who needs a hospital for any life-saving reason also dies.

</comment></comment></comment></comment></comment><comment><USER7> Thanks for posting this. As someone in public health research, I really appreciate being able to get as close as possible to empirical findings about corona. It helps me deal both rationally and emotionally with the crisis. Obviously "it's just a preprint", but this is great to have -- leagues better than a watered-down and panicked-up version from cross-eyed cable news hosts.

I've found that the major scientific and biomedical research journals - <USER2> BMJ, the Lancet, the NEJM, JAMA, Science, Nature - collectively have some of the best stuff on coronavirus out there. It's not as fast as the news, but it's a hell of a lot more rigorous.

</comment><comment><USER8> I wonder what - if anything - post offices / delivery services are doing about this stuff? A lot of people hunkered down at home are going to use those to order things.

<comment><USER9> People should not handle any package for at least 3 days after reception assuming this paper is correct (unless they manually disinfect it).

EDIT: actually the paper doesn't seem to conclude that 3 days is enough, and instead than an unknown number of days, but at least 3, is required, at least relative to their detection method

<comment><USER10> Can you effectively disinfect porous materials like paper and cardboard?

<comment><USER11> Spray disinfectant on it. Expose to bright sunlight. Cook it at 70 deg C.

</comment></comment></comment></comment><comment><USER12> "In short, aerosols (<5 μ m) containing HCoV-19 (105.25 69 TCID50/mL) or SARS- CoV-1 (106.75-7 TCID50/mL) were generated using a 3-jet Collison nebulizer and fed into a Goldberg drum to create an aerosolized environment. Aerosols were maintained in the Goldberg drum and samples were collected at 0, 30, 60, 120 and 180 minutes post-aerosolization on a 47mm gelatin filter (Sartorius). Filters were dissolved in 10 mL of DMEM containing 10% FBS. Three replicate experiments were performed."

I looked up "Goldberg drum" and found this [https://www.researchgate.net/figure/Aerosol- apparatus-A-40-L...](https://www.researchgate.net/figure/Aerosol- apparatus-A-40-L-Goldberg-drum-used-for-aerosol-survival-studies-inside- the_fig3_231212356) which looks pretty small. It would dissipate a lot more in a room, and even more outdoors. How can we account for the effects of dissipation?

</comment><comment><USER13> The slightly tangential question I had was, OK, a potential active lifespan of 2-3 hours in aerosol form, but in a normal environment, how long is it likely to remain in aerosol form before settling on a surface, and in what environments is it likely to remain airborne for 2-3 hours?

<comment><USER7> That's a good question, no doubt. A related one I had was (and maybe I missed this), but what's the "dose" of virus one needs to get infected? In the discussion of decay / half life of the virus on surfaces and in the air, I wondered about this. It's one thing if the virus can hang around for three hours and infect you at any time, and another thing if it's in the air for three hours but decays at ____ rate and can only infect for 1 hour.

<comment><USER14> TCID50 gives you information on infectivity. Not as good as LD50 though [https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4861875/](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4861875/)

</comment></comment></comment><comment><USER15> From the paper:

> Virus stability in aerosols was determined as described previously at 65% > relative humidity (RH) and 21-23°C. In short, aerosols (<5 µm) containing > HCoV-19 (105.25 TCID50/mL) or SARS-CoV-1 (106.75-7 TCID50/mL) were generated > using a 3-jet Collison nebulizer and fed into a Goldberg drum to create an > aerosolized environment. Aerosols were maintained in the Goldberg drum and > samples were collected at 0, 30, 60, 120 and 180 minutes post-aerosolization > on a 47mm gelatin filter (Sartorius). Filters were dissolved in 10 mL of > DMEM containing 10% FBS. Three replicate experiments were performed.

</comment><comment><USER16> COVID19 lives for 3 hours in air. 2-3 days on stainless steel and plastic. Only 4 hours on copper, which is why all door handles should be copper! Other anti-viral and bacterial materials are available as well.

<comment><USER17> or everyone should wear copper gloves

<comment> GuB-42 Or gloves filled with mercury...

Obviously, that's a joke but it is probably not as bad as you might think. Liquid elemental mercury is relatively harmless. Compare to mercury vapor, which is bad, and organic mercury, which is worse than bad.

</comment></comment></comment><comment><USER16> Here's how well copper as a surface kills viruses and bacteria: [https://en.wikipedia.org/wiki/Antimicrobial_properties_of_co...](https://en.wikipedia.org/wiki/Antimicrobial_properties_of_copper)

</comment><comment><USER5> So, someone sick goes into an elevator/bus/small places, they cough, and get on. The guy coming 5 mins later, having no clue, might get infected....

And while 'wash your hand', helps some, it is mostly just a way to make people feel control, as that seems not to be the main vector of transmission. This explain how quickly many people get it.....

This is a crude analogy, but: if you are close enough to someone and you would probably noticed if they 'farted', then there is a good chance that you would get some potential covid-19 particles if their coughed it out.....

<comment> GuB-42 Don't forget the "viable on surfaces up to days" part.

Someone coughs on a doorknob, _hours_ later, you touch the doorknob, virus goes on your hand, you touch your face, you get infected.

Even if you don't touch your face, your dirty hands spread the virus everywhere, including on food and to other people.

And even if touch isn't the main vector, it is better than nothing. Remember that the goal is to make the rate of transmissions less than 1, so if washing hands help us go down from 1.1 to 0.9, even if isn't that much of a difference, it is all we need to beat the virus.</comment></comment>


Ask HN: A Process Definition to Implementation Software - <AUTHOR>

Does anybody know if there exists any such software which can do following tasks?
1. A Person defines a process in the organization through flowcharts. This is a very high level and abstract definition of the process.
2. The software takes this flowchart as input and as a output generates a web application that is nothing but a electronic version of the process.
I am running a business which can be run effectively only if the I get my internal processes defined right. Where the application should reach first, who should scrutinies it, who need to authorize it before it reaches a particular department etc. I know all this but dont want to invest in hiring developers and explaining it to them, they in variably screw it up. <comment><USER2> Yes, it's called BPM (Business Process Management) and Workflow Engines. There are some open source ones as well.</comment>


I accidentally built a nudity/porn platform - <AUTHOR> https://elazzabi.com/2020/08/11/the-day-i-accidentally-built-a-nudity-porn-platform/ <comment><USER2> \- anything that allows file upload -> porn / warez / movies / any form of copyright violation you care to come up with.

\- anything that allows anonymous file upload -> childporn + all of the above.

\- anything that allows communications -> spam, harassment, bots

\- anything that measures something -> destruction of that something (for instance, google, the links between pages)

\- any platform where the creator did not think long and hard about how it might be abused -> all of the abuse that wasn't dealt with beforehand.

\- anything that isn't secured -> all of the above.

Going through a risk analysis exercise and detecting the abuse potential of whatever you are trying to build _prior_ to launching it can go a long way towards ensuring that doesn't happen. Reacting very swiftly to any 'off label' uses for what you've built and shutting down categorically any form of abuse and you might even keep it alive. React too slow and before you know it your real users are drowned out by the trash.

It's sad, but that's the state of affairs on the web as we have it today.

<comment><USER3> github is fairly open and it's not used for porn, yet.

<comment><USER4> It's definitely used for pirated stuff.

Put any technical book title into google with site:github.com in it and click the first PDF that shows up.

<comment><USER5> There's also a font piracy site that simply trawls public Github repos for the font's filename

<comment><USER6> Ah, so _that's_ why the site's so trigger-happy with the excessive-activity bans that it's nearly unusable unless you're logged in.

<comment><USER7> And cloud tokens and other credentials. Those get scraped super fast.

</comment></comment></comment></comment></comment></comment><comment><USER8> I've been maintaining a community forum for more than a decade. We had some abusive users, so we introduced pre-moderation. Meaning, any new user is on probation for a few posts, and all anonymous posts have to be manually approved by an admin to be posted publicly. This has pretty much completely stopped the visible abuse.

However, for about 10 years, there are bots registering every day, some of them even make realistic accounts with cool and unique username, email, even description. Strangely, the email and username never match... And they make post with html links embedded. They even know to actually select the 'HTML' content type, which is an extra select input. Some bots even make a few innocent posts, before the link spam. But just too few to get past probation. Obviously, the spam posts never get approved, and accounts never get out of pre-moderation queue and yet they're still trying every day... Not intelligent enough to make more than 2 dumb posts.

Similarly, I have some work projects that have user registration with a human on-boarding process, where another person has to add the user to their group for them to share any data, none of which is ever public. So these bots are tirelessly registering, and staying in limbo forever. Thousands of useless accounts.

It boggles the mind how much energy is wasted, but I guess it must my profitable enough.

<comment><USER9> It's amazing how some people can't seem to spot a bot/spam post, no matter how obvious.

One of the websites I host is for a retired elderly middle-aged academic who pens articles about his former field and invites comment.

Almost every week I'll get an email from him along the lines of _" Is this worth following up?"_ and attached will be either a comment reading something like _" I love your article. So much good info and useful to me.."_ or an email from some firstname.lastname@example.com address saying _" We love your site. It has much good infos and is useful but we are notice your CEO could being better..."_

No matter how many times I tell him to look for the telltale signs...

* Random gibberish email from address

* Half a dozen links in the comment

* Broken English

* Generic text which could apply to ANY article or website in the bloody world

...he'll still forward them to me and ask if they're worth getting in contact with. Every time, I'm gobsmacked how he can fall for such inept spamming.

<comment><USER10> The ineptitude of the spamming is actually a sign of eptitude -- they intentionally include the signs you look for because you're a waste of their time. They have figured out the precise line to walk where bad marks like you avoid them but easy marks like him engage.

<comment><USER9> I've heard that's the thinking behind the infamous and infamously 'reeking of scam' Nigerian Prince email scams too. And the fact that people still fall for them shows it's a seemingly a strategy worth pursuing.

[But a discussion here on the ridiculously obvious scam that people fall for all the time is probably too off-topic --even for HN!]

 _PS: Upvote for "eptitude". Even if it's not a real word, it ought to be. [And I'm not going to spoil things by looking it up]_

<comment><USER11> Aptitude and ineptitude are the now divergent pair, for your interest. Apt was turned into ept

<comment><USER12> ah TIL

</comment></comment></comment></comment></comment></comment><comment><USER13> "Take a competitor product, remove all features you don't need, and make it crazy fast."

Seems to me there are hundreds of lifestyle businesses just waiting to happen by following this formula. So many good ideas out there could be made so much better by reducing them to their essentials, but making them elegant and "crazy fast".

<comment><USER14> Been forced to use Jira instead of pivotal tracker.

Wow. Traded all useablity for endless features.

Our setup barely works. And creating a story is such a massive pain. Sometimes things just won't work.

So I refuse to use it for stories beyond one mega story.

<comment><USER15> One place I worked wanted multiple people to "own" a story, but JIRA doesn't work like that, so they implemented a totally new custom "owner" field that did allow it and then told everyone not to use the native owner field. Now you had to track everything two ways.

<comment><USER16> This isn't _that_ bad.

What makes this worse is when 1/3 of the teams in your org decide that they want a similar feature, but each comes up with their own custom-named tag ("owner", "lead", "point person", "point of contact", "jefe").

And then you want to run some jql queries against those tickets, and you have to use disgusting query generators to de-dupe the tag monstrosity.

They've done an excellent job of giving you _just enough_ features to shoot yourself in the foot with.

</comment></comment></comment></comment><comment><USER17> Yup. If you build a communications platform, it will be used for spam. If you build a hosting platform, it will be used for porn. If you build a linking platform, it will be used to spam links for porn.

Anything else requires a constant uphill battle of content filtering and deletion. You could call it censorship, but it's a necessary reality.

<comment><USER18> At some point you just have to cave and build a porn site.

<comment><USER19> Waiting for the follow up article, "The day I accidentally built an open source developmennt platform."

"I made a great fast, free porn hosting site. But then these nerds showed up and started uploading their Git repos onto it."

<comment><USER20> "The day I realized my camgirl sex website was being used for business meetings"

</comment></comment></comment></comment><comment><USER21> We were running a privacy focussed Chat-App-Network dating platform in 2017 which was accelerated by Facebook[1].

i.e. A network between, Messenger<->Viber<->Telegram<->Line App.

By design no media sharing was allowed(to prevent pornography) and the user profile images were received from the platform itself. But we soon faced unique challenge of people from certain countries using their children picture as profile picture(often just the children), there were people with group photo as profile image and then there were people who using explicit images as profile pictures.

So we integrated Amazon Rekognition to identify children, group and explicit images. Those using explicit images were banned immediately and those with children/group photo image( _Face detection not Facial recognition_ ) were asked to change their profile image(Their profile was not shown to anyone until they changed their profile picture with just them). We were processing >200,000 profile images per month as people change their profile images often.

But, as we very well know Amazon Rekognition or for the fact any such ML solution is not 100% accurate, we faced issues with people with darker skin color(Amazon told me that they were working to fix the issue; exactly why this type of half baked tech shouldn't be used for things which can cause harm) and so we had to reduce the confidence levels to such an extent that anything resembling a child would be flagged by the system(False positives are better in this case than false negatives).

[1][https://hitstartup.com/about/#FindDate](https://hitstartup.com/about/#FindDate)

<comment><USER22> > privacy focused Chat-App-Network... accelerated by Facebook

Why would any company focusing on privacy partner with Facebook or Google? I would guess that some ardent supporters of such a product/company would be put off by such a partnership, no?

<comment><USER21> Good question.

> Chat-App-Network

Messenger had >1Billion users and so its users were 98% of our user base. We enabled them to communicate with users of other chat apps and vice versa. We didn't even use the 'Name' of the users.

I applied for their bootstrap phase under their FbStart program but they directly selected it for the Acceleration phase.

As for why I applied for Facebook if I care about Privacy?

I was a disabled, solopreneur from a village in India, without any kind of network strength competing with Valley behemoths and any kind of help is not just a force multiplier but life or death(But my product was selected meritoriously by FB). Facebook privacy issues(Cambridge Analytica) started only several months after I launched the product, so the image of Facebook was not like what's today. But it did bother me and just after a year of running the platform successfully, I had to close my startup due to my health issues[1]. I did not sell my platform to safe guard the privacy of the users.

[1][https://abishekmuthian.com/i-was-told-i-would-become- quadrip...](https://abishekmuthian.com/i-was-told-i-would-become- quadriplegic-68c0371e6f05/)

</comment></comment></comment><comment><USER23> A market platform I recently worked on allowed users (free sign up) to create multiple wishlists and then send those wishlists to arbitrary email addresses. The user could set a custom title, limited to 100 characters or so.

We soon discovered a similar problem to OPs - bot accounts (mostly @qq.com addresses) were registering by the hundreds per day to create wishlists and then send those wishlists to other @qq.com addresses. They were setting the titles to arbitrary code blocks.

I found it fascinating, if terribly inefficient. Some colleagues and I were speculating on the purpose, perhaps someone experimenting some kind of laundered botnet control path?

We tried all kinds of measures to prevent it but ultimately we blocked all @qq.com accounts and eventually disabled the wishlist feature altogether as it had such little real usage.

<comment><USER24> We allow users to sign up for a free trial for our product, you have to put in your name & email address. After the trial expires, we send an email that says "Hey So-and-so, your trial ran out, click here to give us money, etc." Some enterprising spammers filled in the name field with spam URLs and the email field with victims' email addresses, in order to spam them. So the victim would get "Hey hxxp://buyfreerolex.com/, your trial ran out..." spam emails, from our email server. Obviously we've fixed it since, but it's absolutely wild the length spammers will go to.

<comment><USER25> Perhaps a bug in some spamming script, mistaken your sign-up form for a blog comment form?

</comment></comment></comment><comment><USER26> We've had multiple spammer attacks over the years. Our platform allows users to create and publish their own content. Our primary target is education, teachers and students. But naturally it's being abused by spammers. It's been an interesting cat and mouse game to counter them.

\- One time, they used our platform to publish links to their streaming websites for the quarter finals of the 2018 Champions League. Suddenly we ended up being first result on Google for "arsenal v barcelona". It was fifteen minutes before the game so you can imagine that we got _a lot_ of traffic. On the one hand it was kind of flattering that the SEO ranking of our domain was so strong. On the other hand, it wasn't great nor beneficial for the platform to be abused like that. As a counter-measure, we decided to block indexing of project pages for 24 hours when they're first made public. The spammers never came back.

\- Another time, we got an email from AWS that our SES bounce rate was 15%, and it was rising fast. Being blocked from sending emails by AWS would have been a disaster. It turned out that our invitation system was abused. A creator of a project can invite an external person by email. That person receives an email saying "John Doe invites you to collaborate on 'A nice project about the 2018 Champions League'" with a link to the project. Replace "A nice project about the 2018 Champions League" by a Chinese ad and you've got yourself spammers who are sending thousands of emails a second to a random collection of email addresses. Naturally a lot of these bounce, which caused AWS to warn us. So we had to start verifying the MX validity of invited email addresses and throttle the system to a maximum of 100 emails in a window of 24 hours.

\- We still get a lot of spammers publishing obvious spammy projects. One thing that has helped is the Clearbit Risk API. You send them an email address and it comes back with an assessment of how spammy the address is. We use it for certain domains (protonmail.com, yandex.com,...) and it frequently flags someone as a spammer right after signup. They can still use the platform but can't make stuff public, completely defeating the purpose of them being spammy.

I'm sure they'll keep finding creative ways to get around the limitations we put in. The toughest is to find a way to counter them without it hampering the experience for all the other users.

<comment><USER8> Awesome tips there!

</comment></comment><comment><USER27> _I later discovered that Instagram banned all mylink.fyi links from the platform. A customer also confirmed to me via email that Snapchat started blocking links. Heh, I'm banned by Instagram and Snapchat!_ [...] _If you're interested in acquiring the domain name, and /or the app, let's talk._

That domain name must have a negative value now?

<comment><USER28> Thinking about it; maybe not.

If you're one of those loud folks who dislike instagram/facebook (like me) then this is a nice way to ensure your content and data does not end up on the platform.

Of course, they're only enforcing it themselves, so it's unlikely to be permanent. :(

</comment></comment><comment><USER29> Linktree, the service the author aimed to replicate had similar problems according to Wikipedia [1].

> In 2018, Instagram banned the site due to "spam," although it was lifted and > Instagram issued an apology.

> Rumors circulate that Instagram will issue another ban.

[1] [https://en.wikipedia.org/wiki/Linktree](https://en.wikipedia.org/wiki/Linktree)

<comment><USER30> I wonder if using Instagram Login has helped them filter out spam accounts.

</comment></comment><comment><USER19> Paying for bouncers is an understood part of the cost model for a nightclub. If you provide any sort of real or virtual venue that allows unvetted participants, you have to factor in the cost of dealing with bad actors. If you have a virtual venue, you have to factor in the cost of dealing with _automated_ bad actors.

It's just how human nature works. 90% of people are great, but 10% can do a _lot_ of damage.

<comment><USER31> great analogy

</comment></comment><comment><USER32> Here's an example of a similar problem - that I created for a website I help a friend with.

We had outbound referral links, basically to monitor the number of times that a visitor clicks out of the website. The URL pattern was something like: example.com/out.php?url=outbound.com

The out.php script would just simply (naively) redirect the user to the url specified. We never validated if the outbound link was to an authorized reference.

The result is the same. Eventually spammers figured out the above link and then just started posting their spam using the site's redirect script to any number of social media sites, embedded in email, etc.

What's interesting too is that we would see multiple redirects embedded into a single request. e.g. out.php?url=another.link.service/link=spammer.com

Obviously in hindsight this was stupid, but when we built it (some 10 years ago), the idea seemed pretty sound if not maybe a little naive. The solution would have been to only allow redirect links to authorized outbound sites, which works when those links are relatively static and not open ended.

</comment><comment><USER33> There is an easier way to accidentally build a porn website:

1) register domain

2) don't renew

Not completely unrelated either, since it seems like OP's domain is now bust too...

What is also interesting is that probably half of what FB or <insert nonexistant competitor> does is moderation of sorts. This is why FB is becoming a commerce/community page website and why they need Instagram for social media.

</comment><comment><USER34> I run a mediawiki site. I got to play the cat and mouse game as well. For a while I was getting hundreds of spam page creations per day despite implementing as many defenses as I could. I was at least once a day going through and deleting the spam posts using the Smite Spam plugin. It's finally calmed down and I get one or two posts maybe every couple of weeks. I think I may have finally been removed from the site list of whatever "packaged" software the spammers use.

<comment><USER35> With prebuilt software, a small custom change required for creating content is often times enough to deter mass automated spam. My go to for a number of the years was to add a form field with the label "Enter the word 'orange'". Trivial for a human but requires just a bit of customization for a bot, enough that most spammers won't bother.

<comment><USER34> I'm building a bespoke replacement for the wiki since all the pages share the same structure and the mediawiki solution isn't as user-friendly as I'd like.

Hopefully I won't do anything dumb like the naïve contact form I'd made that turned into a spam vector because I was putting unsanitized user input into mail headers.

</comment></comment></comment><comment> harry-wood I've come across these kinds of prototype link sharing sites in my battles with SEO spam. On the face of it SEO spam is simple: the bad guys bung a load of links into your wiki or blog comments in the hope of gaining google rankings for their "SEO clients", but... Increasingly they started bouncing links all over the place in complex spamdexing webs. Link sharing sites often get thrown in the mix, along with cross-linking other blogs/wikis where they've got their spam to stick. This all makes it easier to evade any filtering by a particular blog/wiki admin, but maybe also makes it harder for google to filter and down-rank the baddies, and finally depending on how complex a spamdexing web is, it offers protection to their clients because it ends up being impossible to see which end websites the spammer is actually aiming to promote (the links tucked away amidst the randomised cross-linked chaos)

But maybe that was a game of a few years ago, and now spam bots are mostly just trying to push porn on social media.

<comment><USER36> I'm facing the same issue with a URL analysis service I operate which lets you take a snapshot and screenshot of a website. I get countless submissions to other sites which allow user-generated content (Reddit, Medium, random support sites, everything that's "open") and all of these sites themselves host images and links to "Watch XX Soccer Game Live 2020 HD" etc., so all link-spam. I found my ways to battle these submissions and users, but obviously don't want to reveal them here.

The other thing is signup-spam. I'd say a full 50% of my signups are spam, and I do my best to remove those user accounts. What surprised me was that the spammers seem to be human, i.e. using a Gmail address (which requires verification), solving Captcha, entering form fields, clicking the email- verify link, etc. Just crazy. Again, the countermeasures are not something I would want to publicize...

</comment></comment><comment><USER37> I wonder how one can know the history of a domain name before buying it. Imagine making a new website and realizing that your domain name is banned from all social networks!

<comment><USER38> There are various online blacklist check tools. Examples:

email: [https://mxtoolbox.com/blacklists.aspx](https://mxtoolbox.com/blacklists.aspx)

DNS blacklists: [https://www.ultratools.com/tools/spamDBLookup](https://www.ultratools.com/tools/spamDBLookup)

</comment></comment><comment><USER39> > Other solutions include: requiring credit cards for trial periods, ban all > adult content from the platform… But they all require me to put extra effort > in the project. And I don't have time for that.

There is people who spend their entire life trying to build a working business, and those who just walk away from what would possibly be a pretty lucrative business because of lack of time.

Humans, strange and exciting beings, really.

</comment><comment><USER40> Link hiding tools are unfortunately a security threat due to all the bad actors in the world.

</comment><comment><USER41> Every time I see somebody identify moderation as censorship, I remember my experiences with public wikis, forums, etc. It's always spam and porn. They'll spin up more fake users than you'll ever have real users, every damned time. It's a vicious cycle, as real users won't stick around if you don't filter.

</comment><comment><USER42> I struggled with it myself with Twicsy, except Twicsy was just a window into Twitter and made it much easier to find the porn and (gag) child porn. I remember the first time I found a network of child porn, it made me sick to my stomach. Tooks me hours to get rid of it, report it to Twitter, and to the authorities. It was a problem for a long time, I felt like I was doing all of Twitter's dirty work that they wouldn't do themselves. I made tools for people to report it easily, and tools to eliminate it en masse. Twitter took way way way way way too long cleaning up their act in this respect. They also often just deleted tweets and not pictures, pictures could linger for months without being deleted from their content servers, and still appear in Google.

</comment><comment><USER43> IMO the better way to design a product like this to avoid abuse would be to simply force them to sign in using each platform they want to link to. At that point all you're building is a way for people to say, "These 5 social media accounts are all me".

You could allow them to select one of their accounts to source information and a photo for their combined profile. At that point you're not storing anything besides links to social media profile pages.

In effect you get to piggy-back on those sites' abuse mitigation strategies (though of course you're stuck with the lowest common denominator). Your biggest decision at that point is which social media platforms to allow onto your service.

</comment><comment><USER44> Was it legal "to take a closer look and see the links they are sharing"?

<comment><USER45> Why do you think it could be illegal?

The ToS also includes this:

> You represent and warrant that: […] the Content will not or could not be > reasonably considered to be obscene, inappropriate, defamatory, disparaging, > indecent, seditious, offensive, pornographic, threatening, abusive, liable > to incite racial hatred, discriminatory, blasphemous, in breach of > confidence or in breach of privacy; […]

For which they obviously need to look at the data.

<comment><USER46> That doesn't imply they are looking at the data during regular operation. That just means that the user is liable for breach of contract if they post noncompliant links. The first point in time where the admin really has to look at the data would be during the discovery phase of the corresponding lawsuit between operator and customer.

</comment></comment></comment><comment> boo-ga-ga Thinking about this when working on a social network (yes, I know) as a pet project at spare time, I've got a question: are there any tools for handling improper text/images automatically? I think there are some lists of "bad words", but not sure if they are available for most widely used languages. But are there libs/SDKs/online services that I can feed a picture and they will tag it as potentially improper, for example porn or some swastikas, so I can pre-moderate manually only such images? Looks like it could be a nice and useful service.

</comment><comment><USER47> Ow boy, my first real comment on HN, please be gentle!

Okay, so I have something related to this.

 _two paragraph back-story was cut_...

So I built SASRip[1], an Open Source website with an API that allows you to download audio or video from any web-page that is supported by youtube-dl (I use youtube-dl and ffmpeg to do muxing/transcoding). I also built a browser addon for it called Media Reaper[2] (chromium version available on SASRip's website[3]).

Now, I wanted to build a no BS, no tracking website, so all I have is internal logs, these logs keep incoming requests like so: Time, URL, ID string, success/fail, the ID is just to tell where the request came from, web site, API call or the browser addon, I keep no IP data or anything like that, and boy do people download the nasty stuff, there is all kinds of nasty stuff, taboo stuff, feet stuff and stuff I didn't even know existed.

Now I live in constant fear that someday, looking trough those logs I will find CP and I am not sure what I should do, I know implementing tracking methods goes against both my morals and the philosophy of the service, but at the same time I am not sure if I can keep on going, knowing I could do something about it but I am not.

Ultimately I think it is very likely that I will shut the service down if I find CP on it, with no way of tracking the person down, perhaps leave a message with why I shut down.

\</comment><comment></comment><comment></comment><comment></comment><comment></comment><comment></comment><comment>----

P.S. I make no money on this service, it's purely donation based.

P.P.S I know I can do muxing and transcoding via some really cool JS libraries, but I wanted to sharpen some of other skills with this project.

\</comment><comment></comment><comment></comment><comment></comment><comment></comment><comment></comment><comment>----

[1] - [https://sasrip.cf/](https://sasrip.cf/)

[2] - [https://addons.mozilla.org/en-US/firefox/addon/media- reaper/](https://addons.mozilla.org/en-US/firefox/addon/media-reaper/)

[3] - [https://sasrip.cf/Home/MediaReaper](https://sasrip.cf/Home/MediaReaper)

</comment><comment><USER48> I really like the design of the page - very clean and easy to understand the value prop. I could see this being useful for influencers and bloggers. Shame to hear about the mis-use :-(

</comment><comment><USER49> Everyone just want to be horny on main and I think the internet needs to get over / accept this so we can focus and making that profitable and safe.

</comment><comment><USER50> I recall in the early days of mobile apps downloading an ipad app which had this neat idea that kids could share their drawings, made in the app, with each other in a sort of random way. It did not take long for me to realize that meant seeing an endless stream of inappropriate, or sometimes potentially harmful content (e.g. from adults interested in exploiting children).

</comment><comment><USER51> I created a site intended for family photo/video sharing and it did not take long for people to start uploading penis pics. The weird thing is they don't even have a reason or recipient. They just want their penis out there on the internet in the hopes someone might stumble upon it.

</comment><comment><USER52> I wanted a long time ago to make a free speech forum and platform. As much as I believe it would be good to have place you can say what you want, the hassle of spam and plain nastiness is just what always stopped me from doing this.

</comment><comment><USER53> I'm building a platform that could be abused in similar ways. Does anyone have any suggested resources I could read/use to avoid this problem, preferably without employing captchas? Akismet might be helpful?

<comment><USER54> One thing to think of is not to be valuable to them.

So for instance, ALWAYS do HTML sanitization via whitelist; don't let anyone put any javascript or any weird CSS or HTML into your posted content that you don't allow there.

If you allow links, make sure they all have the "nofollow" tag, so that you can't be used for link farming. (Both because it helps spammers, and because if Google detects that your site is being used for link farming, your own sites bomb.)

Other tricks spammers use: Using a link for the username, since that is sometimes emailed or displayed even when moderated content is not.

The site I run is a special-purpose conference website for a relatively small community (usually 60-100 attendees), so manually moderating all content until a user is verified works pretty well. The first year we had a handful of spammers, but their content was all deleted by me before it was seen by anyone. (With the exception of the link for a username. Missed that trick.) The next year we didn't have any spam accounts at all.

No idea how well that will scale for your use case.

<comment><USER53> I will certainly be employing these methods, and doing manual verification at least initially- but if the project is successful, it will outrun my ability to manually verify everything.

Thanks.

</comment></comment></comment><comment><USER55> I don't understand what the problem is with using the service to provide links to porn, and also don't understand why Instagram and Snapchat would care about links to lists of links to porn?

<comment><USER56> I imagine it would have to do with 1) The number of minors on Instagram and Snapchat. and 2) The image that Instagram and Snapchat want for their platforms. They aren't looking to become tumblr in the eyes of the masses.

</comment></comment><comment><USER57> > I optimized it in a way I'll only pay hosting fees when the site is having a > lot of traffic. Like 1M+ visits per month.

I wonder what optimizations were done so you can only pay for 1M+ hits?

<comment><AUTHOR> Hey, author of the post here.

The whole app lives in Firebase. Once a user hits a profile page, a cloud function runs, get the data from the DB, constructs the page, and caches it at the CDN for 24h.

If a user add/delete something on their profile, the cache is removed. Otherwise, the content is served from cache only with no need for a lot of computation.

With this, you can still get your way through Firebase's generous free tier [https://firebase.google.com/pricing](https://firebase.google.com/pricing)

<comment><USER58> Firebase free tier is only 125k invocation per month. How are covering +1M invocations per month on free tier?

<comment><USER59> Caches hit on the CDN are not trigerring an invocation.

So it's not covering 1M+ invocations per month on the free tier.

</comment></comment></comment></comment><comment><USER60> For most bad actors, a small amount of work is all that's needed to block them from a new platform like this.

1\. Use email verification / captchas

2\. Block mailinator/throwaway account addresses

3\. Use something like Cloudflare/Akamai to protect against egregious bad actors

4\. Add some other level of social validation like a major OAuth provider

5\. Simple pattern matching - as the author noted, these are rarely sophisticated, and once you put even a small barrier up, they usually trickle down. You can even go further and just limit the features your product has specifically to hurt their use case, or you can actively shadow ban the users yourself, so they don't know their links aren't working.

</comment><comment><USER61> Firebase has a email verify feature You should use that so spam emails can be blocked from using your service.

</comment><comment><USER62> No offence to you but this is why I hate PH so much. Any product launched there goes down in <6 months.

</comment><comment><USER63> i think it's somewhat of a start for a business if you have the stomach for it. you just need to figure out how to make money off the freeriders and get around the social media censorship for the paid users.

</comment><comment><USER64> Slasdot's moderation system is brilliant in this regard.

<comment><USER65> Can you elaborate?

<comment><USER64> Oh, yes. It assigns a small number of 'moderation points' to random users, and a larger number to trusted users. Essentially their algo picks out random users to moderate just a little, which lets the diaspora bump up visibility of what they like. In addition to up and downvotes the mods label a post "+1 Informative", "+1 Funny", or "-1 Flamebait". Users can assign more visibility to something which has been voted Informative twice than once Informative and once Funny. There is no "-1 I disagree". The purpose of the votes are obvious.

There is meta-moderation on top of this which has users check the moderation of other users. I assume people who repeatedly abuse their privilege are given sub-naive priority for mod point assignment.

This scales with traffic and requires the minimum of admin oversight.

<comment><USER65> I'd forgotten about the random mod privileges, and meta-mod.

</comment></comment></comment></comment><comment><USER66> Pics or it didn't happen!

</comment><comment><USER67> I've never wanted the ability to "react" to hn comments as much as I want it for the comments on this post.

</comment><comment><USER68> For me the knowledge that bots rather don't execute and run Javascript helps to get rid of most bot comment/contact requests.

<comment><USER69> Some can, Selenium or other browser automation is sometimes used in bots. Really, any headless browser can be paired up with some automated QA toolkit and turned into a rather effective bot. All that has to happen is for the bot to load the page in headless mode, then issue the keystroke events to the specified elements.

<comment><USER68> From my experience most don't as it costs more money (ressources). For me a hidden input with some math solved by Javascript got rid of 10 spam contact requests per day to actually 0.

However of course, the larger a page gets the more dedicated the bots get.

But for the plain porn/russian spam it helped.

</comment></comment></comment><comment><USER70> Off topic, I wonder how people publicly admit they released a side project while working a full time job? AFAIK no company accepts this.

<comment><USER71> As long as I'm not releasing something that is a direct competitor for my job, it's all fine. Main thing I learned is that being open about it at work takes away the fear and worries.

<comment><USER72> As long as it's not very successful and not taking your time it's not an issue.

</comment></comment></comment><comment><USER73> One of the hidden consequences of the insane censorship that's being pushed by social media companies.

<comment><USER2> No, it's a consequence of not being on top of abuse on your platform. And because those big social media platforms are working really hard to avoid going down through no particular fault of their own they shut stuff like this down at the first sight of trouble.

HN does the same with spam, which is the only reason we can have this conversation in the first place. I take it that you do not consider that censorship?

<comment><USER73> If big platforms weren't so obsessed with trying to censor porn, there would be no need for people to hijack other platforms simply so they could create links to share porn. There's this bizarre obsession with "protecting" people from nudity (especially female nipples). Advertisers will stay away from your platform if there's nudity. Credit card companies will refuse to process your payments (or charge much, much steeper fees). And for what? So people can pretend that naked bodies don't exist? That sex isn't a thing? Seems odd to me. If I want to private message my friends dirty pictures, who is FB (or whatever platform) to tell me I can't?

As for spam, it's a shame that after 20+ years of the stuff, we still don't have a good answer for it. Some subset of people is spending money on whatever spammers are advertising, or they wouldn't be doing it.

<comment><USER74> Broadly I agree with you - especially regarding payment processors - but the problem is that this

> If I want to private message my friends dirty pictures, who is FB (or > whatever platform) to tell me I can't?

VERY quickly becomes "unsolicited dick pics." That "links to share porn" quickly becomes "links to share child porn", etc. You're not accounting for all the genuinely abusive users.

<comment><USER73> Sure. But the genuinely abusive users are always a minority. Although on the scale of FB and the likes, that could still be a large absolute number. Perhaps if we, as a society, stopped obsessing so much about nudity, unsollicited dick pics might become a thing of the past. One can dream, I guess.

</comment></comment></comment></comment></comment><comment><USER75> Why do social media sites treat "links to X" as directly posting X on their site? Surely the former is not against their terms of service? (Here am talking about legal adult content obviously)...

These overarching powers to censor anything for any reason is disturbing to say the least.

<comment><USER76> That's why we have Mastodon now, where everyone can choose what to censor themselves.

<comment><USER77> Which inevitably means an environment normal people hate - because they end up with some of the quirkier denizens of the internet on their global timelines if they use a public instance.

<comment><USER76> Not at all. "Normal" people simply choose "normal" instances.

<comment><USER78> Which ones are you talking about?

<comment><USER76> Depends on what is normal for you. See e.g. [https://mastodon.social/public](https://mastodon.social/public) or [https://floss.social/public](https://floss.social/public).

</comment></comment></comment></comment></comment></comment><comment><USER79> Guilt by association is illegal in most contexts, but apparently is fine for the censors at Instagram.

<comment><USER80> You're pointing out a problem there. The tools and processes around moderation (censorship might be too strong a word) are pretty lacking.

Let me consider with two cases.

For one the issue of a company making the rules, e.g. Facebook imposing prudery worldwide, even in places where things like a bare breast are not considered as such (yet?!). Why should someone half a world away physically and maybe even further morally have a say in what people can or cannot post in e.g. Europe?

Another is bans/ignores/mutes by users, I would say. The tools for these are absolutely lacking. Mutes or bans are usually permanent and there is no way to do anything about it. It's like solving every problem with a sledgehammer. (If I wanted to, I could go and mute or ban anyone I like to on e.g. Twitter and they would have _absolutely no means_ to explain themselves, appeal the decision or have any expectation that their sentence is going to be over one day.)

Maybe social media should be rather treated like public infrastructure and should have to provide services too all while leaving any moderation problems to other entities (and should just have to execute their decisions instead of both deciding and executing).

/rant</comment></comment>


Ask HN: How do you make sure js from a CDN or a CMS hasn't changed? - <AUTHOR> <comment><AUTHOR> After seeing the magecart attacks at BA and Newegg I decided to try and build a solution: [https://magehash.com](https://magehash.com), unsure if it's useful yet, what do you think?

I'm thinking about integrating it in existing CI/CD workflows, to avoid false positives too

</comment><comment><USER2> Not sure if this is what you're looking for, but subresource integrity perhaps?

[https://hacks.mozilla.org/2015/09/subresource-integrity- in-f...](https://hacks.mozilla.org/2015/09/subresource-integrity-in- firefox-43/)

<comment><AUTHOR> I did see subresource integrity, but I was also curious about last month's string of high profile magecart vulnerabilities, would subresource have saved them there, or is there more to it?

<comment><USER3> SRI won't protect you from:

* Someone injecting malicious JS code into your checkout page

* Non-static JS includes like Google Analytics

But it works well for static assets like jQuery or other static JS resources.

<comment><USER4> I was working with OP on a static asset integrity tool and testing I found out google analytics and facebook change their code multiple times a day!

<comment><USER3> It's been interesting working with teams that have well-defined release management workflows and continuous integration with snapshotted npm/mvn dependencies, but still allow a third party like GA to inject JS that skips the QA queue.

Likewise with CloudFlare: Allowing a third party to proxy all your traffic is a huge liability. CloudBleed should have been a wake-up call, but it doesn't seem to have had much effect.</comment></comment></comment></comment></comment>


iPad Available for Pre-Ordering - Online Orders Arrive Day of Release - <AUTHOR> http://store.apple.com/us/browse/home/shop_ipad/family/ipad?mco=OTY2ODA0NQ

<comment><AUTHOR> Just ordered two of of the 64GBs, with cases and docks- the trick's going to be having them get through customs without too much of a delay, since we need them in Argentina and Hungary.</comment>


Iris: Decentralized Cloud Messaging - <AUTHOR> http://iris.karalabe.com/

<comment><USER2> For anyone interested, I did a write up on Iris a few weeks ago, including how it stacks up to other golang messaging libraries. [http://www.bravenewgeek.com/iris-decentralized-cloud- messagi...](http://www.bravenewgeek.com/iris-decentralized-cloud-messaging/)

<comment><USER3> Thanks for sharing, very interesting article. Your previous post is great (and relevant) too: "Dissecting Message Queues".

[http://www.bravenewgeek.com/dissecting-message- queues/](http://www.bravenewgeek.com/dissecting-message-queues/)

</comment></comment><comment><USER4> Nice project, but it seems like it would need some (financial?) support:

> As of the current release, my focus will shift back to finalizing my > dissertation and inherently, my PhD. Since I can no longer rely on > university support for Iris, I am actively looking for an official backer > who would be interested in taking Iris to the next level and turning it into > an industrial strength project. If you are interested, or know of such a > person, please contact me at email@example.com.

<comment><USER5> Without wanting to sound too plain/blunt, as much as I like working on Iris and giving it to the community for free, I also need to make a living. Hence why I am looking for a backer, to be able to continue it.

On another note, the project is getting quite large with a lot of different things to work on, but I'm a single person with limited time. So while financial support is nice, I'm also open to possibilities of taking Iris under the umbrella of a corporation which would have the necessary expertise to really expand it.

</comment></comment><comment><USER6> Péter Szilágyi, creator of Iris, gave an excellent talk about it at FOSDEM this year: [https://archive.fosdem.org/2014/schedule/event/iris_decentra...](https://archive.fosdem.org/2014/schedule/event/iris_decentralized_messaging/)

</comment><comment><USER7> Github repos: [https://github.com/project-iris](https://github.com/project- iris)

</comment><comment><USER8> Just thought I'd be pedantic and point out that all the Go examples on that page aren't "package main", but are defining a main func; they won't compile to a binary.

<comment><USER5> Yes, the point with the package naming was to convey some additional information (i.e. erlclient, goserver, etc) to keep the snippet size down. I think they are understandable and workable as is, but nontheless you are perfectly right with your concern so I might update them at some point :)

</comment></comment><comment><USER9> Are there Windows/Mac clients for Iris?

<comment><USER5> Iris was written in Go (with a few platform speficit C snippets) and is available for Linux, OSX, Windows and 32bit/64bit/arm :)

You can download pre-built binaries from [http://iris.karalabe.com/downloads](http://iris.karalabe.com/downloads) (or of course you can compile from source [https://github.com/project- iris/iris](https://github.com/project-iris/iris))

</comment></comment><comment><USER10> OSS?

<comment><USER4> Yes, GPL: [https://github.com/project- iris/iris/blob/master/LICENSE.md](https://github.com/project- iris/iris/blob/master/LICENSE.md)

<comment><USER11> GPL seems like a sad choice for something that would need mobile apps, there have been problems with the App Store and GPL before for example.

<comment><USER5> Since Iris was/is my PhD work, and is currently not funded, I decided to release it under GPL to retain some control over what people end up doing with it (by no means do I want to prevent adoption, hence the dual licensing escape clause).

Nonetheless I'm open to discussing other OSS licenses such as BSD or Apache, but I think such issues are a bit further down the road :)</comment></comment></comment></comment>


Ask: Anyone feel like programming is Google Golf? - <AUTHOR> The process of coding feels like golf.
I google to find out how to do something and I come up with answers some fractional value. Each time I then tweak my google search and look for the answer again.
These iterations feel like swings on a golf course.
Is this healthy and productive? <comment><USER2> _Learning_ can definitely be like that, but you use Google less and less as you become familiar with programming and the particular stack you're using.

There are also some stacks that have better tooling and less magic, so you end up using the docs a lot less. A good IDE (with autocomplete and in-line docs) eliminates a lot of Google searches, for example.

What stack are you on and what is your experience level?

<comment><AUTHOR> I'm using python/notebooks. I'm pretty new to this.

There's little auto-complete and the online docs are terse with few or no examples.

People say python is easy, but it seems like there's many packages/ways to do the same thing, which makes learning confusing. It's especially confusing trying to optimize/pretty up code. I've hit plenty of gotchas.

<comment><USER2> Choosing between libraries is a common, not-totally-solved problem. Some good indicators that one library is better than another:

\- more recently updated

\- more total commits

\- more Github stars

\- more closed issues

\- fewer stale issues (issues opened a long time ago, but not fixed)

I don't know much about Notebooks. This may not help at all, but people seem absolutely crazy about PyCharm: [https://www.jetbrains.com/pycharm/](https://www.jetbrains.com/pycharm/)

</comment></comment></comment><comment><USER3> Google is great when it comes to find out details about special corners of your current technology. And there is nothing bad about that - in fact this is the new standard when it comes to solve special problems. You use collective knowledge, you also contribute to the collective data bank by helping others. I love it!

When it comes to basics - those you pick up quickly and never google for them again.</comment>


Fairness is a Perception - What Games Are - <AUTHOR> http://whatgamesare.com/2011/04/fairness-is-a-perception-game-psychology-1.html

<comment><USER2> Interesting read. In this context, it may have also been nice to mention the common gaming industry practice of using cheating as a compensation for poor AI.</comment>


Dear GitHub 2.0: open letter to GitHub from maintainers of open source projects - <AUTHOR> https://github.com/drop-ice/dear-github-2.0 <comment><USER2> So they do not have any complaint against Github, but want to engage in political virtue signaling over completely legal federal law enforcement procedures?

For some reason I doubt the group of people wrote similar letter when Obama had caged people. My bet is that they thought the pictures from Obama's cages were from Trump's cages.</comment>


Paul Erdős - <AUTHOR> http://en.wikipedia.org/wiki/Paul_Erd%C5%91s

<comment><USER2> My dad was a mathematician and has an Erdos number of 2. I figure that gives me an Erdos number of 3, I'll count my dad helping me with homework when I was a kid. Perhaps no one else will.</comment>