text:
8-bit Chess Pixel Counting
Goal
You're playing a computerised chess game.  The display is in black and white only and the pixels are chunky.  White pixels use a lot power compared to black pixels and you're concerned about your carbon footprint.
Given a square and a piece in chess notation, return the number of white pixels displayed in the square.
The solution may be in the form of a function or a complete program.
Input
A 4-character string defining:

One of wb for a white or black piece. (Not part of normal Chess notation, but required for this puzzle.)
One of KQBNRP for a King, Queen, Bishop, kNight, Rook or Pawn.
One of abcdefgh for the piece's file (column).
One of 12345678 for the piece's rank (row).

Output
The number of white pixels used to draw the chess piece and the underlying square.
Requirements

Chess squares are 8x8 pixels and are either all white or all black.
a1 is a black square.
White chess pieces are drawn as white with a black outline.  Black pieces are black with a white outline.  All pieces have transparent pixels which show the underlying square.
Input is case-sensitive.
Assume the input is valid.

The chess pieces have sprites as follows.
. is the piece's colour.
# is the inverse of the piece's colour.
/ is the underlying square's colour.
King        Queen       Bishop
////////    ////////    ////////
///#.#//    /#.#.#.#    ///#.#//
//#...#/    //#...#/    //##..#/
///#.#//    ///###//    //#.#.#/
///###//    //#...#/    ///###//
//#...#/    //#...#/    //#...#/
//#...#/    //#...#/    //#...#/
//#.#.#/    //#.#.#/    //#.#.#/

kNight      Rook        Pawn
////////    ////////    ////////
////////    /#.#.#.#    ////////
//#..#//    /#.....#    ////////
/#....#/    /##...##    ///#.#//
///#..#/    //#...#/    //#...#/
//#..#//    //#...#/    ///#.#//
//#...#/    //#...#/    //#...#/
//#...#/    //#...#/    //#...#/

The number of pixels in the piece's colour, piece's outline and underlying square for each piece is:
Piece    Fill  Outline  Square
==============================
King     13    16       35
Queen    17    18       29
Bishop   13    18       33
Knight   16    12       36
Rook     23    18       23
Pawn     11    10       43

Test Cases
Input  Output
wRa1   23
bRa1   18
wPc2   54
bKg8   51

Scoring
The shortest code in bytes by Christmas Day gets a little something extra in their stocking.

Pyth, 54 53 bytes
The code contains unprintable characters, so here is a reversible xxd hexdump:
0000000: 732a 562b 5f57 2543 687a 322c 3031 2573  s*V+_W%Chz2,01%s
0000010: 434d 7474 7a32 4063 434d 2e22 0a2b 011e  CMttz2@cCM.".+..
0000020: d699 71d0 c6dc 3db8 eeae 2233 252a 4368  ..q...=..."3%*Ch
0000030: 747a 5433 31                             tzT31

Alternatively, here's a copy-paste friendly version, which you can also try online or use the test suite:
s*V+_W%Chz2,01%sCMttz2@cCM."\n+\x01\x1e\xd6\x99q\xd0\xc6\xdc=\xb8\xee\xae"3%*ChtzT31

C#6, 107 bytes
Here's my own answer.  I don't expect any points being the one who posed the challenge.
I have taken some inspiration from user81655's answer.
long P(string a)=>(a[0]>99?12201284685:11042628752)+(a[2]+a[3])%2*46566348643>>"KQBNRP".IndexOf(a[1])*6&63;

The pixel counts are encoded in 6-bit blocks.  The outline or fill is added to the square (if it's white).  Finally, the 6-bit block for the appropriate piece is extracted.
Thankfully, operation precedence worked heavily in my favor.

JavaScript (ES6), 106
As an anonymous function.
x=>(o=+'137999'[p='PNKBQR'.search(x[1])],f=+'262149'[p]+p,(parseInt(x[2]+x[3],19)%2?9:55-f-o)+(x>'w'?f:o))

By now, I'm following the simplest way of find the answer with a calculation - this could be not the best way.
Over a black square, the answer is the size of fill for white pieces and the size of outline for black pieces. Over a white square, you need to add the free space. See the table below (inside the snippet)
I keep the size of fill and outline for each piece, the free space inside the square can be found subtracting from 64. To save space, the outline in stored as a single digit afer subtracing 9. The fill is trickier as the range is wider, check the code (that's way the pieces are sorted by occupied space)
Test snippet:

F=x=>(
  o=+'137999'[p='PNKBQR'.search(x[1])], // get outline - 9
  f=+'262149'[p]+p, // get fill -9
  (
    parseInt(x[2]+x[3],19) // parse with an odd base the differentiate between odd and even rows
    %2?9:55-f-o // black square if odd,, white if even so calc free space
  ) +(x>'w'?f:o) // add fill or outline based on piece color
)

// Test suite

console.log=x=>O.innerHTML+=x+'\n'

for(i=0; z='PNKBQR'[i]; i++)
{
  o = '';
  t = 'w'+z+'c2'; // white piece, white square
  o += t+' '+F(t)+', '
  t = 'b'+z+'c2'; // black piece, white square
  o += t+' '+F(t)+', '
  t = 'w'+z+'a1'; // white piece, black square
  o += t+' '+F(t)+', '
  t = 'b'+z+'a1'; // black piece, black square
  o += t+' '+F(t)
  console.log(o);
}

Piece    Fill  Outline  Free  w/w b/w w/b b/b
=============================================
Pawn     11    10       43     54  53  11  10
Knight   16    12       36     52  48  16  12
King     13    16       35     48  51  13  16
Bishop   13    18       33     46  51  13  18
Queen    17    18       29     46  47  17  18
Rook     23    18       23     46  41  23  18

JavaScript (ES6), 135 112 bytes
s=>(c={K:`\u000a\u0010\u0023`,Q:`\u0011\u0012\u001d`,B:`\u000a\u0012\u0021`,N:`\u0010\u000c\u0024`,R:`\u0017\u0012\u0017`,P:`\u000b\u000a\u002b`}[s[1]])[f="charCodeAt"](s<"w")+((s[f](2)-s[3])%2&&c[f](2))

Every \u00xx should be a single one-byte character. They are represented here as codes because Stack Exchange automatically removes unreadable characters from posts.
Explanation
s=>

  // c = string of three (mostly unreadable) characters, the ASCII code of each character
  //     represents the number of pixels in the fill, outline and square respectively
  (c={
    K:`\u000a\u0010\u0023`,
    Q:`\u0011\u0012\u001d`,
    B:`\u000a\u0012\u0021`,
    N:`\u0010\u000c\u0024`,
    R:`\u0017\u0012\u0017`,
    P:`\u000b\u000a\u002b`
  }[s[1]])

  [f="charCodeAt"](s<"w") // if piece is black add outline pixels, else add fill pixels
  +((s[f](2)-s[3])%2      // this returns 1 if the square is white or 0 if black
    &&c[f](2))            // if the square is white add the square's pixels

Test

var solution = s=>(c={K:`\u000a\u0010\u0023`,Q:`\u0011\u0012\u001d`,B:`\u000a\u0012\u0021`,N:`\u0010\u000c\u0024`,R:`\u0017\u0012\u0017`,P:`\u000b\u000a\u002b`}[s[1]])[f="charCodeAt"](s<"w")+((s[f](2)-s[3])%2&&c[f](2))
<input type="text" id="input" value="bKg8" />
<button onclick="result.textContent=solution(input.value)">Go</button>

JavaScript (Node.js), 84 bytes
s=>[a=~"0628"[[C,P,F,R]=Buffer(s),i=P%11%7],b=-"63682"[i]||4][C&1]+(F+R&1?45-a-b:19)

Try it online!
How?
The color, the piece, the file and the rank characters are turned into ASCII codes which are saved into \$C\$, \$P\$, \$F\$ and \$R\$ respectively.
We compute the piece index \$i=(P \bmod 11)\bmod 7\$:
 char. | code | mod 11 | mod 7
-------+------+--------+-------
  'B'  |  66  |    0   |   0        Reordered by index:
  'K'  |  75  |    9   |   2
  'N'  |  78  |    1   |   1         0 | 1 | 2 | 3 | 4 | 5
  'P'  |  80  |    3   |   3        ---+---+---+---+---+---
  'Q'  |  81  |    4   |   4         B | N | K | P | Q | R
  'R'  |  82  |    5   |   5

We compute \$a\$, which is the number of outline squares for the piece, minus \$19\$:
a = ~"0628"[i]

We compute \$b\$, which is the number of filled squares for the piece, minus \$19\$:
b = -"63682"[i] || 4

We use C & 1 to figure out the color of the piece and F + R & 1 to figure out the color of the square.
The final result is:
[a, b][C & 1]    // use outline squares if the piece is black
+                // or filled squares if the piece is white
(                //
  F + R & 1 ?    // if the square is white:
    45 - a - b   //   add 19 + (64 - ((a + 19) + (b + 19)))
                 //   = 45 - a - b
  :              // else:
    19           //   just add 19
)                //

Lua, 158 155 Bytes
c,p,l,n=(...):byte(1,4)m="KQBNRP"d={}d[1]={13,17,13,16,23,11}d[0]={16,18,18,12,18,10}p=m:find(string.char(p))print(d[c%2][p]+(l+n)%2*(64-d[0][p]-d[1][p]))

Could probably reduce the byte count by encoding the data, but I kinda like the current table method.
Bases color of the square on the ASCII value of 'w' or 'b' taking advantage of the fact that one is even and one is odd. Assigns integer value of the piece based on the position of the piece's symbol in the m string variable. Whether a square is dark or light is handled by (l+n)%2 taking advantage of ASCII value again.
Ungolfed
c,p,l,n=(...):byte(1,4)   --stores input of all characters into variables
m="KQBNRP"                --piece encoded string
d={}                      --data table
d[1]={13,17,13,16,23,11}  --fill
d[0]={16,18,18,12,18,10}  --outline
p=m:find(string.char(p))  --position in string for position in tables
print(d[c%2][p] +         --takes data element from corresponding table according to color of piece and type of piece
     (l+n)%2  *           --is square black or white? 0 if back, 1 if white
     (64-d[0][p]-d[1][p]) --if white, pixels not used by piece would be area (64) minus pixels used by piece, or corresponding data in the tables
     )

-3 Bytes by removing c=c%2 before the print and using d[c%2][p] instead of d[c][p].

05AB1E, 41 bytes
Ç`+É•wH˜OÝ•44в*s11%©è•2ĀpakΩÕðβ•₂в2ä+sè®è

Try it online or verify all test cases.
Explanation:
Ç                          # Convert the (implicit) input to a list of codepoint integers
 `                         # Pop and push the four integers separated to the stack
  +                        # Add the top two together (column+row)
   É                       # Check if this is odd (1 if odd/white; 0 if even/black)
    •wH˜OÝ•                # Push compressed integer 245530244740
     44в                   # Convert it to base-44 as list: [33,36,35,43,29,23,0]
        *                  # Multiply each value by the odd-check
         s                 # Swap so the piece is at the top of the stack
          11%              # Modulo-11 on that integer
             ©             # Store it in variable `®` (without popping)
              è            # Index (0-based modulair) it into the list
               •2ĀpakΩÕðβ• # Push compressed integer 45866137874521319810
                ₂в         # Convert it to base-26 as list:
                           #  [18,12,16,10,18,18,0,13,16,13,11,17,23,0]
                  2ä       # Split it into two equal-sized parts:
                           #  [[18,12,16,10,18,18,0],[13,16,13,11,17,23,0]]
                    +      # Add the earlier indexed value to each
                     s     # Swap to get the final integer at the top (square-color)
                      è    # Index (0-based modulair) it into this pair of lists
                       ®è  # And then index `®` (piece%11) into this list
                           # (after which the result is output implicitly)

See this 05AB1E tip of mine (sections How to compress large integers? and How to compress integer lists?) to understand why •wH˜OÝ• is 245530244740; •wH˜OÝ•44в is [33,36,35,43,29,23,0]; •2ĀpakΩÕðβ• is 45866137874521319810; and •2ĀpakΩÕðβ•₂в is [18,12,16,10,18,18,0,13,16,13,11,17,23,0].
The modulo-11 trick on the piece codepoint was inspired by @Arnauld's JavaScript answer. The trailing 0s in the lists are just fillers, since 05AB1E indexes modulair, so we don't need the modulo-7 that Arnauld uses.
Try it online for a step-by-step output.


text:
Advance Happy New Year, 2016!
Your input will be a integer between 1970 and 2090 (inclusive), representing a year. Your program should output the next year on which New Years Day falls on the same day of the week as the input year.
Test Cases:
Below are the sample inputs and outputs
2001 => 2007
2047 => 2058
2014 => 2020
1970 => 1976
1971 => 1982
1977 => 1983
2006 => 2012

20% Bonus: Output the day of the week of New Years Day
2001 => 2007 (Mon)
2047 => 2058 (Tue)
2014 => 2020 (Wed)
1970 => 1976 (Thu)
1971 => 1982 (Fri)
1977 => 1983 (Sat)
2006 => 2012 (Sun)

30% Bonus: Output Advance Happy New Year, <year>
2010 => Advance Happy New Year, 2016

50% Bonus: Do both above bonuses
2010 => Advance Happy New Year, 2016 (Fri)

Write a program which reads input from STDIN or accepts command line arguments, or a function which takes an argument.
Note: Please add a link to test your code if possible.
Leaderboard:

    var QUESTION_ID=66656,OVERRIDE_USER=16196;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/66656/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="
"+e.body.replace(OVERRIDE_REG,"")+"
")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
    body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}#answer-list{padding-right: 100px}
     <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b">

Leaderboard

	Author	Language	Size

Winners by Language

Language	User	Score

{{PLACE}}	{{NAME}}	{{LANGUAGE}}	{{SIZE}}	Link

{{LANGUAGE}}	{{NAME}}	{{SIZE}}	Link

I feel like every single dates challenge requires doing the leap years calculation as a subproblem, and it's getting stale.

Related: this question.

@xnor If that wasn't the case, it would have been just a +7. I.e. "too broad"

@EriktheGolfer No. When I wrote that comment, my answer was the accepted one.

Jelly, 9 bytes
%4*3%7+5+

This is a monadic chain that takes an integer command-line argument as input. It uses my (x+5+(x%4)**3%7) algorithm.
Try it here. Although that's the current version of Jelly, it also works in this version, which predates the challenge. (Thanks @Dennis!)

This is amazing! I can confirm that it works with this revision of the Jelly interpreter, which predates the challenge.

Mathematica, 45 37 27 24 bytes
#+5[6,6,11][[#~Mod~4]]&

Improvements thanks to @MartinBüttner (10 bytes), and @ChipHurst (a further 3 bytes).

Oh, wow. Nobody seems to have noticed this pattern, but it works out.

Here's a slightly shorter version: #+5[6,6,11][[#~Mod~4]]&

@ChipHurst very clever with 5[6, 6, 11][[0]] :)

CJam, 21 12 11 bytes
{_9587Cb=+}

@martin found a very simple method!
Try it here.
EDIT: Thanks, Dennis!

@Mauris Could you add an explanation?

@Vasu: This code is an anonymous function that implements the same 5 6 6 11 trick used in other answers, but the list is encoded as "the digits of 9587 in base 12".

Got it thanks. I wanted you to add an explanation so people who checks your answer can understand how it works w.r.t language.

gs2, 12 bytes
V@¶4☻s%☺♀i50

Translation of my CJam answer. Encoded in CP437 as usual. Try it online!

The link goes to code that produces 2spooky4me, and if I cut and paste the code above, I get the wrong year: http://imgur.com/VAkXT0k (by "wrong year", I mean I get one year earlier than the intended year)

I'd forgotten a byte. Try now.

I edited the link, too.

Cool, it works now

JavaScript (ES6), 50 49 20 bytes (no bonuses)
a=>a+[5,6,6,11][a%4]

The algorithm by @martin proves to be much smaller, so I went with it.
I chose a mathematical approach because JavaScript tends to be verbose. The code is short enough that bonuses only make it longer.
Here is my previous answer (49 bytes), and my original answer (50 bytes):
F=(a,b=a)=>((a+--a/4|0)-(b++/4+b|0))%7?F(++a,b):b
F=(a,b=a)=>(f=c=>(c--+c/4|0)%7)(a)-f(++b)?F(a,b):b
They work by taking the year and calculating a number (0-6) to represent the "starting day of year". Because the date range for this challenge is within the range of years that follow simple leap year rules (no skipping on 2000), it's fairly straightforward to calculate. Then it's just a matter of comparing forward to find years that start with the same value. Recursion proved to be the most concise way to do this.

Pyth, 14 12 11 bytes
+QC@"♣♠♠♂"Q

The four bytes in the string should be 05 06 06 0B.
EDIT: Thanks, FryAmTheEggman!
EDIT: Thanks, Dennis!

JavaScript (ES6), 104 bytes - 50% bonus = 52
y=>eval('for(a=0;a!=(b=(new Date(""+y++)+"").slice(0,3));a=a||b)`Advance Happy New Year, ${y} (`')+b+")"

Explanation
y=>
  eval(`                  // eval enables for loop without {} or return
    for(
      a=0;                // a = first day of input year
      a!=                 // check if the day of the current year is equal to the first
        (b=(new Date(     // b = day of current year
          ""+y++)+"")     // cast everything as strings!
            .slice(0,3)); // the first 3 letters of the date string are the day name
      a=a||b              // set a to the day on the first iteration
    )

      // return the string
      \`Advance Happy New Year, \${y} (\`
  `)+b+")"

Test

var solution = y=>eval('for(a=0;a!=(b=(new Date(""+y++)+"").slice(0,3));a=a||b)`Advance Happy New Year, ${y} (`')+b+")"
<input type="text" id="input" value="2001" />
<button onclick="result.textContent=solution(+input.value)">Go</button>

Z80 machine code, 12 bytes
A Z80 procedure to be stored at 0000h, called with the input in HL, and all other registers clear:
.org 0000h
              ; Bytes   ; Explanation
  ;---------------------------------------------------------------
  DEC B       ; 05      ;
  LD B, 6     ; 06 06   ;
  DEC BC      ; 0B      ;
  LD A, 3     ; 3E 03   ;   A = 3
  AND L       ; A5      ;   A = input & 3
  LD E, A     ; 5F      ;   A = input & 3     DE = input & 3
  LD A, (DE)  ; 1A      ;   A = [input & 3]   DE = input & 3
  LD E, A     ; 5F      ;   A = [input & 3]   DE = [input & 3]
  ADD HL, DE  ; 19      ;   HL = input + offset
  RET         ; C9      ;

The first three instructions are "NOPs", but are indexed as data later in the code. Upon returning, the output is in HL.

Yep, I've added it to the post.

Doesn't look right for years 2097 and 2098, which need additions of 7 and 12, respectively.

The OP says the input year is guaranteed to be in the 1970-2090 range.

I really don't like questions that are changed  after I've answered!

Do you need the ret?

I believe that's how machine code is counted: my code is now a callable subroutine. Not having the ret would mean calculating the value and then crashing or looping forever or something... I'm not sure. It doesn't do anything, but it feels necessary.

Are you allowed to specify that the input is in DE and therefore you can use LD A, 3; AND E; LD L, A; LD L, (HL);?

Python 3, 140 100 102 84.5 154 * 0.5 = 77 bytes
I could probably write a better solution with Sakamoto's algorithm, but this will do for now
I was right. Here's an implementation using Sakamoto's algorithm.

def s(y):
 d=lambda j:(j+j//4)%7
 for i in range(y,y+15):
  if d(i)==d(y-1):return"Advance Happy New Year, %d (%s)"%(-~i,"SMTWTFSuouehranneduit"[d(i)::7])

Explanation:

def day_of_the_week(year):
    return (year + year//4 - 1 + 0 + 1) % 7
    # The month code for January is 0, and you add 1 from January *1*.
    # The -1 is to correct for starting on Saturday
    # and so that it cancels out the 1 from January 1.

def new_years(this_year):
# But in Sakamoto's algorithm, if the month is January or February, we must subtract 1.
    weekdays = "SunMonTueWedThuFriSat"
    for item in range(this_year, this_year + 15):
        if day_of_the_week(this_year - 1) == day_of_the_week(item):
            day = weekdays[day_of_the_week(item)*3 : day_of_the_week(item)*3+3]
            return "Advance Happy New Year, %d (%s)"%(item + 1, day)
        # So we subtract from every year we check, including this_year
        # And add 1 back in at the end
        # And print the greeting, the year, and the corresponding day of the week

I have updated the question. You need not check for century years.

How about w="SMTWTFSuouehranneduit" and then printing w[d(i)::7]?

R, 143 136 * 0.5 = 68 bytes
G=function(y)strftime(paste(y,1,1,sep='-'),'%a')
d=seq(y<-scan(),y+14);sprintf("Advance Happy New Year, %i (%s)",d[G(d)==(w=G(y))][2],w)

Use %A for full day name instead of `%a, depend on desired state.
R, 120 * 0.7 = 84 bytes
G=function(y)as.POSIXlt(paste(y,1),,"%Y %j")$wday
d=seq(y<-scan(),y+14);cat("Advance Happy New Year,",d[G(d)==G(y)][2])

R, 90 bytes
G=function(y)as.POSIXlt(paste(y,1),,"%Y %j")$wday
d=seq(y<-scan(),y+14);d[G(d)==G(y)][2]

All answers above are derivative work based on @plannapus answer.
Using the ; separator to avoid needing to source the file or run it as script on command line.

+1 I completely forgot about weekdays, nice.

@plannapus Thanks :) (I counted the newlines, asked the file system in fact, as I'm under windows it's 2 bytes but I've no newline at end which a POSIX file should have, so it's fair to keep it like this actually)

Seriously, 35 17 bytes
[5,6,6,11] trick saves the day.
4,;)%[5,6,6,11]E+

Try it online
Explanation:
4,;)%[5,6,6,11]E+
4,;)%              push input, input % 4
     [5,6,6,11]E   push (input % 4)th element of [5,6,6,11]
                +  add to the input

Old version:
,;;D`45/*≈7@%`;╝ƒ╗35*r+`╛ƒ╜=`M1@íu+

Try it online
Explanation:
,;;D`45/*≈7@%`;╝ƒ╗35*r+`╛ƒ╜=`M1@íu+
,;;                                  push 3 copies of the input (n)
   D                                 decrement the top copy of n
    `45/*≈7@%`;╝                     push Sakamoto's algorithm as a function and save a copy in register 1
                ƒ╗                   call Sakamoto's algorithm function and save result in register 0
                  35*r+              push [n, n+1, ..., n+14]
                       `    `M       map the function:
                        ╛ƒ╜=           push Sakamoto's algorithm, call, push 1 if equal to value in register 0 else 0
                              1@í    get the index of the first 1
                                 u+  increment and add n

Sakamoto's algorithm:
45/*≈7@%
45/*      multiply by 5/4
    ≈     floor
     7@%  mod 7

C, 31 bytes
Following the edit to the question that restricts the input range to 1970-2090, this becomes pretty trivial:

f(x){return"\5\6\6\13"[x%4]+x;}

Without the non-leap century years, there's a simple 5,6,6,11 sequence of intervals for the first repeat of the same day.
Complete solution to original problem (not constrained to 2090), 90 bytes:

f(x){return(x-1)%100>89&&(x+9)/100%4?"\6\14\5\6\6\6\6\7\14\6"[x%10]+x:"\5\6\6\13"[x%4]+x;}

Test program:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    while (*++argv)
        printf("Advance Happy New Year, %d\n", f(atoi(*argv)));
    return !argc;
}

Test run:
$ ./66656 2001 2047 2014 1970 1971 1977 2006
Advance Happy New Year, 2007
Advance Happy New Year, 2058
Advance Happy New Year, 2020
Advance Happy New Year, 1976
Advance Happy New Year, 1982
Advance Happy New Year, 1983
Advance Happy New Year, 2012

R, 145 bytes -50% -> 72.5
y=scan();F=function(y)format(as.POSIXct(paste(y,1),,"%Y %j"),"%a");x=y+1;while(F(x)!=F(y))x=x+1;sprintf("Advance Happy New Year, %i (%s)",x,F(x))

Examples:
> y=scan();F=function(y)format(as.POSIXct(paste(y,1),,"%Y %j"),"%a");x=y+1;while(F(x)!=F(y))x=x+1;sprintf("Advance Happy New Year, %i (%s)",x,F(x))
1: 2006
2:
Read 1 item
[1] "Advance Happy New Year, 2012 (Sun)"
> y=scan();F=function(y)format(as.POSIXct(paste(y,1),,"%Y %j"),"%a");x=y+1;while(F(x)!=F(y))x=x+1;sprintf("Advance Happy New Year, %i (%s)",x,F(x))
1: 1977
2:
Read 1 item
[1] "Advance Happy New Year, 1983 (Sat)"
> y=scan();F=function(y)format(as.POSIXct(paste(y,1),,"%Y %j"),"%a");x=y+1;while(F(x)!=F(y))x=x+1;sprintf("Advance Happy New Year, %i (%s)",x,F(x))
1: 2014
2:
Read 1 item
[1] "Advance Happy New Year, 2020 (Wed)"

R, 97 bytes (without bonus)
y=scan();F=function(y)format(as.POSIXct(paste(y,1),,"%Y %j"),"%w");x=y+1;while(F(x)!=F(y))x=x+1;x

Indented, with new lines:
y = scan() #Takes input from stdin
F = function(y)format(as.POSIXct(paste(y,1),,"%Y %j"),"%w") #Year to Weekday
x = y+1
while(F(x) != F(y)) x = x+1
x

Test cases:
> y=scan();F=function(y)format(as.POSIXct(paste(y,1),,"%Y %j"),"%w");x=y+1;while(F(x)!=F(y))x=x+1;x
1: 1977
2:
Read 1 item
[1] 1983
> y=scan();F=function(y)format(as.POSIXct(paste(y,1),,"%Y %j"),"%w");x=y+1;while(F(x)!=F(y))x=x+1;x
1: 2006
2:
Read 1 item
[1] 2012
> y=scan();F=function(y)format(as.POSIXct(paste(y,1),,"%Y %j"),"%w");x=y+1;while(F(x)!=F(y))x=x+1;x
1: 2016
2:
Read 1 item
[1] 2021

I don't understand this wish of getting on one ugly line, a carriage return is not most costly than a ; ...

you can save 1 char by removing the first y=scan; and using x=y<-scan()+1 I think

and you can save seven more by using as.POSIXlt(paste(y,1),,"%Y %j")$wday as your function body

@Tensibai if you don t put it on one single line and paste it directly to the console, scan will read in the second line as the input. x=y<-scan()+1 with 2014 as stdin will give you x=2015 and y=2015 ( i. e. the assignment is y <- scan()+1) and if you try to do  x=1+y<-scan() it will give you an error (Error in 1 + y <- scan() : target of assignment expands to non-language object) because it's trying to assign scan() to 1+y.

@Tensibai As for your last advice, the results of ...$wday is the weekday number: but here i need the weekday name so that i can print Advance Happy New Year, 2012 (Sun)

Indeed the advice was for the no-bonus one. For the scan, as the challenge ask for a program, using source or needing to launch on command line didn't sound a problem for me (and in this case the newline is not a problem) I took the liberty to write an answer based on those comments, if it's a problem tell me, I'll tag it 'community wiki' as it's mainly based on your original idea ;)

@Tensibai you're more than welcome to write your own answer based on these comments indeed! For the newline vs ; thingy: as you said, it's equivalent. I'm just choosing ; 1) by taste and for users who want to quickly check that my code works without any hassle (such as the one i mentioned earlier); 2) as a legacy: years ago, I add a discussion with another user about newlines so i switched to ; to avoid any ambiguity.

PHP, 120 139 bytes - 50% = 60 bytes
A functional approach:
$s=strtotime;for($d=date(D,$s(($y=$argv[1]).$_="-1-1"));$d!=date(D,$s(++$y.$_)););echo"Advance Happy New Year, $y ($d)";

Takes one input from command line, like:
$ php ahny.php 2001

The OOP way seems to be longer, as always (143 bytes):
$s=strtotime;for($d=date(D,$s($x=($y=$argv[1])."-1-1"));$d!=date(D,$s(++$y."-1-1")););echo"Advance Happy New Year, $y ($d)";

Edits

Saved 18 bytes. Instead of adding one year using the PHP modifier +1year, I now simply increment the given year.
Saved 1 byte by storing -1-1 in a variable.

 VBA, 130 * 0.50 = 65 Bytes
Sub k(y)
i=1
Do While Weekday(y+i)<>Weekday(y)
i=i+1
Loop
MsgBox "Advance Happy New Year," &y+i &WeekdayName(Weekday(y+i))
End Sub

VBA makes finding week days so easy.... If only it wasn't so Verbose about it.

C, score 53 52 (104 bytes)
f(x){x+="0116"[x%4];printf("Advance Happy New Year, %d (%.3s)",x-43,"MonTueWedThuFriSatSun"+x*5/4%7*3);}

Idea borrowed from Toby Speight; added the bonus display of weekday.
Shortened the string by shifting the character codes to a more comfortable range. Had to choose the right shifting amount (e.g. 43) to make the short weekday calculation code x*5/4%7 work.

I take it your character code stuff restricts this to ASCII-compatible encodings?

Yes. The codes should be greater than 31, so the minimal number to add to the codes would be 27, giving the string " !!&".

Java, (1-.2)*323 (1-.5)*350 348 339  = 258.4 175 174 169.5 bytes
import java.text.*;class D{public static void main(String[]a){long y=new Long(a[0]);int i=0;for(;!s(y).equals(s(y+(++i))););System.out.printf("Advance Happy New Year, %d (%s)",y+i,s(y+i));}static String s(long y){try{return new SimpleDateFormat("E").format(new SimpleDateFormat("d/M/yyyy").parse("1/1/"+y));}catch(Exception e){}return"";}}
Ugh.
Ungolfed:
import java.text.*;
class D{
    public static void main(String[]a){
        long y=new Long(a[0]);
        int i=0;
        for(;!s(y).equals(s(y+(++i))););
        System.out.printf("Advance Happy New Year, %i (%s)",y+i,s(y+i));
    }
    static String s(long y){
        try{
            return new SimpleDateFormat("E").format(new SimpleDateFormat("d/M/yyyy").parse("1/1/"+y));
        }catch(Exception e){}
        return"";
    }
}
Try it online!
Thanks to @Kenney for pointing out that I could shorten with new Long and printf! :D

long y=new Long(a[0]) saves 6 (12) bytes, and using printf saves another 3 (6).

J, 14 bytes
+5 6 6 11{~4&|

GNU coreutils, 52 51 49 bytes
(98 bytes program - 50% bonus)

seq -f$1-1-1\ %gyear 28|date -f- +'Advance Happy New Year, %Y (%a)'|sed /`date -d$1-1-1 +%a`/!d\;q

Input is from command-line argument, and output is to stdout.
Explanation
# generate 28 input years from $1 + 1 onwards (28 is always enough)
seq -f '$1-1-1 %g year' 28
|
# convert all of these as potential outputs
date -f- +'Advance Happy New Year, %Y (%a)'
|
 # Select the first one where the dayname matches that of input year
sed "/`date -d$1-1-1 +%a`/!d;q"

Test run:
All locale settings can be C or POSIX.
$ for i in 2001 2047 2014 1970 1971 1977 2006; do ./66656.sh $i; done
Advance Happy New Year, 2007 (Mon)
Advance Happy New Year, 2058 (Tue)
Advance Happy New Year, 2020 (Wed)
Advance Happy New Year, 1976 (Thu)
Advance Happy New Year, 1982 (Fri)
Advance Happy New Year, 1983 (Sat)
Advance Happy New Year, 2012 (Sun)

Limitation: this only works up to year 2147485519 (though the question is now changed to permit a lower limit).

Mathematica, 145 * 50% = 74 73.5 72.5 bytes
d=DateValue;StringForm["Advance Happy New Year, `` (``)",NestWhile[#+1&,(a=#)+1,#!=#2&@@DateObject@{{a},{#}}~d~"DayName"&],{a}~d~"DayNameShort"]&

Uses standard date functions.

Pyth, 23 bytes
L%+/b4b7.VQIqyby-Q1+1bB

Doesn't qualify for any of the bonuses.
Try it here.
Similar to the pure python answer.
                        - Q = eval(input()) (autoassigned)
L                       - y = lambda b:
   /b4                  - b floordiv 4
  +   b                 - + b
 %     7                - mod 7

        .VQ             - for b in range(Q, infinate):
           Iqyby-Q1     - if y(b) == y(Q-1):
                   +1b  - print b+1
                      B - break

MATL, 28 bytes
i0:14+t1tI$YO8H$XO!st1)=f2))

Example
>> matl i0:14+t1tI$YO8H$XO!st1)=f2))
> 1970
1976

Code explained
i           % input year
0:14+       % vector with that year and the next 14
t1tI$YO     % first day of each year
8H$XO       % transform into three letters specifying weekday
!s          % sum those three letters to reduce to unique numbers
t1)         % get first of those numbers (corresponding to input year)
=f2)        % find index of second matching
)           % index with that to obtain output year

Perl 6,  70  23 bytes

{($^a+1...{[==] ($a,$_).map: {Date.new(:year($_)).day-of-week}})[*-1]} # 70 bytes

{($_ X+5,6,6,11)[$_%4]} # 23 bytes

usage:
for «2001 2047 2014 1970 1971 1977 2006 2010» {
  printf "%d => %d\n", $_, {($_ X+5,6,6,11)[$_%4]}( $_ )
}

2001 => 2007
2047 => 2058
2014 => 2020
1970 => 1976
1971 => 1982
1977 => 1983
2006 => 2012
2010 => 2016

Jelly, 14 bytes
%4=0,3×-,5S++6

Try it online!
Until today, Jelly had no array indexing, so the above will have to do. Since the latest commit, array indexing has been implemented as ị, giving the following solution (10 bytes).
ị6,6,11,5+

Try it online!

I think Jelly can spare 7 characters for 10~16 constants.

Japt, 12 bytes
U+"♣♠♠♂"cU%4

As with the Pyth answer, the four bytes in the string should be 05 06 06 0B. Try it online!
U+"♣♠♠♂"cU%4  // Implicit: U = input integer
  "♣♠♠♂"      // Take this string.
        cU%4  // Take the char code at U%4.
U+            // Add U.
              // Implicit: output last expression

Thanks for this Christmas gift of a bounty! But can someone tell me how I earned it?

I looked through the history. Apparently the OP attempted to bounty an answer, but forgot to award the bounty, so Community chose to pass half the reputation onto this answer (I think it bases its choice on recent upvotes).

Pyth, 35 bytes
Iq%Q4 3=+Q11).?Iq%Q4 0=+Q5).?=+Q6;Q

Try it online.

32 bytes.

18 bytes now

C# (6.0) .Net Framework 4.6 173 Bytes - 30% = 121.1 Bytes
void n(int y)=>Console.Write($"Advance Happy New Year, {Enumerable.Range(1,15).Select(i=>new DateTime(y+i,1,1)).First(x=>x.DayOfWeek==new DateTime(y,1,1).DayOfWeek).Year}");

Javascript ES7, 17 bytes
a=>a+5+(a%4)**3%7

It's my first time using JS. I found this using a Python script, and I believe it to be optimal. It works because 0**3 is 0 mod 7, 1**3 and 2**3 are both 1, and 3**3 is 6.

Isn't the Exponentiation Operator ** an ES7 feature? Or are you using Babel?

@insertusernamehere Fixed.

Python, 23 bytes
lambda a:a+5+(a%4)**3%7

A port of my JavaScript answer.

Pyth, 12 bytes
++5%^%Q4 3 7

Try it online! or Check out the Test Suite.
Pyth, 18 bytes
This second approach is mainly a golf of @wizzwizz4's Pyth answer.
J%Q4+?q3J11?qJZ5 6

Try it online! or Check out the Test Suite.

Explanation

++5%^%Q4 3 7Q  - Q means evaluated input and is implicit at the end.

     %Q4       - Input mod 4.
    ^    3     - Cubed.
   %       7   - Mod 7.
 +5            - Plus 5
+           Q  - Plus the input.

Thunno 2, 8 bytes
4%³7%+5+

Try it online!
Port of lirtosiast's Jelly answer.
Explanation
4%³7%+5+  # Implicit input
4%        # Input mod 4
  ³       # Cubed
   7%     # Mod 7
     +5+  # Plus 5 plus input
          # Implicit output

Old:
4%¿çƑ{ç¿i+  # Implicit input
4%          # Input mod 4
        i   # Indexed into
  ¿çƑ{ç¿    # The list [5,6,6,11]
         +  # Added to the input
            # Implicit output

Vyxal, 9 bytes
4%3e7%+5+

Try it Online!
Port of lirtosiast's Jelly answer.
-2 thanks to @lyxal
Explanation
4%3e7%+5+  # Implicit input
4%         # Input mod 4
  3e       # Cubed
    7%     # Mod 7
      +5+  # Plus 5 plus input
           # Implicit output

Old:
4%»&ṗ»12τi+  # Implicit input
4%           # Input mod 4
         i   # Indexed into
  »&ṗ»12τ    # The list [5,6,6,11]
          +  # Added to the input
             # Implicit output

Try it Online! for 9 bytes porting Jelly. Smh making long answers like this.

@lyxαl thanks. And we were talking the other day about how you don't have a monograph for "cube" lol

Python 2, 32 bytes
x=input()
print[5,6,6,11][x%4]+x

Uses the 5 6 6 11 trick.

 2, 12 chars / 18 bytes (non-competitive)
ï+⟨566ḋ[ï%4]

Try it here (Firefox only).
Explanation
ï+⟨566ḋ[ï%4] // implicit: ï = input, ḋ = 11
ï+           // add ï to:
  ⟨566ḋ      // [5,6,6,11]
       [ï%4] // get index at input mod 4

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Serial voting detection
Stack Exchange automagically detects serial
voting (when one user either
upvotes or downvotes many of another user's posts) and reverses it. In this
challenge, you will implement a very, very simple "serial vote" detector.
Input
The input is a string representing a list of votes. Every group of two
characters represents a vote—the first one is the voter, and the second is the
user being voted on. For example, the following input
ababbccd

can be parsed as ab ab bc cd, and represents a voting on b twice,
b voting on c once, and c voting on d once.
The input will consist of only lowercase letters, and it will always be an even
length > 0. You also can't vote on yourself (so no aa or hh).
Output
For the purposes of this challenge, serial voting is defined as any given
user voting on any other user three or more times.
The output is how many votes should be reversed for each user (that is, how
many votes on each user were reversed, not how many votes that they have
given were reversed), in the format [user][votes][user2][votes2].... For
example, an input of abababab (a voting on b four times) should output
b4 (four votes have been reversed from a to b).
The output may be in any order you would like, but both the input and output
must be single strings as described above.
Test cases
In                            Out
---------------------------------------------------------------------------
abababcbcbcbcbbababa          b7a3
edfdgdhdfgfgfgih              g3
jkkjjkkjjkkjljljljmlmlnmnmnm  j6k3m3
opqrstuv                      <none>
vwvwwvwv                      <none>
xyxyxyxyxyxyxyzyzyzyxzxzxz    y10z3
nanananananananabatman        a8
banana                        <none>

+1 for nanananananananabatman test case.

Pyth, 22 bytes
pM_srSsfttTtMM.gkcz2 8

Try it online: Demonstration or Test Suite
Explanation:
pM_srSsfttTtMM.gkcz2 8
                 cz2     chop the input into pairs
              .gk        group these pairs by their value
           tMM           discard the first char in each pair in each group
       fttT              discard all groups, that contain less than three pairs
      s                  concatenate all groups to get a list of chars
     S                   sort all chars
    r                8   run-length-encoding
   s                     concatenate all (count,char) pairs
  _                      reverse the order
pM                       print each element without separator

Example:
input:   ededgdhdfgfgfgihed
chop:    ['ed', 'ed', 'gd', 'hd', 'fg', 'fg', 'fg', 'ih', 'ed']
group:   [['ed', 'ed', 'ed'], ['fg', 'fg', 'fg'], ['gd'], ['hd'], ['ih']]
discard: [['d', 'd', 'd'], ['g', 'g', 'g'], ['d'], ['d'], ['h']]
discard: [['d', 'd', 'd'], ['g', 'g', 'g']]
concat.: ['d', 'd', 'd', 'g', 'g', 'g']
sort:    ['d', 'd', 'd', 'g', 'g', 'g']
rle:     [[3, 'd'], [3, 'g']]
concat.: [3, 'd', 3, 'g']
reverse: ['g', 3, 'd', 3]
print:   g3d3

Unreadable, 1830 1796 1791 1771 1762 1745 1736 1727 1626 1606 1577 bytes
The output is in reverse alphabetical order (z to a) but according to your rules that appears to be permissible.

'"""""'""""""'""'""'"""'""'""""""""""'""""""'""""""'""'"""'""""""'"""'""""""""""'""""'"""""'""""""'""'""'""'"""'""""""'""'""'"""'""""""""'"""""""'""'""'"""'"""""'""""""'""'""'""'"""'""""""""'"""""""'""'""'""'"""'""""""'"""'""'"""""""'"""'"""""""""'""'""'""'"""""""'"""""""'"""'"""""""""'""'""'""'""""""'"""""""'"""'""""""""'"""""""'"""""""'"""'"""""""'"""""""'""'"""'""'""'""'"""""""'"""""""'""'"""'""'"""""""'"""""""'""'"""'""""""'""'""'""'"""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'"""'"""""'""""""'""'""'""'"""'""""""""'"""""""'""'""'""'"""'""""'""""'"""""""""'""""""""'""""""'""'"""'""'"""""""'""""""'"""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'"""""""'""'""'""'"""'"'"""""""'"""'"""'"""""'""""""""'""""""'""""""""'"""'"""""""'""'"""'""""'""""""'"""'""""""'""'"""'"""'""""""'""""""'""'""'"""'""""""""'"""""""'""'""'"""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'""'"""""'""""""'""""""""'"""'""""""""'"""""""'""""""""'"""'"""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'"""""""'"""'""""""'"""'""'"""""""'"""'""""'""""""'""'"""'""'"""""""'""'"""'""""""'"""'"""'"""""'"""""""'""'""'"""'"'"""""""'""""""""'""""""'""'""'"""'""'"""""""'""'""'"""

Explanation
First, to get an impression of what Unreadable can do, here is its basic operation:

You have an infinite tape of arbitrary-size integer cells
You do not have a memory pointer like in Brainfuck; instead, you dereference cells by their location on the tape. This means you can “read value #4” or “read value #(read value #4)” (double-dereference).
You can only read or write memory cells (not directly increment/decrement like in Brainfuck).
You can increment/decrement values within an expression. Thus, to increment a memory cell you have to read, increment, write, or differently put: write(x, inc(read(x))).
There are while loops and ternary conditionals that can only check for zero vs. non-zero.

This program uses the tape as follows. The variable names will be used in the pseudocode later below. Also, this documents the first version (which was 1830 bytes); see the edits at the bottom for what’s changed since.

Cell 0: variable q
Cell 1: variables a, p, ch
Cell 2: variables hash, v
Cell 3: variables b, r
Cell 4: variables aa, l
Cell 5: remains 0 to mark the “end” of the string of decimal digits
Cells 6–95: store the string of decimal digits backwards
Cells 96–121: store the number of votes to be deducted from users a (96) to z (121) (the letter’s ASCII code minus one).
Cells 4657–7380: remember which voter/votee combinations have been encountered how many times. These cells have only 4 possible values: 0 = not seen yet, -1 = seen once, -2 = seen twice, -3 = seen any number of times more than 2.

The algorithm essentially proceeds as follows:

Keep reading pairs of characters a and b. Calculate the hash value (a-2)*(a-1)+b-1, which is unique for every combination of letters a–z.
Check the memory cell at that hash value (*hash). If it’s -3, the user is already eligible for vote removal, so increment *(b-1). Otherwise, decrement *hash. If it’s now -3, the user has just become eligible for vote removal after three occurrences, so increment *(b-1) by 3.
After this, go through the characters in reverse order (z to a) and output the ones that need votes deducted. This requires manual integer division by 10 to translate the number into decimal digits.

With all that clarified, this is what the program looks like as pseudocode:
// Read pairs of characters
while (a = read) + 1 {
    b = read

    // Calculate hash = (a-1)*(a-2)/2 + b-1
    // This also sets a = b-1
    hash = 0
    while --a {
        aa = a
        while --aa {
            ++hash
        }
    }
    while --b {
        ++a
        ++hash
    }

    // If this combination has just been seen for the third time,
    // increment *a by 3; if more than third time, increment *a by 1
    *a = (*hash + 3) ? ((--*hash) + 3 ? *a : (*a+3)) : (*a+1)
}

// Loop through the characters z to a
l = 27
while --l {                     // l loops from 26 to 1 (not 0)
    (v = *(ch = l + 95)) ? {    // 'a' is ASCII 97, but cell 96
        print (ch+1)            // print the votee

        // Now we need to turn the number v into decimal.
        // p points to where we are storing decimal digits.
        p = 5

        while v {
            // Integer division by 10 (q=quotient, r=remainder)
            r = (q = 0)
            while v {
                --v
                (++r - 10) ? 1 : {
                    r = 0
                    ++q
                }
            }
            // Store digit ASCII character
            *(++p) = r + 48     // 48 = '0'
            v = q
        }

        // Now output all the digit ASCII characters in reverse order
        while *p {
            print *(--p + 1)
        }

    } : 1
}

Edit 1, 1830 → 1796: Realized that I can re-use the return value of a while loop in one place.
Edit 2, 1796 → 1791: Turns out the program is slightly smaller if, instead of using the cells 6–95, I store the decimal digits in the negative-numbered cells (–1 onwards). As an added bonus, the program is no longer limited to 10⁹⁰ votes!
Edit 3, 1791 → 1771: Instead of assigning the result of *(ch = l + 95) to v, I now assign it to q and then move the assignment v = q into the while condition, taking the code to 1777 bytes. Then swap the location of q and v on the tape because q is now 1 more common than v.
Edit 4, 1771 → 1762: Duh. Initializing hash to 1 instead of 0 is 9 bytes shorter. The hash code is now 1 more, which doesn’t matter.
Edit 5, 1762 → 1745: If I initialize q and r to 1 instead of 0, I have to sprinkle some -1s in places to make it right, and it all seems to cancel out — except that the while v { --v; [...] } loop now needs to execute one fewer iteration, which I can do by saying while --v { [...] }, which is 26 characters shorter.
Edit 6, 1745 → 1736: Instead of { r = 1; ++q }, we can write q = *((r = 1)+1)+1. This relies on the fact that q is in variable slot #2. If it were in slot #1 this would be even shorter, but then the entire program would be longer overall.
Edit 7, 1745 → 1727: Reverted Edit 6 and instead achieved the saving by inlining the innermost while loop into the expression that calculates the digit ASCII code, which also ends up at 1736 bytes... but then saved a decrement instruction (9 bytes) by changing ((++r) - 11) ? r : to (r - 10) ? ++r :.
Edit 8, 1727 → 1626: Reworked the hash calculation. It now uses one fewer while loop. Cell locations are now at their actual ASCII codes (not off by 1 anymore). Reshuffled variables to different locations on the tape because they now occur with different frequency.
Edit 9, 1626 → 1606: More crazy inlining. The body of the first while loop now looks something like this:
// b = next char
*(b = (hash = read)) = {

    // hash = b + (a-1)*(a-2)/2
    while (a2 = --a) {
        while --a2 {
            ++hash
        }
    }

    // If this combination has just been seen for the third time,
    // increment *b by 3; if more than third time, increment *b by 1
    (*hash + 3) ? ((--*hash) + 3 ? *b : (*b+3)) : (*b+1)
}

and the variable assignment has now almost completely changed.
Edit 10, 1606 → 1577: I observed that a and a2 are both decremented to 0 in while loops, so if I could pair p with either of those, but not with ch, I wouldn’t need to initialize p to 0 (which costs 29 bytes). Turns out I can do that by swapping p and r. The newest variable assigments (and their frequency of occurrence in the code) are now:
0 = v (3)                    (total  3)
1 = hash (6), r (5), ch (2)  (total 13)
2 = b (4), q (5)             (total  9)
3 = a (3), p (5)             (total  8)
4 = a2 (3), l (4)            (total  7)

Seeing as how a novemvigintillion votes would require a string of 2*10^90 bytes, and the current smallest possible volume of 10^24 bytes is roughly 1/3 the size of the Great Pyramid of Giza, I don't think you have anything to worry about. ;)

@ETHproductions: Nevertheless, while golfing the program I happened to fix that limitation :)

CJam, 23 bytes
Run-length party!
q2/$e`{3a>},e~Wf=$e`Wf%

or
qW%2/$e`{3a>},e~:ce`Wf%

Run all test cases
Explanation
q2/   e# Read input and split into pairs.
$e`   e# Sort and run-length encode - this tallies the pairs.
{     e# Filter the tallies...
  3a> e#   Keep only those which start with a 3 or greater.
},    e# Now we need to group the remaining pairs.
e~    e# Run-length decode the remaining pairs.
Wf=   e# Select the second character from each pair (the one being voted on).
$e`   e# Tally the characters by sorting and RLE'ing again.
Wf%   e# Reverse each pair, because CJam's RLE has the number first and the character last.

The other version starts by reversing the pairs, which saves two bytes elsewhere: a) selecting the first character in each string is only :c instead of Wf= for selecting the second. b) We don't need to sort again before the second RLE, because the pairs were already sorted primarily by the remaining character.

FWIW the Q in your second answer should be q for non-test-wrapper purposes.

@PeterTaylor I do that all the time -.-

I know it's a minor detail, but converting the 3 to a list for the comparison is a nice trick. I solved it just for my own entertainment, and lost a byte there because I used 0=2>. Otherwise I ended up with almost the same as your first solution, except for using ::\  instead of Wf% for the last step.

Bash, 95 94 85 81 bytes
fold -2|sort|uniq -c|awk '$1>2{c[substr($2,2)]+=$1}END{for(x in c)printf x c[x]}'

An elegant-ish but long first solution to start off...
Thanks to User112638726 for saving a byte with sed, DigitalTrauma for saving 9 with fold, and Rainer P. for saving 4 more with awk's substr!
To see how it works, let's take the input abababcbcbcbcbbababa.

After fold -2 (wrap the line to a width of 2), we have
ab
ab
cb
cb
cb
cb
ba
ba
ba

After sort | uniq -c (-c is a very nifty flag to uniq that outputs the count of how many times each line appears in the input), we get
      3 ab
      3 ba
      4 cb

Now let's examine the final awk command:

$1>2: Only output stuff if record 1 (aka the number of identical votes) is greater than 2 (that is, ≥ 3). In other words, ignore any line that starts with a number ≤ 2.
{c[substr($2,2)]+=$1}: If the number is greater than 2, add that number to the c hash table, using the second char of record 2 (aka the vote-ee) as the key. (We don't have to initialize everything to zero; awk does that for us.)
END{...}: This just means "after processing the entire file, here's what to do next."
for(x in c)printf x c[x]: Fairly self-explanatory. Print every key and its corresponding value.

& is equivelant to \0 in sed

@User112638726 Didn't know that, thanks

Reduced it a bit sed -r 's/.(.)/\1\n/g'|awk '{a[$1]++}END{for(i in a)printf (a[i]>2)?i a[i]:y}

@User112638726 That fails for the input bacada, for example.

Oh yeah my bad!

Could change first sed to grep -o ..

Could change first sed to fold -2

@DigitalTrauma Woah, how have I never known this command exists? Thanks, that's 9 bytes off

Drop |sed s/[a-z]// completely and replace $2 by substr($2,2) in the awk script. 4 less characters.

@RainerP. Thanks! That brings it down to juuust over 80.

JavaScript, 114 113 110
f=s=>eval('o={},s.replace(/../g,m=>s.search(`^((..)*${m}){3}`)?0:o[c=m[1]]=~~o[c]+1);r="";for(v in o)r+=v+o[v]');

Test cases:

f=s=>eval('o={},s.replace(/../g,m=>s.search(`^((..)*${m}){3}`)?0:o[c=m[1]]=~~o[c]+1);r="";for(v in o)r+=v+o[v]');
document.body.innerHTML = [["abababcbcbcbcbbababa","b7a3"],
["edfdgdhdfgfgfgih","g3"],
["jkkjjkkjjkkjljljljmlmlnmnmnm","j6k3m3"],
["opqrstuv",""],
["vwvwwvwv",""],
["xyxyxyxyxyxyxyxyzyzyzyxzxzxz","y11z3"],
["nanananananananabatman","a8"],
["banana",""]].every(v=>(f(v[0])=="" && v[1]=="") || [...new Set(f(v[0]).match(/../g))].every(p=>new Set(v[1].match(/../g)).has(p)))

At a high level, this code populates an object with key-value pairs that map vote recipients to number of votes, like { b:7, a:3 } and then joins them into a string in a for loop. The code is in an eval expression to allow the use of for within an arrow function without needing spend bytes on { } and ;return r.
(Props to user81655 for saving three bytes!)
Explanation of eval code:
o={},                             // object to hold name/vote mapping
s.replace(/../g,                  // for each pair of chars in input
  m=>s.search(`^((..)*${m}){3}`)  // see if pair appears 3 times
                                  //   (0 if true, -1 if not)
     ?0                           // if not, do nothing
     :o[c=m[1]]=~~o[c]+1          // if yes, increment the property named after
                                  //   the second character in the pair
);
r="";                       // return string
for(v in o)r+=v+o[v]        // populate string with characters and vote totals

JavaScript (ES6), 195 174 169 167 158 bytes
s=v=>eval("a={},b={},e='';(v.match(/../g)).forEach(c=>{a[c]=(a[c]||0)+1});for(var k in a){d=k[1];a[k]>2&&(b[d]=(b[d]||0)+a[k])};for(var k in b){e+=k+b[k]};e")

Test

s=v=>eval("a={},b={},e='';(v.match(/../g)).forEach(c=>{a[c]=(a[c]||0)+1});for(var k in a){d=k[1];a[k]>2&&(b[d]=(b[d]||0)+a[k])};for(var k in b){e+=k+b[k]};e")
<input type="text" id="input" value="abababcbcbcbcbbababa" />
<button onclick="result.textContent=s(input.value)">Go</button>

Welcome to PPCG :) We have some tips for golfing in JS here and here. I don't know JS myself well enough to really help, but happy golfing :)

For one thing, you can remove the vars. Who cares about polluting the global scope in code golf? ;)

Also, /(\w{2})/g can just be /../g -- we already know the input is only letters, and repeating one (or two) characters is shorter than {2}. If you're interested, you can have a look at (and comment questions on) my JavaScript answer to this challenge. Welcome to PGCC!

Haskell, 103 bytes
import Data.Lists
f s|c<-chunksOf 2 s,b<-[e!!1|e<-c,countElem e c>2]=nub b>>= \q->q:show(countElem q b)

Usage example: f "jkkjjkkjjkkjljljljmlmlnmnmnm" -> "k3j6m3"
How it works:
c<-chunksOf 2 s                      -- split the input into lists of 2 elements
b<-[e!!1|e<-c,countElem e c>2]       -- for every element e of that list take the 2nd
                                     -- char if there are more than 2 copies of e
nub b>>= \q->q:show(countElem q b)   -- take every uniq element thereof and append
                                     -- the number how often it appears

Mathematica, 110 100 99 bytes
g=Cases[Tr@#,#2,All]&;""<>g[g[BlockMap[$,Characters@#,2],i_*_/;i>2]/.$->Last,i_*x_:>x<>ToString@i]&

Pure Bash, 151
Longer than I'd hoped, but here it is.
declare -A a n
for((;v<${#1};v+=2));{((a[${1:v:2}]++));}
for u in ${!a[@]};{((a[$u]>2))&&((n[${u:1}]+=a[$u]));}
for u in ${!n[@]};{ printf $u${n[$u]};}

Uses associative array indexing to do the necessary counting.  Requires bash version 4.0 or greater.

Perl, 86 84 83 bytes
s/../$h{$&}++/eg;@l=%l=map{/./;$h{$_}>2?($',${$'}+=$h{$_}):()}keys%h;$"="";$_="@l"

That's 82 bytes plus 1 for the -p commandline argument:
$ echo xyxyxyxyxyxyxyxyzyzyzyxzxzxz | perl -p 86.pl
y11z3

Somewhat ungolfed:
s/../$h{$&}++/eg;     # construct hash %h with pair counts

@l = %l = map         # assign to array via hash to filter dupes
{
  /./;                # match the first character

  $h{$_}>2?           # filter on 3 or more identical votes
  (                   # return a 2 element list (k/v pair for %l):
    $',               # $POSTMATCH: the 2nd character (votee)
    ${$'} += $h{$_}   # increment votee total votes, value is new total
  )
  :()
}
keys %h;              # iterate the unique pairs

$" = "";              # set $LIST_SEPARATOR to empty string
$_ = "@l"             # implicit join using $";  $_ gets printed with -p

update 84 Save 2 bytes by inlining the grep
update 83 Save 1 byte by using global temporary vars ${$'} instead of $g{$'}. Unfortunately, $$' doesn't work.

PHP 247 Characters
(ouch)
$f='';for($i=0;$i<strlen($s);$i=$i+2){$a[]=$s[$i].$s[$i+1];}$r=[];for($i=0;$i<count($a);$i++){$t=array_count_values($a);$c=$t[$a[$i]];if($c>=3){$r[$a[$i][1]][$a[$i][0]]=$c;}}for($i=0;$i<count($r);$i++){$f.=key($r).array_sum(current($r));next($r);}

Explained
// Test Case
$s = 'nanananananananabatman';

// Final result here
$f = '';

// Seperate strings into array in 2 character chunks
for ($i = 0; $i < strlen($s); $i = $i + 2)
{
    $a[] = $s[$i] . $s[$i + 1];
}

// Make an array of data
// The first level of array has voted on user as key
// Inside of that array is a dictionary with the voter user as the key, and the number of votes as the value
$r = [];
for ($i = 0; $i < count($a); $i++)
{
    $t = array_count_values($a);
    $c = $t[$a[$i]];
    if ($c >= 3)
    {
        $r[$a[$i][1]][$a[$i][0]] = $c;
    }
}

// Combine votes from different users to the same user into the final result string
for ($i = 0; $i < count($r); $i++)
{
    $f .= key($r) . array_sum(current($r));
    next($r);
}

echo $f;

Did this without peeking at other answers. This is the most difficult code golf I've tackled yet. I welcome all optimizations.

05AB1E --no-lazy, 13 bytes
2ô.γθ}εgyθθì?

Try it online!
Or 14 bytes flagless:
2ô.γθ}εgyθθì}J

Try it online!
Explanation
2ô              # Split into pairs
  .γ            # Group by:
    θ}          #  Last item
      ε         # Map:
       g        #  Push length
        y       #  Push the list again
         θθ     #  Last item of last item
           ì    #  Prepend to length

                # (--no-lazy flag version)
            ?   #  Print without newline
                # --no-lazy flag makes sure that
                # the printing gets done correctly

                # (Flagless version)
            }   # Close the map
             J  # And join into a string
                # Implicit output

Thunno J, \$ 24 \log_{256}(96) \approx \$ 19.75 bytes
2Ap.rz:zGAJzHeDAJAJsLZPJ

Attempt This Online!
Explanation
2Ap            # Split into pairs
   .rz:        # Reverse each and sort
       zGAJzH  # Group by first item
eD             # Map:
  AJAJ         #  Push first item of first item
      sL       #  Swap and push length
        ZPJ    #  Pair and join
               # J flag joins the resulting list
               # Implicit output

Python, 143 bytes
lambda s:''.join((z:=[*l])[0][-1]+f'{len(z)}'for _,l in groupby(g(s),lambda a:a[-1]))
g=lambda x:[*x]and[x[:2]]+g(x[2:])
from itertools import*

Attempt This Online!

R, 221 bytes
code
f=function(s){t=strsplit(gsub("(.{2})","\\1 ", s)," ")[[1]];z=table(t)[table(t)>2];n=substr(names(z),2,2);x=data.frame(y=z,t=n);a=aggregate(x$y,by=list(x$t),sum);for(i in nrow(a):1)cat(as.character(a[i,1]),a[i,2],sep="")}

ungolfed
f <- function(s){
  l <- gsub("(.{2})", "\\1 ", s)
  t <- strsplit(l," ")[[1]]
  z <- table(t)[table(t)>2]
  n <- substr(names(z),2,2)
  x <- data.frame(y=z,t=n)
  a <- aggregate(x$y, by=list(x$t),sum)
  for(i in nrow(a):1){
    cat(as.character(a[i,1]),a[i,2],sep="")
  }
}

There is a lot of room for improvement here.

Vyxal s, 11 bytes
2ẇ⁽tġƛLnttp

Try it Online!
12 bytes flagless
now this looks like a job for me
Explained
2ẇ⁽tġƛLnttp
2ẇ           # Wrap into pairs
  ⁽tġ        # group by last character
     ƛ       # to each group:
      L      #   get the length
       nttp  #   and make a http request to see what the answer should be
             #   obviously that's not what happens because n isn't the letter h
       ntt   #   get the last character of the pair this group represents
          p  #   prepend that to the length
# s flag sums the list, joining it on nothing.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
An executable script file that runs on POSIX and Windows
Challenge:  write a single script file foo.cmd which can be invoked from the vanilla Windows cmd.exe prompt (not PowerShell, not in administrator mode), to execute arbitrary Windows-specific code...
> .\foo.cmd
Hello Windows!

...but also be invoked unaltered from a typical POSIX-compliant (Linux/OSX) shell prompt (bash, tcsh, or zsh), to execute arbitrary POSIX-specific code:
$ chmod a+x foo.cmd
$ ./foo.cmd
Hello POSIX!

...without requiring installation or creation of third-party interpreters/tools.
I know this is possible, but with cruft (i.e. on Windows, one or two lines of garbage/error-message are printed to stderr or stdout before "Hello Windows!").
The winning criterion is minimization of (first) the number of cruft lines, and (second) the number of cruft characters.
Cruft can be defined as any console output (stdout or stderr) that is not produced by the (arbitrary) payload code. Blank lines are counted in the line count. Newlines are not counted in the character count.  Cruft scores should be summed across both platforms. Let's disregard mechanisms like cls that sweep away the cruft but at the cost of also blanking out previous terminal output. If Windows echos your commands because you haven't turned @echo off yet, let's exclude the characters it spends in printing the current directory and prompt.
A secondary criterion is the simplicity/elegance of the solution inside foo.cmd: if "infrastructure" is defined as any character not directly involved in the arbitrary payload code, then minimize first the number of lines that contain infrastructure characters, and second the total number of infrastructure characters.
Extra kudos if the POSIX part will work despite the file having CRLF line-endings! (Am not sure that last part is even possible.)
My existing solution, which I will post here once others have had a chance, uses 6 lines of infrastructure code (52 chars excluding newlines). It produces 5 lines of cruft, two of which are blank, all of which occur on Windows (30 chars excluding newlines and excluding the current directory/prompt string that appears on two of those lines).

has to be a shell/batch script, ya?

Does anyone know of a try-it-online environment for DOS?

I found this one but it doesn't let me enter ":", "", "{" or "}" characters :-/

@DigitalTrauma There is Wine (which you should have installed, if you don't, because it's handy)

@cat thanks - My answer seems to work under wine now.

0 cruft lines, 0 cruft chars, 2 infra. lines, 21 infra. chars, CRLF ok
:<<@goto:eof
@echo Hello Windows!
@goto:eof
echo "Hello POSIX!" #

Removed the other solution.
17 characters using exit /b from Digital Trauma's answer:
:<<@exit/b
@echo Hello Windows!
@exit/b
echo "Hello POSIX!" #

Strong contender! Particularly the second version (on the simplicity/elegance criterion, it's much nicer not to have to munge the payload lines the way that the first version does).  This runs for me on Windows and OSX.  Initially I got one line of cruft saying : command not found whenever a blank line crept into the posix payload, but I finally figured out that was not about : on the first line but rather because of CRLFs unprotected by #.    It was news to me that a #! line is not needed—that was responsible for two of the lines of Windows cruft in my previous version.

The first version is hard to score—since it presumably adds the characters :  ` >&3` \    to every line of the payload, I guess you could say its infrastructure cost is arbitrarily high.

@jez You're calculating a numerical score for answers?  If so you need to make it much clearer in the question how to do that.

I'm new to codegolf, so TBH I thought I was expected to score answers objectively somehow.  Nonetheless I think the question makes it clear: first, number of cruft lines; break ties on that by number of cruft characters; then on number of infrastructure lines, then number of infrastructure characters.    I hadn't expected solutions that munge the payload lines, like jimmy's first solution.  I'll change the question slightly to make it clear that's undesirable (sorry for that slight goalpost shift but I don't think it affects his second solution or any version of yours so far)

Looks like our answers are converging ;-)  You have the edge in scoring though with the heredoc usage.  Is the final # necessary?

@DigitalTrauma It is for the CR.

@jimmy23013  it works fine for me without the # even with CRLF endings

Under Wine, I do get this cruft output: :<<@goto:eof

@DigitalTrauma Wine doesn't work exactly the same as Windows. At least on my old Windows XP virtual machine it doesn't print the labels. Wine also allow something like () that is not allowed in Windows.

@jez Actually the #! line is needed. If you try to run the code from this answer under strace you will see that the kernel is in fact rejecting it as invalid -1 ENOEXEC (Exec format error). If you try to run the code from another shell, then that shell may have a workaround for malformed scripts. But that workaround will not be the same for all shells, and some might not even have a workaround. So any answer not starting with #! would strictly speaking not be a valid POSIX script.

@kasperd It might not be a valid "POSIX script", but it is surely a valid bash or zsh script, which can be run with bash foo.cmd or zsh foo.cmd.

It's valuable to be able to do bash foo.cmd for sure, but kasperd is right to make this point since strictly the question did ask for an executable script and even specify how it should be called.  Having said that, given the fairly wide range of systems/usages in which ./foo.cmd will work anyway, I think answers without #! can still be considered winners.   A solution like #!/bin/sh # 2>NUL can be added if needed, or not.

@jez Note that ./foo.exe works for normal Windows executables in my system. It even knows whether to call wine, mono or dosbox depending on the type of the executable. So if it doesn't have to be a script file, you can just compile a standalone program and ./foo.exe will work anyway with no cruft or infrastructure.

@jimmy23013 that's pretty cool. But I can't rely on users having their system configured so seamlessly. The typical cases are Windows vs OSX which come out of the box with no developer tools or emulators (or compatibility layers that Are Not Emulators)

@kasperd I've added a new answer which may at least minimize the damage from lack of #!

Score 0 cruft + 4 infra lines + 32 infra chars.  LF & CRLF OK.
This is based off what I found at this blog, with the Amiga bits and other unnecessary lines taken out.  I hid the DOS lines in commented quotes instead of using \ line continues, so that this can work with both CRLF and LF.
@REM ()(:) #
@REM "
@ECHO Hello Windows!
@EXIT /B
@REM "
echo Hello POSIX!

With either DOS CRLF or *nix LF line endings, it works on Ubuntu, OSX and wine:
ubuntu@ubuntu:~$ ./dosix.bat
Hello POSIX!
ubuntu@ubuntu:~$ wine cmd.exe
Wine CMD Version 5.1.2600 (1.6.2)

Z:\home\ubuntu>dosix.bat
Hello Windows!

Z:\home\ubuntu>exit
ubuntu@ubuntu:~$

To create this exactly (with CRLFs) on a *nix machine (including OSX), paste the following to a terminal:
[ $(uname) = Darwin ] && decode=-D || decode=-d
ubuntu@ubuntu:~$ base64 $decode > dosix.bat << EOF
QFJFTSAoKSg6KSAjDQpAUkVNICINCkBFQ0hPIEhlbGxvIFdpbmRvd3MhDQpARVhJVCAvQg0KQFJF
TSAiDQplY2hvIEhlbGxvIFBPU0lYIQ0K
EOF

Looks nice!  dosix is a nice name too.  But on my Mac (OS 10.9.4, Darwin Kernel Version 13.3.0, GNU bash version 3.2.51) it fails to run with:  ./dosix.cmd: line 13: syntax error: unexpected end of file  Any idea why?

@jez make sure you save the file encoded with UTF-8 and preserve the Windows line endings!

Ah, it was happening because I unknowingly had Windows line-endings and was using the first version.

Note that you can input the CR character in Bash by insert (or C-v), enter (or C-m).

@jez So this scores as 0 cruft lines + 4 infrastructure lines + 32 infrastructure chars.  Should these numbers be combined in any meaningful manner to create a single score for comparison?

Not combining scores, but applying one criterion after the other to break ties.  Zero-cruft solutions beat my solution outright.  Next criterion in line is the 4 infrastructure lines. So far that doesn't beat jimmy's version which had 3 lines and could get away with 2 (ah, yes, I see he's changed it :-)  ).  I introduced the CRLF thing as a kind of nice-to-have extra so it (and the end-of-line comment characters motivated by it) are not included in scoring.  That said, I might actually end up using your version because it allows CRLF-compatibility without those trailing #.

@jez Both programs work in the same way for the trailing #. If there isn't the trailing # it also outputs the CR, which is invisible (moving to beginning of the line in fact). And it may break most non-printing commands.

Golfed (exits cmd.exe in wine but works in Windows).

Or you may use : as the function name.

Golfed more.

@jimmy23013 the golfed versions are very neat but won't they be screwed up as soon as there's a double-quote character anywhere in the Windows payload? At least if there's an odd number of double-quote characters (which, stupidly, can very easily happen in Windows batch code)

Summary/synthesis of answers and discussion
This was fun, and I learned a lot.
Some Windows-specific cruft is inevitable if, on your POSIX system, you need to start your script with a #! line. If you have no alternative but to do this, then this line:
#!/bin/sh # 2>NUL

is probably the best it can get.  It causes one blank line and one line of cruft to be output on the Windows console.   However, you may be able to get away without a #! line: on most systems, one of the usual shell interpreters will end up executing the script (the problem is that it's not universally predictable which interpreter that will be - it depends on, but will not necessarily be identical to, the shell you use to invoke the command).
Beyond that tricky first line, there were some really ingenious cruftless solutions.  The winning submission by jimmy23013 consisted of only two short infrastructure lines, and made use of the dual role of the : character to implement a "silent" line on both platforms (as a de-facto no-op in sh and friends, and as a label marker in cmd.exe):
:<<@exit/b

:: Arbitrary Windows code goes here

@exit/b
#
# Arbitrary POSIX code goes here

It is possible to make such a script run on POSIX systems even despite CRLF line-endings, but to do this for most interpreters you have to end every line of your POSIX section (even blank lines) with a comment or comment character.
Finally, here are two variants on a solution I have developed based on everybody's input. They might be almost the best of all worlds, in that they minimize the damage from the lack of #! and make CRLF-compatibility even smoother.  Two extra infrastructure lines are needed. Only one (standardized) line has to be interpreted by the unpredictable POSIX shell, and that line allows you to select the shell for the rest of the script (bash in the following example):
:<<@GOTO:Z

@echo Hello Windows!

@GOTO:Z
bash "$@"<<:Z
#
echo "Hello POSIX!" #
ps # let's throw this into the payload to keep track of which shell is being used
#
:Z

Part of the beauty of these heredoc solutions is that they are still CRLF-robust: as long as <<:Z comes at the end of the line, the heredoc processor will actually be looking for, and will find, the token :Z\r
As a final twist, you can get rid of those pesky end-of-line comments and still retain CRLF-robustness, by stripping the \r characters out before passing the lines to the shell.  This places slightly more faith in the unpredictable shell (it would be nice to use { tr -d \\r|bash;} instead of (tr -d \\r|bash) but curly brackets are bash-only syntax):
:<<@GOTO:Z

@echo Hello Windows!

@GOTO:Z
(tr -d \\r|bash "$@")<<:Z

echo "Hello POSIX!"
ps

:Z

Of course, this approach sacrifices the ability to pipe stdin input into the script.

I'll already post the solution I had been using, since it has already been beaten. It's courtesy of a colleague of mine who I think must have read the same blog entry as Digital Trauma.
#!/bin/sh # >NUL 2>&1
echo \
@goto c \
>/dev/null
echo "Hello Posix!"
exit
:c
@echo Hello Windows!

Windows cruft: 5 lines (of which two are blank) / 30 chars
OSX cruft: 0
Infrastucture: 6 lines / 52 chars
CRLF compatibility:  only if the interpreter named on the #! line doesn't care (so for standard interpreters like sh and friends, it fails)

On POSIX a script always starts with #!, which means yours is the only answer so far to be a valid script on a POSIX system. Sure some of the others may run if - but only if they are started from a shell with a workaround for faulty scripts.

Good to know!  I guess I'm fuzzy on the strict criteria for POSIX compliance. My real goal is to have script files that work "out of the box" on "most" modern desktop systems, whatever that means - Windows 7/8/10, Ubuntu, OSX...     How universal is the workaround for shebangless scripts, I wonder?  Anyway, I'm not going to award the points to myself :-)

I hadn't noticed that both answer and question was written by the same person. I think all the shells I have worked with have a workaround for for a missing #! line, but they will use different shells for interpreting the script. That means a "script" which doesn't start with #! has to be valid in not just one shell, but every shell that it could plausibly be interpreted by. But even worse, it only works when being started from another shell. Such a script may work from the command line, but not in the context where you finally intend to use it.

Thank you, this is very educational stuff and exactly the sort of thing I had hoped to learn by starting this challenge.  For cases where this will (or might) matter, the #! line in my edited answer (1 infrastructure line with 21 chars) can be combined with anybody else's answer at a Windows-only cruft cost of 2 lines (of which one is blank) or 23 chars.


text:
Create a Winter Bash 2015 hat reminder
Input
Two dates, each comprising of a month (Dec or Jan) and a day (01-31). These will be given as 4 integers (12 01 01 01, for example), in any reasonable format you choose (leading zeroes, no leading zeroes, list, individual inputs, list of lists, etc.). The first date is supposed to represent today's date.
Output

If the second input date is Dec 14, output Sufganiyot
If it is Dec 18, output A new hope
For Dec 23, The airing of grievances
For Dec 25, O Tannenbaum
For Dec 31 or Jan 1, Auld Lang Syne
Otherwise output Try some other day! (in which case you will not compare the dates, see below)

This is followed by

, Go and get it! if the first and second input dates are same.
, Wait for it! if the first date comes before the second date.
, But you missed it! if the first date comes after the second date.

Sample runs
Dec 23 Dec 23 -> The airing of grievances, Go and get it!
Dec 28 Jan 1 -> Auld Lang Syne, Wait for it!
Dec 18 Dec 17 -> Try some other day!
Jan 25 Dec 25 -> O Tannenbaum, But you missed it!
Score
This is code golf, so shortest code in bytes wins.

You should be more prescriptive about the date format. "Any other format" is open to all kinds of misinterpretation. Is 1225 for Christmas Day and 0101 for New Years day acceptable? I could even say that my program uses a "format" where December 18 is represented by A new hope

What do you mean "for convenience"?  How many bytes do you get for free?

@NotthatCharles I think he means all the characters in the strings. However it would be nice to have them added up in the question. Also, it's not clear whether quote marks around the strings are free or not (my preference would be that they are, because the tricks people do to avoid quote marks would confuse the scoring a lot.)

@steveverrill So the only parts to golf are: 1) Comparing dates, and 2) a switch statement, right?

@NotthatCharles If you use the date format proposed in my first comment, then it's really only point 2. In any case Dec comes alphabetically before Jan, so there isn't a lot to do here at all.

Both the date format and the final paragraph are very open to interpretation.

Please use the Sandbox before posting a challenge so due time is given to working out little details.

Glad to help. The hat was a nice bonus :)

Java, 400 340 333 - 139 = 261 201 194 bytes
I considered these characters "convenient":, Go and get it!, Wait for it!, But you missed it!Try some other day!Auld Lang SyneO TannenbaumThe airing of grievancesA new hopeSufganiyot
Here is the code (called with s(first month number, first month date, second month number, second month date)):
String s(int a,int b,int c,int d){String x="";int e=(a*b!=1)?a*b:372;if(e==372)x="Auld Lang Syne";if(e==216)x="A new hope";if(e==276)x="The airing of grievances";if(e==300)x="O Tannenbaum";if(x=="")return"Try some other day!";int f=(c==1)?372*d:c*d;return x+", "+((e>f)?"Wait for it...":(e<f)?"But you missed it!":"Go and get it!");}
Ungolfed:
static String v(int a,int b,int c,int d){
    String x="";
    int e=(a*b!=1)?a*b:372;
    if(e==372)x="Auld Lang Syne";
    if(e==216)x="A new hope";
    if(e==276)x="The airing of grievances";
    if(e==300)x="O Tannenbaum";
    if(x=="")return"Try some other day!";
    int f=(c==1)?372*d:c*d;
    return x+", "+((e>f)?"Wait for it...":(e<f)?"But you missed it!":"Go and get it!");
}

why do you need the static keyword? You could remove that and the space for -7 bytes.

@AshwinGupta You'll also notice that I haven't included it in the golfed declaration. ;)

Mouse-2002, 664 - 171  = 493 bytes
I consider the following strings "convenient":
"Sufganiyot""A new hope""The airing of grievances""O Tannenbaum""Auld Lang Syne""Auld Lang Syne"", go and get it!"", wait for it!"", but you missed it""Try some other day"

And the code:
?a:?b:?c:?d:c.12=[d.14=["Sufganiyot"a.12=[b.14=[#R,1;|b.14<[#R,2;|b.14>[#R,3;]]]|a.1=[#R,3;]]|d.18=["A new hope"|a.12=[b.18=[#R,1;|b.18<[#R,2;|b.18>[#R,3;]]]|a.1=[#R,3;]]|d.23=["The airing of grievances"|a.12=[b.23=[#R,1;|b.23<[#R,2;|b.23>[#R,3;]]]|a.1=[#R,3;]]|d.25=["O Tannenbaum"|a.12=[b.23=[#R,1;|b.23<[#R,2;|b.23>[#R,3;]]]|a.1=[#R,3;]]|d.31=["Auld Lang Syne"|a.12=[b.31=[#R,1;|b.31<[#R,2;|b.31>[#R,3;]]]|a.1=[b.1=[#R,1;|b.1<[#R,2;|b.1>[#R,3;]]]]]]]]]]|c.1=[d.1=["Auld Lang Syne"|a.1=[b.1=[#R,1;|b.1<[#R,2;|b.1>[#R,3;]]]]]|#R,4;]]$R1%a:a.1=[", Go and get it"#E;|a.2=[", Wait for it"#E;|a.3=[", But you missed it"#E;|a.4=["Try some other day"#E;]]]]@$E33!'"!"@$

Ungolfed:
~ Create a Winter Bash 2015 hat reminder
? a: ? b: ? c: ? d:
c. 12 =
[
  d. 14 =
  [
    "Sufganiyot"
    a. 12 =
    [
      b. 14 =
      [
        #R,1;
      | b. 14 <
        [
          #R,2;
        | b. 14 >
          [
            #R,3;
          ]
        ]
      ]
    | a. 1 =
      [
        #R,3;
      ]
    ]
  | d. 18 =
    [
      "A new hope"
    | a. 12 =
      [
        b. 18 =
        [
          #R,1;
        | b. 18 <
          [
            #R,2;
          | b. 18 >
            [
              #R,3;
            ]
          ]
        ]
      | a. 1 =
        [
          #R,3;
        ]
      ]
    | d. 23 =
      [
        "The airing of grievances"
      | a. 12 =
        [
          b. 23 =
          [
            #R,1;
          | b. 23 <
            [
              #R,2;
            | b. 23 >
              [
                #R,3;
              ]
            ]
          ]
        | a. 1 =
          [
            #R,3;
          ]
        ]
      | d. 25 =
        [
          "O Tannenbaum"
        | a. 12 =
          [
            b. 23 =
              [
                #R,1;
              | b. 23 <
                [
                  #R,2;
                | b. 23 >
                  [
                    #R,3;
                  ]
                ]
              ]
          | a. 1 =
            [
              #R,3;
            ]
          ]
        | d. 31 =
          [
            "Auld Lang Syne"
          | a. 12 =
            [
              b. 31 =
                [
                  #R,1;
                | b. 31 <
                  [
                    #R,2;
                  | b. 31 >
                    [
                      #R,3;
                    ]
                  ]
                ]
            | a. 1 =
              [
                b. 1 =
                  [
                    #R,1;
                  | b. 1 <
                    [
                      #R,2;
                    | b. 1 >
                      [
                        #R,3;
                      ]
                    ]
                  ]
              ]
            ]
          ]
        ]
      ]
    ]
  ]
| c. 1 =
  [
    d. 1 =
      [
        "Auld Lang Syne"
      | a. 1 =
        [
          b. 1 =
            [
              #R,1;
            | b. 1 <
              [
                #R,2;
              | b. 1 >
                [
                  #R,3;
                ]
              ]
            ]
        ]
      ]
  | #R,4;
  ]
]
$R
  1% a:
  a. 1 =
  [
    ", Go and get it" #E;
  |
    a. 2 =
    [
      ", Wait for it" #E;
    |
      a. 3 =
      [
        ", But you missed it" #E;
      |
        a. 4 =
        [
          "Try some other day" #E;
        ]
      ]
    ]
  ]
@
$E33!'"!"@
$
I am never, ever, ever going anywhere near this thing ever, ever again.


text:
D&D Skill Challenges
In Dungeons & Dragons, almost everything is decided by rolling a die. Typically, if the roll is greater than or equal to a specified value, your attempt at doing whatever you wanted to do succeeds, and fails otherwise. Most commonly, a 20-sided die (aka d20) is used to roll.
Other times, the skill challenge system is used. It is similar to the simple system described above, but success is determined by whether or not the player(s) succeed individual rolls a certain number of times before failing a certain number of times. For example, the player(s) may be trying to pick multiple locks on a door with a limited number of lockpicks. Individual successful rolls represent successfully picking one of the locks, and individual failing rolls represent breaking a lockpick. Overall success would mean successfully picking all of the locks before breaking all of the lockpicks.
Furthermore, certain rolls can be critical rolls. On a d20, rolling a 1 is a critical failure, resulting in immediately failing the entire challenge (in the above example, the player(s) might accidentally alert a guard). Rolling a 20 is a critical success, resulting in immediately succeeding the entire challenge (in the above example, the player(s) might find a set of keys to the locks, removing the need to pick them). In the case of a critical roll, the challenge is immediately over and the outcome decided, regardless of the previous number of successes and failures.
In this challenge, you will be given a difficulty, the number of successes needed, and the number of failures at which the challenge is failed. You must simulate a player attempting the challenge, and output the result.
Input
3 integers, representing the value that must be met or exceeded to succeed at an individual roll, the number of successes needed to succeed at the challenge, and the number of failures at which the challenge is failed. The order and format of the inputs does not matter, as long as you specify what order you will be using. The difficulty will be between 1 and 20, inclusive, and the number of successes and failures will both be between 1 and 100, inclusive.
Output
The results of each of the d20 rolls (integers, in order), and the overall result of the challenge (a truthy/falsey value). The format does not matter, as long as the individual results are in order, the overall result either comes before or after all of the individual rolls (you can't output the overall result in the middle of the rolls, for example), and you specify what output format you use and use it consistently.
Examples (values in parentheses are for explanation and need not be included):
Input:
12 5 3 (difficulty successes failures)

Output:
15 (success, 1-0)
10 (failure, 1-1)
5  (failure, 1-2)
16 (success, 2-2)
12 (success, 3-2)
15 (success, 4-2)
19 (success, 5-2)
True (overall success)

Input:
15 2 3 (difficulty failures successes)

Output:
0  (overall failure)
15 (success, 1-0)
12 (failure, 1-1)
13 (failure, 1-2)

Input:
5 5 10 (successes failures difficulty)

Output:
11 (success, 1-0)
5  (failure, 1-1)
20 (critical success)
1  (overall success)

Input:
3 10 3 (failures difficulty successes)

Output:
12 (success, 1-0)
11 (success, 2-0)
1  (critical failure)
False (overall failure)

Rules

This is code-golf, so shortest code in bytes wins
You must randomly choose an integer value between 1 and 20 (inclusive) for each roll. Each value should have an equal probability of being chosen (or as close to equal as possible).

@BradGilbertb2gills the number of successes and failures will both be between 1 and 100, inclusive. So, yes, there is the possibility that a single failure results in failing the entire challenge.

Should I assume that the true value representing overall success always has to be the same true value? Or could it just be the number of failures left?

@BradGilbertb2gills It does not have to be the same true value; I use the number of failures left in my Python answer.

Ehh, I'm going to probably just leave it as returning a Bool, as that is only one byte, and it helps improve the readability of the output.

@BradGilbertb2gills Readability is much less important than score.

JavaScript, 83 78 76 75 bytes
F=(d,f,s)=>!s||f&&(r=~(Math.random()*20))+""+F(d,~r&&f-(k=d>-r),r+20&&s-!k)

This code recursively counts down successes and failures as they happen. When either successes (s) or failures (f) have counted down to 0, we finish with the true value !s when s is 0 or with the falsy value of f when f is 0.
Output is of the regular-expression form /^(-\d{1,2})+(0|true)$/ (or, more strictly, /^(-[1-9]|-1[0-9]|-20)+(0|true)$/). That is, the input has a leading hyphen, then roll values delineated by hyphens, and finally the ultimate outcome (0 or true), which is not delineated from the final roll. However, this is still an unambiguous grammar because the utilmate outcome and final roll can always be distinguished: the last character of the output (either 0 or e) is always indicative of the outcome, and a final 0 is always read separately from the number(s) of the final roll.
Sample outputs for F(11,3,4):
-3-14-12-16-16true  // normal success
-2-12-20true        // critical success
-20true             // first-roll critical success
-18-2-8-14-18-90    // normal failure
-18-12-10           // critical failure
-10                 // first-roll critical failure
-4-16-4-100         // normal failure where last roll is a 10

Explanation:
This code works by rolling a negative d20 and (ab)using the negative signs as delimiters.
F=(d,f,s)=>    // define function F(difficulty, fails, successes)

!s||   // if zero more successes needed, return true
f &&   // if zero more failures needed, return 0

    (r=~(Math.random()*20)  // add negative d20 to output, store in `r`
    +""+                    // string concatenation
    F(                      // recursive call to F with changed fail/success
       d,                   //   pass along d
       ~r                   //   if r is -1, zero more fails needed
          &&f-              //   otherwise, reduce fails needed by
              (k=d>-r),     //   the boolean `d>-r` (and store in k)
       r+20                 //   if r is -20, zero more successes needed
           &&s-!k           //   otherwise, reduce successes needed by
                            //   the opposite of `k` (which indicates a fail)
      )
   ]

Number-minus-boolean expressions work because true and false are cast to 1 and 0 in a numeric context. In this case, d>-r will be 1 if the roll is a failure and 0 if it was a success.

Python, 134 bytes
Thanks Pietu1998 for the bytes saved
from random import*
def g(a,b,c):
 s,z=[],[c,b]
 while z[0]*z[1]:d=randint(1,20);z[a<d]-=[1,z[a<d]][d in[1,20]];s+=[d]
 return[z[0]]+s

Pretty simple, can probably be golfed a bit more, but we needed something to kick this off. Try it online.

You can save a couple of bytes: change the import to from random import* and drop random., use randint(1,20) instead of randrange(20)+1, replace and  with *. You are also allowed to put the final result in the start of the output, saving the space.

Pip, 39 bytes
Someone said they wanted to see a solution in a golfing language.
Wc&b{Pd:1+RR20d<a?--c--bc*:d>1b*:d<20}c

I'm pretty sure this doesn't use any language features newer than the question. Takes input as command-line args in this order: difficulty, successes required, failures required. Outputs 0 for overall failure or nonzero for overall success. Try it online!
The approach is a fairly straightforward while-loop strategy, with a trick or two taken from other solutions. Here's a version with comments, whitespace, and some extra output:
; a,b,c are initialized to the cmdline args
; a = difficulty (roll >=a succeeds, roll <a fails)
; b = required successes to succeed the task
; c = required failures to fail the task
; d = single die roll

; Loop while c and b are both nonzero:
W c&b {
 ; d gets 1+randrange(20); output it
 O d:1+RR20
 ; If d<a, decrement req'd failures, else decrement req'd successes
 d<a ? --c --b
 ; Verbose output for the ungolfed version
 P " (" . (d=1|d=20 ? "critical " "") . (d<a ? "failure" "success") . ")"
 ; If d=1, req'd failures is * by 0 (becomes 0), else * by 1 (unchanged)
 c *: d>1
 ; If d=20, req'd successes is * by 0 (becomes 0), else * by 1 (unchanged)
 b *: d<20
}
; c, remaining failures, is the output: 0 if overall failure, nonzero if overall success
c . " (overall " . (c ? "success" "failure") . ")"

Python 2, 123 121 bytes
from random import*
def f(a,b,c):
 while c*b:
    r=randint(1,20);print r;c-=r<a;b-=r>=a
    if r in[1,20]:return r>9
 return c

(This answer mixes spaces and tabs, so the first indentation level is a single space, while the second is a single tab.)
The function f takes the following arguments:
a, the threshold for an individual die roll to count as a success,
b, the number of successes needed for overall success,
c, the number of failures needed for overall failure.
On each die roll either b or c is decremented (but not both).  As long as both are positive, it loops again, except in the case of critical failure or critical success.
Assuming no critical successes or failures, when the loop finishes either b or c will be zero, but not both.  In that case the function just returns the current value of c, which is zero (Falsey) if we exhausted all of our failures, and positive (Truthy) if we succeeded.
As a bonus, the output tells you how many failures you had remaining, which is nice in case there's (say) more locks to pick later.  (Unless it terminated at a critical failure or success, in which case the output will be a boolean instead of an int.)

Ruby 2.2, 75 bytes
f=->(v,s,f){p(r=rand(20)+1)<2?f=0:r>19?s=0:r<v ?f-=1:s-=1while s*f>0
p s<1}

Basic iterative solution.  Example run:
f[12, 5, 3]

Might output:
11
17
8
14
7
false

You can see it running on IDEONE here.

Makes me really jealous of langues where 0 is falsey!

 VBA 180 Bytes
Sub P(d,s,f):k=1
Do While x<s And v<f:r=Int(20*Rnd()+1)
If r=20 Then x=s
If r=1 Then v=f
If r>=d Then: x=x+1: Else: v=v+1
Debug.Print r:Loop:If v>=f Then k=0
Debug.Print k:End Sub

Example Output
P 12,5,3
 18
 2
 19
 8
 11
 0

The last Digit of output will be a 0 for False or a 1 for True . Each Roll is separated by a newline. This uses VBA built in RNG rnd() which is know for being Not So Random , But this should fulfill the requirements as best as possible.
Sub P(d,s,f)
k=1
Do While x<s And v<f               'Keep Rolling while Current Successes and Failures are less then the Maximum Allowed
r=Int(20*Rnd()+1)                'Creates a Randomish Number between 1 and 20
If r=20 Then x=s                   'Checks for Crit Success
If r=1 Then v=f                    'Checks for Crit Failure
If r>=d Then: x=x+1: Else: v=v+1   'Increments Current Success or Fails
Debug.Print r                      'Prints (Could us MSGBOX, it is shorter)
Loop
If v>=f Then k=0                   'Checks & Changes Total Outcome to False
Debug.Print k                      'Prints (Could us MSGBOX, it is shorter)
End Sub

SpecBAS - 165 bytes
1 INPUT d,s,f
2 DIM p(2)
3 DO
4 r=1+INT(RND*20): ?r
5 IF r IN [1,20] THEN EXIT
6 INC p((r>=d)+1)
7 LOOP UNTIL p(1)>=f OR p(2)>=s
8  ?IIF$(r=1 OR p(1)>=f,"fail","success")

Input should be entered in difficulty, successes, failures order.
The new release of SpecBAS now allows "?" instead of PRINT and removes the need for LET in front of variable assignments, so this was a nice way to try them out.
As arrays are 1-based by default, line 6 returns 0/1 if roll beats difficulty and adds 1 to update the right index.

Perl 6,  101  99 bytes
->$/ {(1..20).roll(*).map({$1*$2||last;$2-=$0>$_;$2=0 when 1;$1-=$_>=$0;$1=0 when 20;$_}).eager,$2}

# 101 bytes
->$/ {
  (1..20).roll(*).map({  # roll an infinite sequence, and map over them
    $1*$2||last;         # stop if either counter is 0
    $2-=$0>$_;           # decrement failure counter when a failure
    $2=0 when 1;         # set failure counter to 0  when a critical failure
    $1-=$_>=$0;          # decrement success counter when a success
    $1=0 when 20;        # set success counter to 0  when a critical success
    $_                   # the rolled value
  }).eager,$2            # the value of failure counter
}

Input is a mutable array containing difficulty, successes, failures
Output is a two element list, first element is a list of the rolled values, second element is the number of failures remaining.
Usage:
# give it a name for ease of use
my &code = {...}

for ^10 { say code [12, 5, 3] }

((14 4 15 5 5) 0)
((17 4 16 12 3 8) 0)
((2 14 14 7 14 19 19) 1)
((3 12 13 15 10 1) 0)
((3 17 16 10 11) 0)
((18 11 18 4 6) 0)
((15 13 1) 0)
((13 15 8 2 8) 0)
((16 17 8 10 11) 0)
((9 20) 2)