A convenient untruth: Array notation in C is a lie - <AUTHOR> https://blog.feabhas.com/2016/12/a-convenient-untruth/ <comment><USER2> The equivalent in C# always made more sense to me (not comparing memory or allocation model between the languages, but simply syntax in relation to a person reading it):

        int[] arr = new int[5]; // C#

        int arr[5]; // C

The fact that the brackets go on the datatype always made more sense to me, after all, I want to refer to memory of a certain cell size (as indicated by int). I realize that there is a lot of stuff going on when using new, but i believe even in C it should read, because you effectively change the datatype (to be of type pointer, rather than int).

        int[5] arr;

But then, I will now duck and get the hell out. This is the same reason why it feels wrong to write:

        int *arr;

You're not changing the identifier, you're trying to change the datatype.

In summary, I believe that the syntax to fiddling with pointers in C is very misleading, and this I fully agree with the article, but as many people are accustomed to this notation, I will now duck and get far away from the internet, in fear of all the hateful comments explaining to me how I am wrong, and apparently just don't understand the superior beauty of complicated C syntax. I will now go and check my garbage collected privilege.

<comment><USER3> > I will now duck and get far away from the internet, in fear of all the > hateful comments explaining to me how I am wrong, and apparently just don't > understand the superior beauty of complicated C syntax.

I am going to be that person :-)

One phrase – "declarations mirror use". In a declaration, you use the same set of operators around the declared object that you would use in a normal expression. All of these operators (asterisk, `[]` and `()`) have the exact same precedence and associativity as in the rest of the language. The type specifier(s) on the left is the final type of the expression that you get after applying all of the operators in the correct order as per the precedence/associativity rules.

So when you see:

        char *arr[X]

You identify the identifier first: `arr`. Then, because `[]` takes precedence over the asterisk, you say that `arr` is an array (of size X) of pointers to `char`. In other words, the expression `*arr[some_index]` is of type `char`.

<comment><USER4> I don't know if "declarations mirror use" gets you all the way there. You can use:

      *some_index[arr]

(though obviously not saying you _should_ ), but you can't declare:

      char *5[arr];

Obviously there's good reasons for that, but then you have "declarations mirror use, except when there's good reason not to", which basically brings you back to the original question.

<comment><USER5> > char *5[arr]

Isn't that exploiting a quirk of the operator's definition, rather than how the operator is intended to be used?

<comment><USER4> I assume you're right, though I would _love_ to see some of the original discussion around it. That said, while I don't think it's a catastrophic point against "declarations mirror use", I do think it's a strike against it.

Edit: I guess I'll also note here just for fun that while

      char [5]arr;

seems reasonable enough,

      char [4][5]arr1;
      char[5][4] arr2;

seems less so.

</comment></comment></comment></comment></comment><comment><USER6> This gets weird when you compare it to how structs work in C. Both are complex data types, so I sometimes forget that array semantics are totally different to struct/union semantics. Unlike arrays, in ANSI C, structs are real value types. You can pass them by-value to functions, return them by-value from functions and assign them by-value to variables of the same type. Also, structs never work like pointers to themselves. You have to dereference the pointer or use the -> syntactic sugar to access a member of a pointer to a struct.

Value type semantics enable some neat things, for example, you can zero all the members of a struct by assigning a compound literal to it. You can also make simple structs, like three uint8_ts for an RGB colour, and use them just like they were primitive types. In comparison, it seems almost archaic that you have to break out memset() and memcpy() to zero and move arrays.

<comment><USER7> Worth noting that you can always wrap an array in a structure and kick it around in your program happily, as if it's how the language should've been.

        struct { int a[5]; } arr5 = {{4, 3, 2}};

What's a bit weird though, is that while initialization like above is possible, assignment of a contsant is not as smooth in C, you will have to typedef your structure and use it in a typecast expression:

        typedef struct { int a[5]; } Array5;
        ...
        arr5 = (Array5){{4, 3, 2}};

<comment><USER8> You can actually drop the extra brackets (at least in C++, but IIRC also in C).

C++11 has array<T, size_t> which has proper value semantics. It is implemented exactly like your structure above, so no overhead, and also has a proper operator== and assignment via initializer list.

</comment></comment></comment><comment><USER9> I suppose this article is tongue-in-cheek but it doesn't really demonstrate _lies_ in the C language. It does point out some of the quirks of arrays in C but not calling them _real_ arrays is a matter of interpretation of terms. C defined what the term array meant for a lot of the languages that followed it. That today's languages have diverged from C's definition of array is not surprising.

<comment><USER10> From the OP:

> Of course, if you've read this far you'll (hopefully) realise that this post > should have been taken in jest. Arrays aren't really a lie (any more than > any of C's constructs are). Despite all the 'trickery' C's arrays work well > for many, many programming tasks. They are – as the title of this article > suggests – a very convenient set of untruths.

</comment></comment><comment><USER11> These facts is not a lies. They are inconviniences which one can see looking on C from perspective of higher level language. But if you learn how to program with assembler before studing C, than all these facts would look like obvious and convinient syntactic sugar.

Maybe in C++ these facts become inconvinient, because of C++ pretending to be higher level language than crossplatform assembler. But if it is a problem, it is not problem of C, it is problem of C++.

<comment><USER8> None of those 'lies' have anything to do with assembler. C deviated from regularity for the sake of convenience in some cases, and now we are stuck with those bad decisions forever.

<comment><USER11> > None of those 'lies' have anything to do with assembler.

They do. Lets take a look at the very first one. "Array name is just a pointer".

Assebler "array" is a name of a label. So its just named address in memory. Or we can alternatively say, that assembler array is constant pointer.

`sizeof' returns size of array in bytes? Hmm... maybe that because main C abstraction for memory is the assembler one: memory is a continuous sequence of bytes? `sizeof' meant to be used for functions like malloc or memcpy, not for operator `new'. When we use some dynamic memory allocation in assembler we get pointer to untyped memory chunk, compare with C:

void* malloc(size_t size);

If you wish I can show you the connections of other 'C lies' with assembler abstractions. I'm too lazy to write about all of them, but I could write about one more if you ask. Just pick one you like more.

> now we are stuck with those bad decisions forever

Yes, you are right. We stuck with that. And it is bad. But it doesn't make my point wrong. C is crossplatform assembler, and these decisions looks pretty good from perspective of assembler. They give to programmer low level control on generated machine code while keeping code portable, and its very useful in some cases. For example when you developing an OS kernel.

<comment><USER8> From an assembler point of view a structure of N elements of type T and an array of T[N] have exactly the same layout and are accessed in exactly the same way [1], but in C have wildly different semantics.

Sizeof behaves exactly the same way for structs and arrays, so it is one of the few things in C that treat arrays "correctly".

[1] although usually the offset is constant for a struct field access.

<comment><USER11> > but in C have wildly different semantics.

Can you show it with example? I'm not sure what you mean exactly.

Look:

        struct {
            int a, b, c;
        } foo;
        int *pfoo = (int*)&foo;
        printf("%d, %d, %d\n", pfoo[0], pfoo[1], pfoo[2]);

Code like this can have problems due to alignment, but at my opinion its not "wildly different semantics".

<comment><USER8> In addition to being UB, the example doesn't illustrate the issue: arrays in C are not first class as they can't be passed by value and can't be assigned. The decay-to-pointer thing that prevent this regularity has nothing to do with asm.

<comment><USER11> > In addition to being UB,

Yes, its UB. But I'm not persuade you to use this UB in real code: in real C code use offsetof from stddef.h. The only thing I want to say is: this code would work everywhere (if you pay attention to alignment). And its not coincidence by some chance: C mimics asm, because C needs to be 100% predictable to coder. Because asm use simpliest and the most obvious abstractions, with predictable runtime costs. C also goes this way. So its inevitable for my code to work. With some precautions, but it would work everywhere.

> the example doesn't illustrate the issue...

Yes, I suggested it, and I asked you for some illustrative example, because I can't understand your reasoning from "arrays are not first class" to "nothing to do with asm". I see it other way: "arrays are not first class" _is_ "asm mode".

<comment><USER8> > this code would work everywhere it does not, it will be miscompiled by > modern compilers.

> I asked you for some illustrative example,

      foo(T x) { x[0] = 1; }
      T x = {0};
      foo(x);
      assert(x[0] == 0);

The assertion fails for T = char[1], but succeed for T=std::array<char, 1>; You could construct a similar example in pure C.

std::array and C arrays compile down to the exact same code for access, have the exact same layout, etc, but C array are not copyable and assignable and implicitly convert to pointers without any good reason. This has nothing to do with assembler whatsoever.

<comment><USER11> >> this code would work everywhere

> it does not, it will be miscompiled by modern compilers.

Sorry, due to formatting bug I overlooked this.

Can you show me example of such a modern compiler? I suspect that you mean some C++ compiler, and they probably do, they would `miscompile' my example, because they treat struct in a matter similar to a class with vtable and all other stuff. But we are speaking about C, not C++. But if I'm mistaken with my suggestions, I'd like to know about modern compiler of C which prove me wrong. Such a proof can help me to understand modern C much better.

<comment><USER8> It is hard for compilers to miscompile this specific example as it doesn't do much at all.

The idea is that a write to pfoo[1] couldn't possibly alias with any write to foo, so the compiler should be free to reorder accesses if profitable. This is the same in C and C++ and has nothing go do with vtables.

For what is worth, I couldn't get gcc, clang and icc it to miscompile [¹] a slightly changed example, so either it is not actually UB or compilers still refrain to make this kind of optimization as it would break way too much code.

[¹] i.e. they elect to reload from the struct after writing to the array and vice versa even when it would be profitable not to do so.

</comment></comment></comment></comment></comment></comment></comment></comment></comment></comment><comment><USER12> I once proposed a backwards-compatible way out of this: "Safe Arrays for C"[1]. The fundamental problem with arrays in C is that compiler has no idea how big they are. My proposal was to replace

        int read(int fd, char buf[n], size_t n);

with a safe form

        int read(int n; int fd, char (&buf)[n], size_t n);

This says that the size of "buf" is "n", which comes in as another parameter. There are no array descriptors; the generated code for a call is the same. Thus, this is backwards-compatible, allowing mixing of "regular C" and "safe C" modules.

The programmer has to know how big the array is, after all. There must be some way to compute the array size from other variables or constants, or the program has no hope of working. All C needs is a way to allow the programmer to say that in the language. Then subscript checking is possible. Buffer overflows can be eliminated.

The required changes to C are minor. The big one is adding C++ references. Instead of passing a pointer to the first element of an array, you pass a reference to the array. Same object code, but now arrays are first-class objects.

This was discussed at length on the C standards digest back in 2012. After many revisions, the conclusion was that it was technically feasible, but too difficult politically.

[1] [http://www.animats.com/papers/languages/safearraysforc43.pdf](http://www.animats.com/papers/languages/safearraysforc43.pdf)

<comment><USER13> > The fundamental problem with arrays in C is that compiler has no idea how > big they are

Isn't that the compiler's choice, to not know how big they are? You could write a standards compliant implementation of C that did track how big arrays were if you wanted to couldn't you?

<comment><USER12> That's been done, with "fat pointers". GCC used to have an option for that, but it wasn't used much. The overhead is all at run time and is substantial.[1]

[1] [http://www.imperial.ac.uk/pls/portallive/docs/1/18619746.PDF](http://www.imperial.ac.uk/pls/portallive/docs/1/18619746.PDF)

</comment></comment></comment><comment><USER14> > _Why is this [array assignment] failing? Because the array's name is a lie! > Using a variable as an expression normally yields its value, but in the case > of arrays the array name yields a pointer (to the first element; which is at > least reasonable)_

Sorry, no; the assignment fails because an array isn't a modifiable lvalue. Array assignment simply isn't supported.

If array assignment were supported the array-to-pointer conversion ("decay") could be suppressed in that case to make it work. Just like it is suppressed when an array is the operand of sizeof of & (address-of).

Assignment of arrays is supported when they are struct/union members:

      struct wrapper {
        int a[5];
      } x = { 0 }, y = x;

We can return this from a function, too.

</comment><comment><USER15> Brings back fond memories of the first time I learned C, when I really had to dig into what the difference was between storage durations (auto/stack, dynamic/heap, static, thread local). It makes it increasingly important to think about when an object is going to be stored, and for how long. To me this is still a really useful concept that most high-level languages seem to have all disregarded in favor of extremely eager GC or refcounting, with the exception of Rust.

<comment><USER16>
        most high-level languages seem to have all disregarded in
        favor of extremely eager GC or refcounting, with the
        exception of Rust.

Because Rust does a good job of hiding the fact it isn't a high level language.

Sure you have ML type checking, pointer safety rules, multiple returns. But if you can see past the syntax sugar you realize it is just C (with guardrails).

<comment><USER17> High level abstraction or syntax sugar?

Terrorist or freedom fighter?

</comment></comment></comment><comment><USER18> Why did people think otherwise? Chapter 5 of _K &R_[1] is titled _Pointers and Arrays_ and basically explains that arrays and pointers are equivalent.

[1]: [https://www.amazon.com/Programming-Language-Brian-W- Kernigha...](https://www.amazon.com/Programming-Language-Brian-W- Kernighan/dp/0131103628/)

<comment><USER19> The point of the article is that sometimes they're _not_ equivalent, and that creates a lot of confusion. Please read it before commenting on it.

<comment><USER20> I thought the same things as GP. Anyone who has read K&R (as any C programmer ought to have) will know everything in this article.

<comment><USER19> I don't think that's true. While I don't have my copy of K&R handy, I don't recall it covering all the subtleties of how assignment and increment operators and sizeof will work differently for something declared as an array vs. something declared as a pointer. At least in the edition I've had, it just had the same "pointers and arrays are equivalent" which is misleading in exactly the way this article describes. Did that get added in your much-later edition?

</comment></comment></comment></comment><comment><USER21> It's not that convenient an untruth seeing as these are probably some of the first things you learn in C, and some of the first gotchas that'll getcha.

Having said that, the article was well written.

<comment><USER3> Some of the first things that people learn in C is the fallacy that "arrays and pointers are equivalent". An array is a series of contiguously laid-out objects that has a size known at compile time (except C99 VLAs). A pointer, on the other hand is merely a "single cell" that is supposed to contain an address and can be added/subtracted to, also dereferenced.

The truth is that array names decay to pointers except when the array is an operand to the `sizeof` or `&` operator.

<comment><USER22> Right, the fact that arrays aren't pointers is academic when they decay to pointers at the drop of a hat. In fact it's so easy to decay the array to a pointer that it is generally best to always treat it as a pointer lest you get burned later on during a code refactor. This mostly means never using sizeof() to get the size of an array.

<comment><USER3> Even if we simplify it this way, arrays are still different because they cannot be assigned to and their decayed pointer can never be NULL (they always have a backing storage provided by the compiler):

        int arr[5];
        int *ptr;

        // "arr" has a fixed backing storage of sizeof(int) * 5 bytes
        // "ptr" may point to anything or be NULL, depending on control flow

<comment><USER22> Best to check for NULL anyway though, because anything can happen once you let it decay to a pointer. Never assigning them is a good idea though, maybe it's best to think of them as constant pointers? But that's more confusing terminology for a C programmer, so maybe not. People get really wrapped around the axle when differentiating a constant pointer from a pointer to a constant.

</comment></comment></comment></comment></comment><comment><USER23> C now has static array indices. For example

void func(int arr[static 8]) {}

imposes a limit on the size of the array that can be passed as an argument (you cannot pass an array of 7 or fewer elements.)

I'd suggest that to the author, but given the article, I fear it may give him a heart attack.

<comment><USER24> I know they're called static array indices, and they're called that because of the use of the keyword `static`, but they don't have to be compile time constant at all (and checks aren't performed at compile time, IIRC). You can have the following:

        void foo(size_t len, int arr[static len]);

Which is really useful in asserting that you won't pass in the null pointer at runtime (so you can remove any `if (arr) {}` checks). Taken further, this exact method is what makes the restrict keyword usable in practice. One of the main problems of the restrict keyword is that you shouldn't be aliasing pointers. By ensuring that your passed-in array isn't actually a null pointer using the above syntax, you avoid one of the biggest problems of aliasing: passing in two null pointers. Consider:

        void foo1(size_t len1, restrict int* arr1, size_t len2, restrict int* arr2);

vs

        void foo2(size_t len1, restrict int arr1[static len1], size_t len2, restrict int arr2[static len2]);

The second is more verbose, but you have a stronger guarantee that this procedure won't be called with pointers aliased to NULL. The compiler can (and I believe in the case of GCC, will) take advantage of this.

<comment><USER25> > Taken further, this exact method is what makes the restrict keyword usable > in practice. One of the main problems of the restrict keyword is that you > shouldn't be aliasing pointers. [..] one of the biggest problems of > aliasing: passing in two null pointers

You shouldn't be dereferencing NULL pointers. Aliasing them is perfectly fine.

The non-aliasing requirements of restrict kick in only when you are actually accessing (and modifying!) the object referenced by an lvalue based on an expression of the restrict qualified pointer. So NULL pointers don't matter because first, they do not point to an object, and second, if you dereference them, you're already in UB land anyway. Correct code will not dereference NULL pointers, therefore the restrict qualification means absolutely nothing on code that opts to not try access anything through NULL pointers.

EDIT:

N1256 22.214.171.124p4 under Formal definition of restrict ( _emphasis_ mine):

> During each execution of B, let L be any lvalue that has &L based on P. _If > L is used to access the value of the object X that it designates, and X is > also modified_ (by any means), then the following requirements apply: T > shall not be const-qualified. Every other lvalue used to access the value of > X shall also have its address based on P. Every access that modifies X shall > be considered also to modify P, for the purposes of this subclause. If P is > assigned the value of a pointer expression E that is based on another > restricted pointer object P2, associated with block B2, then either the > execution of B2 shall begin before the execution of B, or the execution of > B2 shall end prior to the assignment. If these requirements are not met, > then the behavior is undefined.

</comment></comment></comment><comment><USER26> I don't know how this is a lie or untruth, even in jest. In a language that exposes memory management directly of course you can manually traverse an array.

<comment><USER27> It's just a different way of looking at C that might resonate with someone new to the language and the idea of exposed memory. There's no "lying" but by framing it like a story or an evil conspiracy it might make it interesting or fun enough to stick when a clinical description might not for many students.

</comment></comment><comment><USER28> C has no more real arrays than assembly: for the cpu, it's just differently indexed pointers in the end. But arrays in C have some notable differences from pointers in C however, please read a good detailed description here: [http://eli.thegreenplace.net/2009/10/21/are-pointers-and- arr...](http://eli.thegreenplace.net/2009/10/21/are-pointers-and-arrays- equivalent-in-c)

</comment><comment><USER29> Is this article a sign that C has fallen out of mainstream use?

<comment><USER30> What is "mainstream" these days?

<comment><USER31> React (a javascript library, sometimes referred to as reactJS or react.js) and more specifically its most popular module, Reagent, which is a full, lazily- loaded preemptive operating system that can run concurrent Java, Pythonjs, Rubyjs programs all from your browser while allowing cooperative suspend, load and save to network or local storage, intertab cooperative process management, etc.

Basically, if you're not working in an add-on to a framework library written in javascript running in a web browser, you might as well be using punch cards. /s

I made the part about Reagent up, but you know you believed it.

We're so far from the metal we might as well be sending a telegram with our requirements.

In the five seconds it takes this crap to load and show you a still loading page, your CPU cores have done 40,000,000,000 sixty-four bit operations.

<comment><USER32> You laugh, but Odoo* 's hand-rolled, Backbone.js-based frontend framework includes an interpreter for a subset of Python. They call it py.js. I'm not fucking with you.

[https://github.com/odoo/odoo/tree/10.0/addons/web/static/lib...](https://github.com/odoo/odoo/tree/10.0/addons/web/static/lib/py.js)

Just so that you can experience the full horror: Yes, the Python server ships XML templates with raw embedded Python code to the client. The client then parses the XML and interprets the Python using this py.js thing.

If the embedded Python needs to access the database (and it almost always does), the client makes calls to a JSONRPC interface on the server.

(If you ever think of using Odoo. Don't. Just... don't.)

*An open source ERP.

</comment></comment></comment></comment><comment><USER33> I'd be careful about assuming that C code run on a human interpreter behaves similarly to C code compiled by a modern compiler. For example, string literals probably don't actually have to exist in memory anywhere, but could arise implicitly from the control flow of your program. A compiler could probably turn:

        char *x = "abcdefghijklmnopqrstuvwxyz"
        printf("%s", x)

into something like:

        for (int x = 'a'; x <= 'z'; x++) {
          putc(x);
        }

Maybe when your program thinks it's accessing the 42nd element of that array, it's actually accessing some function of (the number of clock cycles in the CPU's counter, n unrelated code segments XOR'ing into a memory location, the executable's exact binary output) and the compiler has conspired to make these calculate to what that string's value would've been in an imaginary virtual machine to save 2 bytes(or because they're cached).

Sounds like a good DRM scheme actually.

And who says pointers are to RAM addresses? Maybe the compiler statically notices that the pointer's target stays strictly between 'a' and 'z', and decides to use a simple 26-value counter. Depending on how you debug a program compiled by a sufficiently smart compiler, pointers could point to RAM addresses only when you're looking at them.

That for loop you thought you wrote? Well, your program accesses different parts of the result at different times, so it scattered it all over your program so it's lazily computed. The loop counter or pointer never actually exists or takes on any value.

You can't be sure any of it exists unless you add logging or inspection. The whole program could be a lie, cleverly calculated to mimic the one you really intended.

<comment><USER34> > The whole program could be a lie, cleverly calculated to mimic the one you > really intended.

The standard has a similarly convoluted way of saying that, in a nutshell, C compilers are permitted all optimizations under the as-if rule. (§ 184.108.40.206)

<comment><USER3> The "canonical" mental memory model of C (globals in data/BSS, locals on the stack, memory is a big array, code and data are the only artifacts) may be utterly useless when reasoning about the performance of a program, but helps the programmer greatly when approaching a problem.

The language was designed with these things in mind, no matter how much more sophisticated compilers and hardware have become, and no matter how much language lawyer fetishists frown on you for saying "this is on the stack" instead of "this has automatic storage duration".

</comment></comment></comment><comment><USER35> > Why is this failing? Because the array's name is a lie! Using a variable as > an expression normally yields its value, but in the case of arrays the array > name yields a pointer (to the first element; which is at least reasonable)

Ahh, not quite. sizeof(array) was using the variable as an expression - not an evaluated expression, but an expression nonetheless - and it's clearly not giving us the same result as sizeof(array+0). In C++, you can even construct references, which can be abused in conjunction with templates to create a 'safe' array size check, which relies on array maintaining it's array typing:

      int (&r)[5] = array;

Now, arrays _are implicitly convert to_ pointers is you so much as sneeze in the same room as them, but there are instances (namely arrays of arrays and the like) where you can fuck up your pointer math if you assume that simply using the array name yields a pointer, or that the array 'is' a pointer - because _that_ is the lie! If I'm feeling particularly explicit, I'll write something like (assuming a and b are arrays, in C++ again):

      std::copy(a+0, a+N, b+0);

Where the +0s ensure I'm actually dealing with pointers. This avoids any compiler errors from having mixed types for 'a' (array) and 'a+N' (pointer) which, while rare (the former typically converts to a pointer at some point), has happened to me at least once.

The real reason "this" (array init and assignment) is failing is that C decided arrays weren't copyable and assignable like this. That's all. Really! Now, one can think of plenty of rationale that made sense at the time (memcpy is more explicit, simplifies the implementation to only implement copy/assignment for simpler types, etc.) but it ultimately boils down to the choice of the implementors.

</comment><comment><USER36> The thing to keep in mind is Never (Never) use array syntax in your function arguments. It implies something that you can't rely on. More on this: [https://lkml.org/lkml/2015/9/3/428](https://lkml.org/lkml/2015/9/3/428)

<comment><USER24> See [https://news.ycombinator.com/item?id=13237674](https://news.ycombinator.com/item?id=13237674) and my corresponding reply, where you _should_ use array syntax for function arguments, but you need to do it using the `static` index syntax.

</comment></comment><comment><USER37> I was lucky to learn C with pointers first, and then arrays. When you think about it as just chunks of memory, it all makes sense and is easier to reason about what the cpu will do. This is another example of a "simplifying abstraction" that is more misleading than simplifying.

</comment><comment><USER38>
      But this is exactly what the index operator is doing.  When you write (for example)
      arr[0]
      The compiler is re-writing your code as:
      *(arr + 0)

Since addition is commutative, you can also write arr[0] as 0[arr].

<comment><USER39> Yes, it's in the article.

</comment></comment><comment><USER40> These are no "lies", just misunderstanding on the part of those that believe the untruths. Those that have basic understanding of C know most of the things listed in the article.

</comment><comment><USER41> The mycodeschool channel on youtube has a playlist[1] that provides a great visual explanation of this information.

I found it really useful in getting my head around these concepts.

[1]: [https://www.youtube.com/playlist?list=PL2_aWCzGMAwLZp6LMUKI3...](https://www.youtube.com/playlist?list=PL2_aWCzGMAwLZp6LMUKI3cc7pgGsasm2_)

</comment><comment><USER42> Regarding #3, it's worth noting that even though the elements of the two- dimensional array form a contiguous block of integers, you cannot treat them as such [1].

[1]: [http://c-faq.com/aryptr/ary2dfunc2.html](http://c-faq.com/aryptr/ary2dfunc2.html)

</comment><comment><USER43> In the last example,

> char string[] = "Hello world";

I thought that gives out warning these days. Isn't the proper type of a string literal the following?

> const char string[] = "Hello world";

Therefore, you can't really modify individual characters there.

<comment><USER36> > Isn't the proper type of a string literal the following?

No, it's a const char pointer. Your declaration actually makes a copy of the "Hello world" string into a new char array, distinct from the string literal itself:

      [~]$ cat test.c
      #include <stdio.h>

      int main(int argc, char ** argv)
      {
          char a[] = "test2";
          printf("sizeof(a): %lu\n", sizeof(a));
          return 0;
      }
      [~]$ gcc -std=c99 -pedantic -Wall -o test test.c
      [~]$ ./test
      sizeof(a): 6
      [~]$

<comment><USER44> The type of a string literal is array of char, and like other arrays, they decay to pointers to the first element when used in expression context, with three exceptions: sizeof, taking the address with &, and when used as a string initializer. "test2" in your example is not a const char *, it's an initializer, since this is one of the exceptions to array-to-pointer decay.

[http://c-faq.com/aryptr/aryptrequiv.html](http://c-faq.com/aryptr/aryptrequiv.html) [http://c-faq.com/decl/strlitinit.html](http://c-faq.com/decl/strlitinit.html)

</comment></comment></comment><comment><USER45> This is covered in "Expert C Programming: Deep C Secrets"

[https://www.amazon.com/gp/product/0131774298](https://www.amazon.com/gp/product/0131774298)

</comment><comment><USER46> If you want Pascal, you know where to find it. C is C.

</comment><comment><USER47> So the only difference between an Array and an *int is how sizeof() behaves?

And how do I pass my Array to a function without losing sight of its size?

<comment><USER48> Short answer: For the user? yes. For the type system? no. To keep track of the length of the array, you can pass the number of elements as a second parameter to the function.

Long answer: For arrays with a declared length, the length is included in its type (188.8.131.52, page 42, [1]). Therefore, the type of "int a[5]" is "array of 5 integers". The type of "int*" is "pointer to integer". For arrays without a length, the type is considered 'incomplete' (220.127.116.11).

So the C typing system considers these 2 different types.

"Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue." (22.214.171.124.3)

sizeof is essentially an exception.

"The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer." (220.127.116.11.2)

And that's how sizeof is defined. Because it uses the type to compute the size, and the type of arrays include their length, and the type of arrays doesn't change in sizeof expressions, sizeof will return the total number of bytes of all the elements of the array.

[1] C11 standard (draft): [http://www.open- std.org/jtc1/sc22/wg14/www/docs/n1548.pdf](http://www.open- std.org/jtc1/sc22/wg14/www/docs/n1548.pdf)

</comment></comment><comment><USER49> This stuff is all taught in 1st year of C.S.

I hope that anyone who works with asm, C (and also C++) learned all this when he was still a kid

<comment><USER50> From my own experience and what I've seen from major US universities, this does not seem to be the case.

For intro (1st year-ish) CS, it looks like most places are teaching Python and C++, with some institutions (such as my own) using Java. An ACM article from 2014 actually has some numbers here. [0]

I graduated relatively recently with a bachelors degree, majoring in CS and Computer Engineering. I had only one course which actually used C, and that wasn't for my CS major. I've spent a fair amount of time since then doing low- level work on ARM micros, but definitely wasn't taught this in school.

[0] [http://cacm.acm.org/blogs/blog-cacm/176450-python-is-now- the...](http://cacm.acm.org/blogs/blog-cacm/176450-python-is-now-the-most- popular-introductory-teaching-language-at-top-u-s-universities/fulltext)

</comment></comment><comment><USER51> Well done, Grasshopper. You are now ready to begin the true journey of understanding.

</comment><comment><USER52> Don't even get me started on packing when you have arrays of structs...

</comment><comment><USER19> Worth noting: since everyone on HN is clearly an expert on C[1], we're just as clearly not the audience for this post. It's obviously written for people who haven't learned this yet, who might still be fooled by the superficial similarity of arrays in C to arrays elsewhere (or to what any rational non- lazy person not implementing their first compiler might expect). That doesn't make it a bad article, so stop being so gratuitously negative. It's actually a pretty good explanation, for somebody at that level, of how C arrays can trip you up. I might use it myself, as a reference for some of the people I mentor. Pedagogy matters.

[1] Or any other topic. Just ask any one of us. Apparently we all sprang fully formed from Athena's brow, already endowed with every bit of knowledge we'll ever need.</comment>


Why Twitter Is Still Dying - <AUTHOR> https://www.linkedin.com/pulse/10-reasons-why-twitter-still-dying-saleem-s-khatri <comment><USER2> A linkedIn post about Twitter dying? Uhh the irony.

<comment><AUTHOR> I can send you the Twitter link too :)

</comment></comment><comment><USER3> Because 140...</comment>


Silicon Roundabout Social Club - informal meetup + drinks - <AUTHOR> http://www.meetup.com/SiliconRoundaboutSocialClub/

<comment><USER2> Looks good. I'm glad to see folks/companies getting together themselves to do this stuff (especially since Drink Tank went dormant).

</comment><comment><USER3> How come this is a closed group?

<comment><AUTHOR> We've had a lot of people wanting to pitch services (accounting/marketing/social media advice) to us at other events, essentially fishing for work we want to try and filter that out. We feel that an open group of people working on startups is far more valuable than another networking group with people pitching for business.

</comment></comment><comment><USER4> A gathering of self-facilitating media nodes - totally mexico.</comment>


Buried Alive: Stories from Inside Solitary Confinement - <AUTHOR> http://www.gq.com/story/buried-alive-solitary-confinement <comment><USER2> > the federal government and about half of the states in the country began > restricting their use of solitary. These efforts gained bipartisan support > for economical, not compassionate, reasons

That is the most telling line about how the Government thinks. Do these people not think about how cruel solitary confinement is?

The best way to make people understand these cruel practices is to imagine themselves in solitary confinement. Would you want that? Obviously no, so why would you wish it or allow it on somebody else? Slightly tangential, but people who are openly racist or hate certain religions, ask them to imagine themselves as the people they hate.

The recent elections, and articles such as these are reminders that humanity is still very medieval. Sad!

<comment><USER3> Do you know how much people suffer if their house is broken into, if they are robbed at gunpoint, if they are raped, etc? Not just the direct harm, but the ongoing psychological harm?

<comment><USER4> Will the perpetrator's suffering make the victim un-robbed?

<comment><USER5> It might make some victims feel better, which can be considered a form of a moral compensation.

<comment><USER4> It might.... under what circumstances? some victims.... which ones? can be considered.... by who?

<comment><USER5> Well, I would've certainly felt better knowing that the guy who robbed me got punished.

<comment><USER4> Note that we're talking about a justice system that rehabilitates vs. one that punishes. Do you care which one happens to the perp, with the knowledge that they will be back in society at some point?

<comment><USER5> Why do we have to choose between rehabilitation and punishment? The goal should be "If you did the crime, you will be punished, but while you're being punished, we can help you become a better person".

</comment></comment></comment></comment></comment></comment></comment></comment><comment><USER6> On the intellectual level I have absolutely no reason to doubt the scientific evidence or the countless accounts of people who were subjected to solitary imprisonment and describe it as torture and worst thing that ever happened to them. I remember a documentary (probably NatGeo's "America's hardest prisons") episode where a violent and seemingly fearless thug was reduced to a crying baby by 2 weeks of solitary confinement. Yet, for some reason I am completely unable to empathize with it. And it's not for general lack of empathy either - I am quite horrified by pretty much everything else I learn about the experience of prisoners. But even after reading this article I feel like I'd choose solitary over sharing a cell with others. I suspect that points to some peculiarity/defect in my psyche. Does anyone else feel the same way?

<comment><USER7> I'm guessing in your case it's either a misunderstanding of what solitary would be like, or a misunderstanding of how bad it would be to share a cell with the average prisoner.

Solitary is not just getting the room to yourself. It's 24 hours a day of total isolation and really nothing at all to do. Your human contact would be limited to having guards slide food trays into your cell and once a day having a guard escort you to and from a slightly larger rec room (and you are alone there also). You would not have access to amenities that other prisoners have, like TV, computers, or possibly even books. I have seen descriptions of some solitary cells that are dark 24/7, and some that remain lit all day. Some people are in solitary for decades. I think staring at the wall all day and not having a meaningful conversation for years on end easily constitutes torture.

<comment><USER8> Really, how many people get to stay DECADES in prison? In Brazil the most horrible crimes have a de facto threshold of 6 years in jail.

<comment><USER9> Generally speaking, those who commit violent felonies are relatively likely to serve sentences like that. So rapists, murders and that sort of thing.

Part of the rationale is that it keeps people who willingly do such things away from society. So it's not simply punitive (and there's very little in the way of rehabilitation), it's more a matter of keeping them away from new victims. A point frequently lost in these conversations.

<comment><USER8> Yes, that's what I always say too. And it is a strong argument.

But still, in Brasil take 4 years and murderers 6 years in jail.

</comment></comment></comment></comment></comment><comment><USER10> _" There are still significant variations within Europe in the maximum permissible duration for solitary confinement allowed as punishment. In Belgium, eight days is the maximum permissible duration, whereas Finland allows 14 days; Poland, England, and Wales allow 28; France and Estonia allow 45; and Ireland allows up to 60. But overall, the dangers of solitary confinement have been recognized."_ [1]

[1] [http://www.brownpoliticalreview.org/2015/11/beyond- solitary-...](http://www.brownpoliticalreview.org/2015/11/beyond-solitary- confinement-lessons-from-european-prison-reform/)

<comment><USER11> Regarding Sweden, does Breivik's prison sentence and stay (solitary confinement) constitute torture? "1 March 2017, the Court of Appeals upheld part of Brevik`s appeal that Article 3 of the convention on human rights had been breached, that he has been subjected to degrading treatment but that his solitary confinement did not violate Breivik's rights" (source: wikipedia) Or what about the solitary confinement of Gottfrid Svartholm, co-founder of ThePirateBay? [https://www.vice.com/en_us/article/the-swedes-have-the- pirat...](https://www.vice.com/en_us/article/the-swedes-have-the-pirate-bays- co-founder-in-solitary-confinement)

Regarding The Netherlands, the killer of Theo Van Gogh, Mohammed B., is also held in solitary confinement. Do all of these constitute torture or an inhumane treatment?

<comment><USER12> Breivik's solitary confinement is also much, much different than the little rooms in the US. He has 3 rooms to move around in. He can cook for himself, play instruments, has exercise equipment. He has a computer, though I think his internet access is limited to nil. He has medical and mental health care at his disposal. He can have visitors, though they are through glass.

They made an exception to that glass before his mother died - he was allowed direct physical contact with his mother.

Not only that, but I'm pretty sure he can earn his way outside of solitary. And theoretically, he'll wind up getting released. I've heard it is possible to label him a threat to society, in which case he's more likely to wind up in a mental institution at that point - but it really depends on what he does in the next 10 years or so.

<comment><USER13> I strongly doubt that Breivik will ever be let out of solitary confinement unless the Norwegian high court finds that the Norwegian penal system violates Norwegian law. I doubt that even a conviction in the European court of human rights would cause Norwegian authorities to change the practice.

The official explanation for the solitary confinement is that other prisoners would kill him if they had access to him. The word punishment has never been been used to describe his extraordinary sentencing conditions. Actually, it's pretty ironic to have this discussion the same week that a convicted child sex offender was killed in a Norwegian prison after numerous warnings.

Breivik killed dozens of children of Arbeiderpartiet politicians, one of the biggest parties and the ruling party at the time. Norwegian society, great though it is in many ways, is still not capable of admitting that our relationship with the rule of law is somewhat selective.

Note: This is not in _any_ was a defence of Breivik's actions or ideology, rather a commentary on how legal principles are difficult for even a principled society to uphold in extreme cases. (It's also worth pointing out that Norway has been repeatedly criticised by the UN for our use of solitary confinement against arrestees that are not yet charged with a crime).

<comment><USER14> > Actually, it's pretty ironic to have this discussion the same week that a > convicted child sex offender was killed in a Norwegian prison after numerous > warnings.

That an inmate gets killed in a Norwegian prison is extremely rare. As you mention it did happened this week, but the last time before that was in 1982 (according to [http://frifagbevegelse.no/nffmagasinet/drapet-i-ringerike- fe...](http://frifagbevegelse.no/nffmagasinet/drapet-i-ringerike- fengsel-6.185.450223.66696d3d17) )

</comment></comment></comment></comment></comment><comment><USER15> It's insane that prisoners are treated poorly. It's also ridiculous that statistics like "rate of recidivism" do not seem to even consider what effect the incarceration itself had on the offender.

</comment><comment><USER16> Stories of torture at the hands of the state, in a domestic correctional context, are everywhere. This is a confirmed, observable phenomenon, not subject to much conjecture or doubt.

And it's time to _smash_ it. Thinking that some slow, incremental legislative progress is going to fix this problem is pulling a blanket of privilege over eyes and ears.

When Washington falls, which it will, we must immediately turn to our states and ensure - by whatever nonviolent means necessary - that they do not fill in the budget vacuum currently filled by a hodgepodge of federal grants and instead close prisons en masse.

In the mean time, we need to form pen-pal relationships with prisoners, shame people who decide to work in the prison industry (I know this sounds cruel, but it's _less_ cruel than refraining from doing so), and speak out in square company.

Enough is enough.

<comment><USER17> Your plan would make things unbelievably worse.

And I don't understand how you don't see this.

You reject a legislative process, and also want to shame people who work in prisons.

So basically you are blocking the only two possible paths to accomplish your goals: Either new laws, or reform from the inside.

How can you be so short sighted?

<comment><USER16> What makes you think that these tactics represent "the only two possible paths?"

</comment></comment></comment><comment><USER18> I had an experience with solitary confinement and I was tormented by it. The memories don't effect me much anymore and I now can write about it.

It resulted from a mental break down, causing an arrest which was not justified legally but the officer at the scene was annoyed by me. The charge were eventually dismissed but still haunts me like it would for any person.

I'm transgender which is related to the situation; at the time I had troubles communicating what I was going through and an attempt at failing 'x' which caused a wreck. Luckily nobody other than me was injured physically or mentally by the wreck.

I was told by other officers & firemen, "I would not be arrested as I had done nothing illegal" but the leading male officer decided to arrest me regardless and I ended up in the place for mentally ill criminals.

I either pissed off the officer by asking to speak to the female officer instead when questioned or he had something against me by how I looked.

I've never had a mental illness or have been diagnosed with any mental illness or even depression but I somehow ended up on haldol for schizophrenia which was shortly decided a day after the arrest without seeing any medical professional qualified for making such a diagnosis which needs 6 months observation anyway.

It all happened in Texas, almost ruined my life and has influenced other events in my life by negligence of others not understanding; leading to discrimination with other things by negligence.

I'm trying to pursue some justice for connections to what I've experienced resulting from negligence of others, so I can sleep better but let me now get on to the solitary confinement story.

The solitary confinement I was put in (while stripped of all clothes) had a button/speaker system to an supervising law enforcement person.

None of the law enforcement in charge of watching would make any indication to sympathy and would say things which would escalate any grief a person communicated even if it was a sane request.

Talking by button/speaker you would hear short responses made to sound annoyed and I was told to "get used to this as how am I going to survive when I go to prison" which to this day I cannot understand how messed up a person must be to feel the need to say something like that to a person in the situation I was in.

The confinement smelled similar to bleach or some really strong chemical odor, it would make my throat dry and people would be screaming for water. Other inmates in solitary confinement would scream they are Lucifer or that they are on true crime TV with nonsense stuff.

There were bars on the floor forming a 2 by 2 square for #1 or #2. Meals would consist of a paper bag containing an apple past it's prime, a milk carton, chips/pretzels and a small sandwich of tuna.

So you're stuck in this small space with a camera watching you and no clothes. Eventually I became anxious where I needed to know the time and ended up annoying the guard on duty by repetitively asking for it. I only had to stay in there for close to 2 days, until my lawyer managed to come and get me out of there. Bail was set at 50k which luckily I have parents that paid for it and it was returned to them after the dismissal.

Anyway I think it's reasonable for a person to prefer death when experiencing solitary confinement because I would have preferred death to that experience.

I really do enjoy life though but going through that was just wow.

<comment><USER12> I'm sorry you've had to endure this and am happy you are doing a bit better. Thank you very much for sharing the experience.

<comment><USER18> The sad thing was how so many inmates there were so kind and the stories they shared were so awful.

Jail is really just a cheap way to justify money not going to healthcare for improving mental health of people that need it.

US has to dry up all the tax money for war it seems. :/

Also thanks!

</comment></comment></comment><comment><USER19> When can we move to fixing people, not just punishment?

Our current system is selfish. The suffering is a show for everyone else.

It's supposed to suck. Nobody has a beef with that. But it doesn't have to destroy.

</comment><comment><USER20> Mindfield, the new series by vsauce, tackled this in its first episode, which recently became free to watch.

It was an interesting watch, although I couldn't really take the experiment seriously after the segment with the former inmate who had spent way more time confined in a cell with even less stimulation than the one Michael was about to enter.

Anyhow, prolonged isolation(>3 days, maybe less) and willful disruption of circadian rhythms should definitely be considered torture.

Also, doing this to people who will reenter society is just so shortsighted and dumb, regardless of the total lack of morality.

[https://www.youtube.com/watch?v=iqKdEhx- dD4](https://www.youtube.com/watch?v=iqKdEhx-dD4)

</comment><comment><USER21> Also see: This Blinding Absence of Light[1], true story of an Morrocan coup attempt gone wrong, and the 18 year punishment that ensued.

Disturbing and beautiful account; it's amazing what humans can endure, pushing toward the inner light amidst its complete absence.

[1] [https://en.wikipedia.org/wiki/This_Blinding_Absence_of_Light](https://en.wikipedia.org/wiki/This_Blinding_Absence_of_Light)</comment>


Police Find Paris Attackers Coordinated via Unencrypted SMS - <AUTHOR> https://www.techdirt.com/articles/20151118/08474732854/after-endless-demonization-encryption-police-find-paris-attackers-coordinated-via-unencrypted-sms.shtml <comment><USER2> not necessarily always a bad strategy[1].

OPSEC101: tor users stand out like a Mongolian transgender in the desert.

[1] [https://twitter.com/KristoferA/status/666980002114744320](https://twitter.com/KristoferA/status/666980002114744320)</comment>


CA DMV: Whoops, your "Real ID" isn't actually compliant with federal law - <AUTHOR> https://www.mercurynews.com/2018/12/25/feds-say-california-issued-real-ids-not-good-enough <comment><USER2> Adwalled.</comment>


How early 8-bit arcade machines differed in design from 8-bit home computers - <AUTHOR> https://floooh.github.io/2018/10/06/bombjack.html <comment><USER3> Great article. Wish he named some of those "obscure Eastern European computers". I know there are good communities around the Japanese microcomputers, the Sharp X1, the 8801, the 9801, MSX, MSX2, etc. [http://fullmotionvideo.free.fr/phpBB3/index.php?sid=88c8ee18...](http://fullmotionvideo.free.fr/phpBB3/index.php?sid=88c8ee189140bd7f358d8d66d722e936)

There's some excellent games buried away on them. This series of books in particular is amazing:

[https://www.amazon.com/Untold-History-Japanese-Game- Develope...](https://www.amazon.com/Untold-History-Japanese-Game- Developers/dp/0992926009)

Anyone know what the author is referring to?

<comment><USER4> You can check out some of the East German 8-bit computers and games for them on my tiny emulator page [https://floooh.github.io/tiny8bit/](https://floooh.github.io/tiny8bit/):

\- KC85/2 to /4 these were 'original' designs, even though some ideas (like the pixel/color attribute RAMs) were inspired by the ZX Spectrum. A slower Z80 CPU (1.75 MHz) but higher pixel and color resolution (e.g. a 320x256 display, compared to the Spectrum's 256x192)

\- Z1013 was a most minimalistic Z80 home computer sold as a assemble- yourself-kit (the only East German computer that was really available and affordable for 'normal people')

\- the Z9001 (aka KC85/1, aka KC87) was somewhere inbetween the Z1013 and KC85/2 models

\- the KC Compact was an East German Amstrad CPC clone, but without custom chip (the custom gate array was 'emulated' with standard chips)

The Soviet Union built a very interesting PDP-11 compatible 16 bit home computer ([https://en.wikipedia.org/wiki/Electronika_BK](https://en.wikipedia.org/wiki/Electronika_BK)), and impressive demos are still written for it: [https://www.youtube.com/watch?v=u_pdp1QSp70](https://www.youtube.com/watch?v=u_pdp1QSp70).

There were also surprising number of ZX Spectrum clones built in Eastern Europe because they didn't require custom chips, some of those designs also improved on the original Spectrum design (for instance a higher color resolution)

Bulgaria built an Apple II clone (and also built their own MOS 6502 and Motorola 6800 clone chips): [https://en.wikipedia.org/wiki/Pravetz_computers](https://en.wikipedia.org/wiki/Pravetz_computers)

...and there's probably at least a dozen more computer models I have never heard of :)

<comment><USER3> Ah, that's awesome! thanks!

</comment></comment></comment><comment><USER5> > And then for the rest of the year spend all my after-school time trying to > build rather poor impressions of those arcade games on my home computer, not > unlike a cargo-cult worshipper on a post-WWII pacific island trying to build > a US military radio station from wooden sticks.

Hahaha, this matches my own experience exactly :) Playing the likes of Dragon Ninja / Bad Dudes and then trying to reproduce them on the Spectrum. The few arcade games that did have Spectrum versions were disappointing - thinking of Green Beret for example.

Best memory might be finding a POKE for infinite lives in Commando, playing it for 3 days straight until level 70-something (the levels just looped every 5 or 10 stages, I think?), and ending up with a burned CRT. I'll never know whether the infinite lives POKE also made the game loop, or the developers never thought of including an ending in the Spectrum port.

<comment><USER6> What's wrong with the Spectrum's Green Beret? And R-Type Spectrum conversion was very good.

<comment><USER5> Nothing wrong with it, I spent endless hours playing it. But I saw the arcade version only afterwards, and I went "oooooh, colours!"

The "native" Spectrum games were better IMO. Sir Fred comes to mind. Pentagram, Gunfright, Knight's Lore, Abu Simbel Profanation. These worked with the limitations of the hardware (most notably the colour clash), not against it.

I mean, there even was a Spectrum version of Operation Wolf, and it was kind of atrocious (but still unbelievable that they made it work on such modest hardware!)

<comment><USER6> Funny you mentioned Operation Wolf, this is a game I really like and still play in the emulator from time to time.

<comment><USER5> Definitely not the same without the light gun :(

</comment></comment></comment></comment></comment><comment><USER7> He made me smile when he says: "there's very little information for Bomb Jack on the web"

hardware schematics, dumped rom, source of a working emulator... What do you want more ? :)

<comment><USER4> Compared to the wealth of information and research that's available for popular machines like the CPC, ZX or C64 that's indeed not much :) But true, since Bomb Jack is only built from well-known standard parts, the schematics is all that's needed (although there are some minor problems in it, like missing or faulty labels).

</comment></comment><comment><USER8> The piece is at least as much about how emulator design (can) differ between emulators for arcade machines and emulators for 8-bit home computers.

Home computer emulators need to be able to handle all the software you can throw at it, while an arcade emulator need to be able to handle on the single game ROM which ran on it. It doesn't need to handle subtle behavior of the hardware which never manifests in the game output.

(Of course, the situation is different for arcade machines which could take different ROMs.)

<comment><USER9> Not to mention that home computers had a different set of devices to handle as well - eg. cassette drives, floppy disks and later small hard disks - <USER2> with their own controllers which had to be interfaced with the system somehow (using isolated I/O on CPU's like the Z80, and memory-mapped I/O on others like the 68000).

</comment></comment><comment><USER10> I will forever wonder why 8-bit computers of the 80s didn't have more powerful video hardware. It's not that the technology wasn't available, since most arcade machines at the time had a lot more powerful graphics hardware than 8-bit home machines.

(I will also forever wonder why Sega's 16-bit console didn't have hardware sprite scaling and rotation, since that was the main attraction of Sega games at the time...)

I don't think it was only economic reasons, because I really doubt it would be that much more expensive to have a few tiled background layers, a few more sprites on the screen and a few more colors in a decent (i.e. not 16o pixels wide) resolution...

<comment><USER11> It would have been quite a lot more expensive, I assume? Roughly speaking, with 2MHz RAM, and assuming a setup where the CPU and the display system alternate (so 1,000,000 bytes/second bandwidth for each), you have a budget of 40 bytes for the visible part of the line, and large buffers are expensive, so it's just a question of how you spend it. Take the C64 as an example: you've got 320 px mono (40 bytes/line), 160 px 2bpp (40 bytes/line), or 2 40-byte character modes (40 bytes/line). I assume the fetches for the 8 sprites fit in the 24 bytes that are left, as each is 3 bytes wide.

Later machines had more bandwidth and more complicated memory systems, but the limitations are still the same. You have a fixed number of bytes you can fetch from RAM per second, the TV scans out at a certain rate, and that's going to limit what you can do.

<comment><USER12> That's assuming you're reading all the layers from the same ram. You could increase memory bandwidth by using separate chips for each layer.

<comment><USER13> Memory usually accounted for a majority of the cost in those days, so there's a lot to be said for a unified memory system in home computers. The standard memory architecture for home computers from 8-bits like C64 to 16-bits like Amiga was unified memory with half the memory cycles each going to the CPU and graphics, and PCM playback on later systems could conveniently steal a few graphics memory cycles during hblank. (The C64's VIC-II also stole CPU memory cycles every 8 scanlines and could be forced into stealing a lot more bandwidth with the 'badlines' technique.) ROM-based arcade machines and consoles generally had memory parallelism for their graphics systems. It puts heavy pressure on the chip pin-out and it requires you to physically allocate the RAM/ROM chips onto different buses. I guess theoretically you could put all the memory chips on multiple buses with a configurable arbiter in front of each so you could change the allocation per application, but the PCB for that would be massive and expensive. Instead there was usually a slow, awkward way to access memory from a different bus, e.g. the graphics bus could be accessed by the CPU only with DMA or a pair of memory-mapped addr/data registers with multi-cycle wait states. So, this kind of architecture isn't really suitable for a general-purpose home computer unless you can afford a large allowance of memory for each bus, but it did exist on high-end home computers like the X68000 that were less cost constrained. Also, Amiga did have the option for a kind of RAM expansion called Fast RAM which was only accessible to the CPU, unlike normal Chip RAM which was accessible on the standard chipset bus to the audio and graphics chips in addition to the CPU. Fast RAM didn't speed up the graphics system but it prevented the CPU from stalling when the other chips wanted to steal CPU memory cycles on the chipset bus (they always take precedence since they have hard real-time constraints).

</comment></comment></comment></comment><comment><USER14> > The entire remaining space on the mainboard is dedicated to the video > decoding hardware (besides a couple of RAM and ROM chips).

This wonderful post points out a fascinating cultural shift that I've never seen written up but is visible in the traces of various papers.

Although there was a Cambrian explosion of computer designs in the 1960s and 1970s they did follow a common evolutionary path, to whit: there really was a central processing unit, and around it fed various peripheral parts, primarily memory, I/O (channel controllers) and the like.

A lot of the vocabulary and assumptions of minicomputers and microprocessors came from this world, though the big difference in the late 60s was letting the CPU do some of the I/O (and one of the weird things about C, fundamentally a minicomputer language, was that it didn't have IO keywords or commands).

So when the Alto was designed one of the biggest weird things about it was not the bitmapped display itself but its support: the bus speed was only 3/2 the screen refresh rate! That blew people away (in fact if you wanted to do a lot of computation you'd end up blacking out most of the screen for a while).

==

The games developers went the other way: they started with hardcoded logic and only later were able to use MPUs. so to them they'd just accelerate part of the design with the computer. You can even see this as the domains started to merge; the early Atari computers like the 400 and 800 weren't only what we'd call today game consoles but had built-in sprite hardware that you could call from your programs.

</comment><comment><USER15> I've always been interested in the 128-bit Naomi hardware which Sega used around the time of the DreamCast. Cabinets were hooked together via fiber supposedly- this is how at Disney all the Daytona USA machines were connected together. There is a picture of two motherboards connected on this site: [http://sega-naomi.com/hardware.htm](http://sega-naomi.com/hardware.htm) and I wonder how different their protocol is from actual computers.

<comment><USER16> What is supposed about it? There are pictures right there. That hardware is mostly off the shelf components (SH-4 cpu, PowerVR Gpu, arm based sound dsp), the thing is basically just an "actual computer."

</comment></comment><comment><USER17> And a direct link to his WebAssembly version of the emulator: [https://floooh.github.io/tiny8bit/bombjack.html](https://floooh.github.io/tiny8bit/bombjack.html)

Took longer to boot then I expected, but after that played quickly.

<comment><USER18> Second stage music of Bombjack is clearly a rendition of Lady Madonna by The Beatles.

</comment></comment><comment><USER19> Ah, Bomb Jack. I loved playing this game on my Spectrum, had a MAME version in 2001 while studying my masters, and now it runs perfectly in a browser. Amazing. As is often the way with procrastination I became pretty skilled at my chosen distraction, memorising all the patterns with which to get a high score. Let's see how much I can remember!</comment>


A Junior Data Scientist Bookshelf (including Free Versions and HN Discussions) - <AUTHOR> http://ghyslain.me/bookshelf <comment><AUTHOR> Thanks everyone for the positives feedbacks. I did not have much time yet to write down full reviews of all the books, but I'll work on it - so far this page is more of a personal "bookmark". But to reply to @Nekopa and @carlsednaoui, here is a short review of the first books.

I have had a really pragmatic approach about reading them - only focusing first on parts relevant to my projects.

# An Introduction to Statistical Learning (ISL) / The Elements of Statistical Learning (ESL)

I focused on chapter 8-9 of ISL about Tree Based Methods and SVMs, two algorithms I used for my dissertation project. I found ISL to provide very clear explanations of the algorithms with just enough mathematical formalism.

I have a good math background so ESL was interesting to go through. But I am more of a practical person, and I found ISL to be more suited for me when it came down to working on my project and supporting my choices.

# Python Machine Learning

Really great hands-on book ! Sebastian Raschka manages well to guide you through all steps of a ML project data: pre-processing, feature engineering, model selection... - all the steps are defined and covered with practical examples.

I strongly recommend this book if you are just starting out with ML and feel "lost" about how to start your own project.

# Taming Text

I decided to use text data I had available for my dissertation project. However, half-way through the book I realized my dataset was to small to apply any of the techniques described there. I still like the practical approach and in the end the book gave me a good idea of what can be done with text.

# Advanced Analytics with Spark

I picked this book once I started working on the implementation of my project into production - we use Apache Spark (Scala) at work.

It provided me with a good introduction to Spark BUT it's based on the RDD-api and as stated on Spark website: "As of Spark 2.0, the RDD-based APIs in the spark.mllib package have entered maintenance mode. The primary Machine Learning API for Spark is now the DataFrame-based API in the spark.ml package."

I'm now mostly relying on Spark Doc / API, I'm not aware of any up-to-date books yet :)

</comment><comment><USER2> "R for Data Science" by Garrett Grolemund & Hadley Wickham was recently completed.

[http://r4ds.had.co.nz/](http://r4ds.had.co.nz/)

The ebook is free online, you can buy from Amazon & O'Reilly too.

</comment><comment><USER3> Nice list! I especially like that you added Resonate in there.

Could you add your personal reason for keeping these books on your shelf? That would make the page more interesting, and maybe help you out with your job search, as it will give an insight into your thought processes.

<comment><USER4> I don't get why Resonate is there. From the Amazon description I get that this book helps with creating meaningful presentations (?), yet it landed on the list among Data Science books and now I read positive comment about it. Can anyone elaborate why this book is worth any aspiring Data Scientist attention?

</comment></comment><comment><USER5> As a senior practitioner in the field, I feel a few years removed from my initial learning chunk. I really like this list as a throw back to see how the I would have done it today.

<comment><USER6> I'm a software engineer, about a year into a career shift into data science / machine learning. I'd second the majority of the books. Some were new to me. I did a lot of on the job learning, but Intro To Statistical Learning was my first formal treatment of much of the material outside 1:1 mentorship. I wrote my thoughts here [https://www.linkedin.com/pulse/introduction-statistical- lear...](https://www.linkedin.com/pulse/introduction-statistical-learning- book-luke-duncan)

I'm also halfway through the Deep Learning Book now. I'm really enjoying it. I got turned on to the book because there were a large number of people and reading groups at work (LinkedIn) that had organized around the book when it first came out in the html format a few months ago.

</comment></comment><comment><USER7> Still debating whether I should start with An Introduction to Statistical Learning (ISL) or Bishop's Pattern Recognition and Machine Learning (PRML). I really don't like using R (always a python person). Both have rave reviews on Amazon. Any thoughts?

</comment><comment><USER8> Solid start. I'd strongly suggest adding some Bayesian modeling books; start with Gelman.

If you look at the academic lineage of many of these authors, it will also help you understand how they get stuck into little biases.

</comment><comment><USER9> This is awesome, thanks for sharing. Ditto what Nekopa said, curious to hear why you like each of these resources.</comment>


GitHub SSH key audit - <AUTHOR>

Just got this email:

  A security vulnerability was recently discovered that made it possible
  for an attacker to add new SSH keys to arbitrary GitHub user accounts.
  This would have provided an attacker with clone/pull access to
  repositories with read permissions, and clone/pull/push access to
  repositories with write permissions. As of 5:53 PM UTC on Sunday,
  March 4th the vulnerability no longer exists.

  While no known malicious activity has been reported, we are taking
  additional precautions by forcing an audit of all existing SSH keys.

  # Required Action

  Since you have one or more SSH keys associated with your GitHub
  account you must visit https://github.com/settings/ssh/audit to
  approve each valid SSH key.

  Until you have approved your SSH keys, you will be unable to
  clone/pull/push your repositories over SSH.

  # Status

  We take security seriously and recognize this never should have
  happened. In addition to a full code audit, we have taken the
  following measures to enhance the security of your account:

  - We are forcing an audit of all existing SSH keys
  - Adding a new SSH key will now prompt for your password
  - We will now email you any time a new SSH key is added to your
    account
  - You now have access to a log of account changes in your Account
    Settings page
  Sincerely, The GitHub Team

  --- https://github.com email@example.com
 <comment><USER2> I wasn't sure how to verify that I recognized my keys at first. To save anyone else a bit of time googling, you want to run "ssh-keygen -lf your_key.pub" against your local copy of the key to generate the fingerprint and compare that to what GitHub shows you.

</comment><comment><USER3> It would be interesting to hear about what the vulnerability was. Was this yet another Rails-related security problem?

<comment><AUTHOR> Did you miss the posts from the last few days?

<https://gist.github.com/1978249></comment></comment>


'Firebase' Does for Apps What Dropbox Did for Docs - <AUTHOR> http://www.wired.com/wiredenterprise/2012/04/firebase/

<comment><USER2> I didn't dig deep in to the docs - just played with the demos - but if all data is exposed as 'just' a URL - what implications are there for security? Can someone mod the JS to grab someone else's data associated with my app? They probably have answers for this, but it wasn't apparent in the demos I looked at.

<comment><USER3> Hey. Yeah, we have an ACL system for specifying who can read/write data at each location. So you can lock down your application data to keep it secure. The API for this is still in flux though, so it's not documented. Coming soon though! :-)

<comment><USER4> How do you specify subjects of ACL — that is clients to have access granted to?

</comment></comment></comment><comment><USER5> I don't really get the benefits. You don't need servers, but you need to host the JS/html5 application somewhere, even if you don't need to configure the database server etc.

It is nice technology, but I don't really see if it is worth the price (vendor lock-in, technology lock-in, etc.)

<comment><USER6> Hosting can be handled much more efficiently / easily by someone designed just for content distribution, like a CDN. Our own site is 100% server from a CDN, which makes for very nice scaling characteristics. Also, it's free right now...

<comment><USER7> Or with a scheme like Chrome Apps, the browser could store the app locally. The app could work offline and only use the server to sync/collaborate.

</comment></comment></comment><comment><USER8> This could be incredibly useful for full stack developers that need to do mockups quickly, or have clients that are constantly calling them and asking questions like, "Can you build me something like $data_driven_webapp_dujour".

If your client just needs something small, you could host it on Firebase.

I also like the possibility of hosting an entire data driven application on Amazon S3 or Rackspace Cloud Files.

Looking forward to giving it a try.

</comment><comment><USER9> From the How It Works page: "Developers include a JavaScript library in their application which gives them access to a shared data structure (your Firebase). Any changes made to that data structure are automatically propagated to all other clients and to the Firebase servers....If a user modifies a piece of data a callback will be triggered on every client allowing it to respond to the change."

It sounds like every client gets a full copy of the entire database. You wouldn't exactly want to run reddit on this.

Or am I missing something?

</comment><comment><AUTHOR> The actual Firebase website is at <http://www.firebase.com> (there didn't seem to be a link in the article).

</comment><comment><USER10> How does this work with Meteor? They said it was complimentary. Is there going to be a Firebase Smart Package for Meteor?

      Michael Lehenbauer
      11:51 AM
      Potentially! Meteor supports a pluggable backend, so we're working on plugging Firebase in as the meteor backend. So you get the client-side help that meteor provides and the sophisticated, scalable backend of Firebase.

</comment><comment><USER11> Looks like something like parse.com for javascript folks...

</comment><comment><USER12> As a frontend guy this is HUGE. I can build apps in hours/days instead of taking weeks+ to learn node.js/ruby/etc.

</comment><comment><USER13> Sounds pretty cool and is in line with the trend of app logic moving to the front-end. I'm naturally reticent to put all my data eggs in one vendor's API basket, however (assuming this won't be open sourced). App Engine was supposed to scale too and those who bought into that ran into a lot of problems.

</comment><comment><USER7> I'd love to see the host-proof scheme that ZeroBin uses, so users can store sensitive data without having to trust Firebase. <http://news.ycombinator.com/item?id=3832269>

</comment><comment><USER14> So, I've wanted to do a number of things in the iOS / Android space that would require some real time communications and a server. In my quick skim I didn't see a mention of mobile APIs.

</comment><comment><USER15> This would seem to fit in well with all the Backbone.js tutorials showing up. Will have a play, it looks interesting for quick client apps or demos.

</comment><comment><USER16> Looks sick! Can't wait to see the demos!</comment>


I Quit YouTube [video] - <AUTHOR> https://youtube.com/watch?feature=youtu.be&v=Ii-EwaPfAC0 <comment><USER2> the video ends with "subscribe for more videos like this" hahahahahah

<comment><AUTHOR> The video is more about how he quit for a long time. And explaining why he quit. I have no idea why the title got changed.</comment></comment>


German FIS hands over data to NSA, except emails ending with .de - <AUTHOR> http://translate.google.com/translate?hl=en&ie=UTF8&prev=_t&sl=de&tl=en&u=http://www.zeit.de/politik/deutschland/2013-08/bnd-nsa-datenweitergabe-gesetz/komplettansicht

<comment><AUTHOR> Better translation of the important parts:

> "Before forwarding, personal data belonging to German citizens is removed in > a stepped process," said a spokesman of the BND.

> According to information from ZEIT ONLINE, they for instance remove all > e-mail addresses ending in .de and all phone numbers with the country code > 0049 [Germany]

<comment><USER2> > they for instance remove all e-mail addresses ending in .de

 _Sehr lustig!_ As if a yahoo.com or gmail.com couldn't possibly belong to a German user!

<comment><USER3> As if the NSA needs Germany to get at emails on yahoo and google!

<comment><USER2> Sure, that goes without saying though.

</comment></comment></comment></comment><comment><USER4> As long as Germany allows the construction of huge NSA surveillance centers within its borders, I will consider this country _NSAland_.</comment>


Is it a Good Idea to Write Tests for Legacy Code? - <AUTHOR> http://stephenhaunts.com/2013/11/19/is-it-a-good-idea-to-write-tests-for-legacy-code/

<comment><USER3> No. It's a _great_ idea.

The author mentions "characterization tests," which document what the code actually does as opposed to what it "should" do, or what the documentation says it does. These kinds of tests are _gold,_ especially if you go back through the bug tracker and create tests for the major bugs that have been fixed. Doing this gives you a good framework for constructing a regression test suite, which is what you really want when working with legacy code. It's like the opposite of TDD, because you want a green light to start, rather than RED -> GREEN -> REFACTOR.

OTOH, some code just isn't all that testable by its very nature. I'm thinking of stuff that requires expensive, custom hardware that would be difficult to mock out, for instance. Or GUI code. Or, if you're unlucky, like I was in a previous job... GUI code that requires specialized hardware.

Also keep in mind the amount of work it takes to make the code testable. You can easily end up breaking things just doing this if you're not careful or if the code is just not written with testability in mind.

<comment><USER4> Red -> Green -> Refactor is important because it indicates that the test genuinely behaves as required.

(RED shows you that the test fails when it should: there is good reason why this step should not normally be skipped; then GREEN shows you that the test passes when it should)

<comment><USER5> Parent was suggesting that an existing system's tests should already pass (green) before you monkey with it (red).

Although if you're fixing bugs, red-green-refactor can work well.

<comment><USER6> It's very possible that without a red test, your green test would be green with inputs for which you intended it to be red.

It's not enough to know that the test pass, you need to make sure the test would fail. Otherwise it's like having a cybernetic canary that doesn't need air to survive (great example, isn't it?).

<comment><USER7> If you were expecting the test to fail for some inputs you might as well just add another test case for that scenario.

</comment></comment></comment></comment></comment><comment><USER8> Often yes, although obviously your mileage may always vary, particularly by the importance of the project (Your old blog? No. A busy e-commerce site? Yes!)

I had an e-commerce system from a long time ago that was developed pre-TDD mania. My post-TDD approach was to develop a suite of acceptance tests for it testing a wide variety of typical use cases (add to cart, use discount codes, check out, tax treatments for various countries, etc.) and this has since saved my ass in a variety of ways without needing to go right down to the unit testing level.

(As an aside, if you're working on a project, need to move super fast and simply feel you haven't the time to do "proper" testing, be sure to do some high level acceptance tests at the least. They _will_ save you time because when the inevitable problems occur, you can just code the process to run automatically rather than be clicking 101 times in the 23rd hour of that 24 hour hackathon ;-))

<comment><USER9> I definitely concur with this. Acceptance tests are really powerful as they somewhat "imply" unit tests. Using your gut-feeling to write them makes the process less brute force than "proper unit testing"

<comment><USER7> As projects get older I find that the acceptance tests are the part that change the least. Lower level there's always a degree of churn as you refactor out duplication, consolidate interfaces etc. and the tests have to be rewritten as you go. A good solid set of acceptance tests means you can refactor away without having to worry about breaking the site.

</comment></comment></comment><comment><USER10> My approach to situations when there are no unit tests for existing legacy code is to start by writing a few coarse grained, or basic tests. Just enough to get initial coverage on critical functionality. Then you can add a few more tests over time.

What also works well is to give someone new to the project some initial tasks to write and fill in gaps for missing unit tests and coverage. Just enough to get them productive from the start, but don't task them with writing all the missing tests. I've found that for most developers that it helps them come up to speed on getting their environment configured, looking at the code, and introduces them to your build and version control process from the start.

Ultimately it's going to depend on the project and how hard it is to go back and add the tests.

</comment><comment><USER11> Honestly it depends entirely on the expected lifetime of the changed code and the complexity of the changes required.

If a particular application is just milking out another year or two until it's replaced, it's probably not worth erecting unit test scaffolding around the entire app. Sometimes it's safer to just change a couple constants and do a smoke test than to really get into it.

That said, my experience was that it was immeasurably helpful in breaking apart and working with older code - just taking a portion of my time devoted solely to writing unit tests helped my understanding beyond what you'd expect.

</comment><comment><USER12> This violates the law of headlines with questions in them: the answer is YES. In particular, it's possible to turn a legacy system into a non-legacy system this way.

<comment><USER13> That feels like a misuse of the word "legacy", but I know what you mean - <USER2> sense of "legacy" as "an unknown quantity of technical debt just landed on my desk."

<comment><USER12> Michael Feathers defines "legacy" as "something that doesn't have satisfactory tests". Dan North adds "does something useful".

Without the tests, refactoring is dangerous. This means that the systems are encouraged to remain static while the world around them changes. Systems that do the job, but for the wrong reasons, are legacy.

That last one was me. :)

</comment></comment></comment><comment><USER14> Well it depends on the code quality. If you have a system which is actually testable (with some mocking) then it is fine. You are in trouble however if that system is full of tight coupled components, static calls, inlined cache layers and so on. So you can't say "Yes" or "No" because it depends on the context.

</comment><comment><USER15> Take a look at Michael Feathers - Working Effectively With Legacy Code

<comment><USER16> 2nd the book recommendation.

It's relatively up to date in regards to technique and UML use but doesn't overpower the reader with too much.

Written to a decent level (it's not a Knuth book).

One main critique, it covers a lot of common issues but no complex corner cases, e.g. what to do about network architectures i.e. CORBA.

Should be required reading at the University level.

</comment></comment><comment><USER17> It could be quite a large task to unit test everything. Another option could be to unit test portions of the code that are impacted by the changes going forward. This can be handled by padding the development time for work done on the legacy codebase with some unit testing time.

</comment><comment><USER18> I've termed this type of development "Maintenance Driven Development" ([http://taylodl.wordpress.com/2012/07/21/maintenance- driven-d...](http://taylodl.wordpress.com/2012/07/21/maintenance-driven- development/))

Yes, it's a good idea to write unit tests for the existing code base, though be careful with setting unrealistic expectations with regards to test coverage. The goal is to better understand the existing code base and have tests around the most critical parts of functionality to provide evidence they haven't been negatively impacted by the code changes.

</comment><comment><USER19> Any code you modify now is much more likely to be modified in the future compared to any code you haven't yet touched. Test the code you touch.</comment>


Google's cloud-based machine learning tools - <AUTHOR> https://developers.google.com/prediction

<comment><USER2> The free pricing tier looks like a joke.

100 predictions a day isn't enough to test if it works. Somebody needs to make a much bigger commitment of their time to make a machine learning application that really works -- when you look at what's holding machine learning back it's not the algorithms or the hardware requirements, it's that people don't want to do the work of creating high quality training sets and validating them.

</comment><comment><USER3> There's a meetup at Google's Crittenden Campus (Mountain View) that'll be going over this next Wednesday: <http://www.meetup.com/sv- gtug/events/51114452/>

</comment><comment><USER4> At least, by making it a for-pay service, the likelihood of Google just shutting it down in the middle of the night is lessened (although still present). However, anyone competent enough to be passing data to an API can pass data to one of the many open source ML libraries that are available for many languages. I don't see the point.

<comment><USER5> Here is the 'point':

* Training models can be rather computationally expensive. Especially if your business requires training new models very often, this can be prohibitively expensive to do in ec2, whereas the prediction API solves that for you.

* Just hooking up to an open source ML library isn't the whole story. You still need to do backtesting on different algorithms and do the parameter tuning, aka you need some machine learning know-how. The Prediction API does all this for you automatically and probably uses a much larger set of algorithms than you would bother to test yourself.

</comment></comment><comment><USER6> It's great to see these tools available on a cloud computing basis. Just make sure you read the ToS:

1.2. From Customer to Google. By submitting, posting or displaying any Customer Data on or through the Service, Customer gives Google a worldwide, non-sublicensable, non-transferable, non-exclusive, terminable, limited license to reproduce, adapt, modify, translate, publish, publicly perform, publicly display and distribute any Customer Data for the sole purpose of enabling Google to provide Customer with the Service in accordance with the Agreement.

<comment><USER7> Isn't that the standard lawyerspeak to actually run the service? If I understood correctly, when reading those you just need to check that it is limited to the service provided ("for the sole purpose of enabling Google to provide Customer with the Service").

I've found the following (it's about photographs and social networks) quite helpful in explaining the issues: [http://www.readwriteweb.com/archives/getty_images_says_googl...](http://www.readwriteweb.com/archives/getty_images_says_google_plus_terms_of_service_is_ok.php)

</comment></comment><comment><USER8> Incidentally, here is an article I wrote today introducing three new machine learning tools being launched by startups:

[http://www.readwriteweb.com/hack/2012/02/three-new-tools- bri...](http://www.readwriteweb.com/hack/2012/02/three-new-tools-bring- machine.php)

Discuss: <http://news.ycombinator.com/item?id=3640954>

</comment><comment><USER9> Is it only me, or does anyone else think that the 40k predictions per day limit is a little too low for some?

<comment><USER10> The limit is actually 60k. And you can probably raise that if you talk to them, as they ask you to.

</comment></comment><comment><USER11> Lol. What a joke. Another BU that needs to be shut down.</comment>