<commit_before>/**
 * Copyright (c) 2016 Virtue Studios
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions\:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

 var CookListener = Java.extend(Java.type('org.virtue.engine.script.listeners.EventListener'), {
	invoke : function (event, npcTypeId, args) {
		var player = args.player;
		var npc = args.npc;
		if (event == EventType.OPNPC1) {
			if(questApi.isFinished(player, 6)) {
			chatnpc(player, npc, "Hello, friend, how is the adventuring going?", function () {
			CookFinished.maintalk(player, npc);
			});
			} else if(questApi.isStarted(player, 6)) {
            chatnpc(player, npc, "How are you getting on with finding the ingredients?", function () {
			CookStarted.maintalk(player, npc);
			});
			}
			else {
			chatnpc(player, npc, "What am I to do?", function () {
			Cook.maintalk(player, npc);
			});
			}
		}
	}
});

  var CookFinished = {
       maintalk : function (player, npc) {
	   multi4(player, "SELECT AN OPTION", "I'm getting strong and mighty.", function () {
	   chatplayer(player, "I'm getting strong and mighty. Grr.", function () {
	   chatnpc(player, npc, "Glad to hear it.", function () {
	   });
	   });
	}, "I keep on dying.", function () {
	   chatplayer(player, "I keep on dying.", function () {
	   chatnpc(player, npc, "Ah, well, at least you keep coming back to life too!", function () {
	   });
	   });
    }, "Can i use your range?", function () {
	   chatplayer(player, "Can i use your range?", function () {
	   chatnpc(player, npc, "Go ahead! It's a very good range;it's better than most
 other ranges.", function () {
	   chatnpc(player, npc, "It's called the Cook-o-Matic 25 and it uses a combination
 of state-of-the-art temperature regulation and magic.", function () {
	   chatplayer(player, "will it mean my food will burn less often?", function () {
	   chatnpc(player, npc, "As long as the food is fairly easy to cook in the first place!", function () {

	 if(api.itemTotal(player, Inv.BACKPACK, 15411)) {
		 chatnpc(player, npc, "The manual you have in your inventory should tell you
 more.", function () {
	     chatplayer(player, "Thanks!", function () {
	     });
	     });
		 }
	else {
		chatnpc(player, npc, "Here, take this manual. It should tell you everything you
 need to know about this range.", function () {
	  //  chatitem(player, 15411, "The cook hands you a manual.", function () {//and add item to inv
		//	  });
		chatplayer(player, "Thanks!", function () {
	    });
		});
	}
	   });
	   });
	   });
	   });
	   });
	   }, "What happened to the castle?", function () {
		chatnpc(player, npc, "The castle really did suffer in the battle of Lumbridge. I'm
 glad it's over", function () {
		chatnpc(player, npc, "People came from all over the world to help rebuild, and
 now things are getting back to normal. I'm glad - I have
 important things to cook and I'm not letting anything get
 in the way!", function () {
		});
		});
		});
	},
}

  var CookStarted = {

       maintalk : function (player, npc) {

	},
}

 var Cook = {

	maintalk : function (player, npc) {
		multi5(player, "SELECT AN OPTION", "What's wrong?", function () {
		Cook.Whatswrong(player, npc);
		}, "Can you make me a cake?", function () {
		chatnpc(player, npc, "*sniff* Don't talk to me about cakes...", function () {
		Cook.Whatswrong(player, npc);
		});
		}, "You don't look very happy.", function () {
		chatnpc(player, npc, "No, I'm not. The world is caving in around me. I'm
 overcome with dark feelings of impending doom.", function () {
		multi2(player, "SELECT AN OPTION", "What's wrong?", function () {
		Cook.Whatswrong(player, npc);
		}, "I'd take the rest of the day off, if I were you.", function () {
	    chatnpc(player, npc, "No, that's the worst thing I could do. I'd get in terrible
 trouble.", function () {
		chatplayer(player, "Well, maybe you need to take a holiday...", function () {
		chatnpc(player, npc, "That would be nice, but the Duke doesn't allow holidays
 for core staff.", function () {
        chatplayer(player, "Hmm, why not run away to the sea and start a new life as
 a pirate?", function () {
        chatnpc(player, npc, "My wife gets seasick and I have an irrational fear of
 eyepatches. I don't see it working.", function () {
		chatplayer(player, "I'm afraid I've run out of ideas.", function () {
		chatnpc(player, npc, "I know, I'm doomed.", function () {
		Cook.Whatswrong(player, npc);
		});
		});
		});
		});
		});
		});
		});
	    });
		});
		}, "Nice hat!", function () {
		chatnpc(player, npc, "Er, thank you. It's a pretty ordinary cook's hat, really.", function () {
		chatplayer(player, "Still, it suits you. The trousers are pretty special too.", function () {
		chatnpc(player, npc, "It's all standard-issue cook's uniform.", function () {
		chatplayer(player, "The whole hat, apron and stripy trousers ensemble...it
 works. It makes you look like a real cook.", function () {
		chatnpc(player, npc, "I AM a real cook! I haven't got time to be chatting about culinary fashion, I'm in desperate need of help!", function () {
		Cook.Whatswrong(player, npc);
		});
		});
		});
		});
		});
		}, "What happened to the castle?", function () {
		chatnpc(player, npc, "The castle really did suffer in the battle of Lumbridge. I'm
 glad it's over", function () {
		chatnpc(player, npc, "People came from all over the world to help rebuild, and
 now things are getting back to normal. I'm glad - I have
 important things to cook and I'm not letting anything get
 in the way!", function () {
		chatnpc(player, npc, "In fact, even now I'm preparing a cake for the Duke's
 birthday! Although...umm...", function () {
		multi2(player, "SELECT AN OPTION", "What's the problem?", function () {
		Cook.Whatswrong(player, npc);
		}, "I'll let you get on with it!", function () {
		});
		});
		});
		});
		});
	},

	Whatswrong : function (player, npc) {
		chatnpc(player, npc, "Oh dear, oh dear, oh dear, I'm in a terrible, terrible mess!
 It's the Duke's birthday today, and I should be making him
 a lovely, big birthday cake using special ingredients...", function () {
		chatnpc(player, npc, "...but I've forgotten to get the ingredients. I'll never get
 them in time now. He'll sack me! Whatever will I do? I have
 four children and a goat to look after. Would you help me?
 Please?", function () {
        //start quest
		});
		});
	}

}

var CooksAssistant = {
		showQuestJournal : function (player, questLog) {
			if(questApi.isFinished(player, 6)) {
				questLog.setJournalLine(player, 1, "");
				questLog.setJournalLine(player, 2, "<col=999999>It was the Duke of Lumbridge's birthday, but his cook had forgotten to buy the");
				questLog.setJournalLine(player, 3, "<col=999999>ingredients he needed to bake a birthdat cake. I brought the cook an egg, a pot");
				questLog.setJournalLine(player, 4, "<col=999999>of flour and a bucket of milk and the cook made a delicious-looking cake with");
				questLog.setJournalLine(player, 5, "<col=999999>them");
				questLog.setJournalLine(player, 6, "");
				questLog.setJournalLine(player, 7, "<col=FFFFFF>QUEST COMPLETE!");
				questLog.setJournalLine(player, 8, "<col=EB981F>I gained <col=EBE076>1 Quest Point<col=EB981F>, <col=EBE076>20 sardines<col=EB981F>, <col=EBE076>500 coins <col=EB981F>and <col=EBE076> 300 Cooking XP<col=EB981F>.");
				questLog.setJournalLine(player, 9, "<col=EB981F>I have also gained <col=EBE076>two prize keys<col=EB981F> for <col=EBE076>Treasure Hunter<col=EB981F>!");
				questLog.setJournalLine(player, 10, "<col=EB981F>The cook now also lets me use his high-quality <col=EBE076>range<col=EB981F>, which burns certain low-");
				questLog.setJournalLine(player, 11, "<col=EB981F>level dishes less often thsn other ranges.");
			} else {
				questLog.setJournalLine(player, 1, "");
				questLog.setJournalLine(player, 2, "<col=EB981F>I can start this quest by speaking to the <col=EBE076>Cook<col=EB981F> in the <col=EBE076>kitchen<col=EB981F> of <col=EBE076>Lumbridge");
				questLog.setJournalLine(player, 3, "<col=EBE076>Castle<col=EB981F>.");
			}
		}
}

/* Listen to the npc ids specified */
var listen = function(scriptManager) {
	var listener = new CookListener();
	scriptManager.registerListener(EventType.OPNPC1, 278, listener);
};
<commit_msg>Update CooksAssistant.js<commit_after>/**
 * Copyright (c) 2016 Virtue Studios
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions\:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

 var CookListener = Java.extend(Java.type('org.virtue.engine.script.listeners.EventListener'), {
	invoke : function (event, npcTypeId, args) {
		var player = args.player;
		var npc = args.npc;
		if (event == EventType.OPNPC1) {
			if(questApi.isFinished(player, 6)) {
			chatnpc(player, npc, "Hello, friend, how is the adventuring going?", function () {
			CookFinished.maintalk(player, npc);
			});
			} else if(questApi.isStarted(player, 6)) {
            chatnpc(player, npc, "How are you getting on with finding the ingredients?", function () {
			CookStarted.maintalk(player, npc);
			});
			}
			else {
			chatnpc(player, npc, "What am I to do?", function () {
			Cook.maintalk(player, npc);
			});
			}
		}
	}
});

  var CookFinished = {
       maintalk : function (player, npc) {
	   multi4(player, "SELECT AN OPTION", "I'm getting strong and mighty.", function () {
	   chatplayer(player, "I'm getting strong and mighty. Grr.", function () {
	   chatnpc(player, npc, "Glad to hear it.", function () {
	   });
	   });
	}, "I keep on dying.", function () {
	   chatplayer(player, "I keep on dying.", function () {
	   chatnpc(player, npc, "Ah, well, at least you keep coming back to life too!", function () {
	   });
	   });
    }, "Can i use your range?", function () {
	   chatplayer(player, "Can i use your range?", function () {
	   chatnpc(player, npc, "Go ahead! It's a very good range;it's better than most
 other ranges.", function () {
	   chatnpc(player, npc, "It's called the Cook-o-Matic 25 and it uses a combination
 of state-of-the-art temperature regulation and magic.", function () {
	   chatplayer(player, "will it mean my food will burn less often?", function () {
	   chatnpc(player, npc, "As long as the food is fairly easy to cook in the first place!", function () {

	 if(api.itemTotal(player, Inv.BACKPACK, 15411)) {
		 chatnpc(player, npc, "The manual you have in your inventory should tell you
 more.", function () {
	     chatplayer(player, "Thanks!", function () {
	     });
	     });
		 }
	else {
		chatnpc(player, npc, "Here, take this manual. It should tell you everything you
 need to know about this range.", function () {
	  //  chatitem(player, 15411, "The cook hands you a manual.", function () {//and add item to inv
		//	  });
		chatplayer(player, "Thanks!", function () {
	    });
		});
	}
	   });
	   });
	   });
	   });
	   });
	   }, "What happened to the castle?", function () {
		chatnpc(player, npc, "The castle really did suffer in the battle of Lumbridge. I'm
 glad it's over", function () {
		chatnpc(player, npc, "People came from all over the world to help rebuild, and
 now things are getting back to normal. I'm glad - I have
 important things to cook and I'm not letting anything get
 in the way!", function () {
		});
		});
		});
	},
}

  var CookStarted = {

       maintalk : function (player, npc) {

	},
}

 var Cook = {

	maintalk : function (player, npc) {
		multi5(player, "SELECT AN OPTION", "What's wrong?", function () {
		Cook.Whatswrong(player, npc);
		}, "Can you make me a cake?", function () {
		chatnpc(player, npc, "*sniff* Don't talk to me about cakes...", function () {
		Cook.Whatswrong(player, npc);
		});
		}, "You don't look very happy.", function () {
		chatnpc(player, npc, "No, I'm not. The world is caving in around me. I'm
 overcome with dark feelings of impending doom.", function () {
		multi2(player, "SELECT AN OPTION", "What's wrong?", function () {
		Cook.Whatswrong(player, npc);
		}, "I'd take the rest of the day off, if I were you.", function () {
	    chatnpc(player, npc, "No, that's the worst thing I could do. I'd get in terrible
 trouble.", function () {
		chatplayer(player, "Well, maybe you need to take a holiday...", function () {
		chatnpc(player, npc, "That would be nice, but the Duke doesn't allow holidays
 for core staff.", function () {
        chatplayer(player, "Hmm, why not run away to the sea and start a new life as
 a pirate?", function () {
        chatnpc(player, npc, "My wife gets seasick and I have an irrational fear of
 eyepatches. I don't see it working.", function () {
		chatplayer(player, "I'm afraid I've run out of ideas.", function () {
		chatnpc(player, npc, "I know, I'm doomed.", function () {
		Cook.Whatswrong(player, npc);
		});
		});
		});
		});
		});
		});
		});
	    });
		});
		}, "Nice hat!", function () {
		chatnpc(player, npc, "Er, thank you. It's a pretty ordinary cook's hat, really.", function () {
		chatplayer(player, "Still, it suits you. The trousers are pretty special too.", function () {
		chatnpc(player, npc, "It's all standard-issue cook's uniform.", function () {
		chatplayer(player, "The whole hat, apron and stripy trousers ensemble...it
 works. It makes you look like a real cook.", function () {
		chatnpc(player, npc, "I AM a real cook! I haven't got time to be chatting about culinary fashion, I'm in desperate need of help!", function () {
		Cook.Whatswrong(player, npc);
		});
		});
		});
		});
		});
		}, "What happened to the castle?", function () {
		chatnpc(player, npc, "The castle really did suffer in the battle of Lumbridge. I'm
 glad it's over", function () {
		chatnpc(player, npc, "People came from all over the world to help rebuild, and
 now things are getting back to normal. I'm glad - I have
 important things to cook and I'm not letting anything get
 in the way!", function () {
		chatnpc(player, npc, "In fact, even now I'm preparing a cake for the Duke's
 birthday! Although...umm...", function () {
		multi2(player, "SELECT AN OPTION", "What's the problem?", function () {
		Cook.Whatswrong(player, npc);
		}, "I'll let you get on with it!", function () {
		});
		});
		});
		});
		});
	},

	Whatswrong : function (player, npc) {
		chatnpc(player, npc, "Oh dear, oh dear, oh dear, I'm in a terrible, terrible mess!
 It's the Duke's birthday today, and I should be making him
 a lovely, big birthday cake using special ingredients...", function () {
		chatnpc(player, npc, "...but I've forgotten to get the ingredients. I'll never get
 them in time now. He'll sack me! Whatever will I do? I have
 four children and a goat to look after. Would you help me?
 Please?", function () {
        //start quest
		});
		});
	}

}

var CooksAssistant = {
		showQuestJournal : function (player, questLog) {
			if(questApi.isFinished(player, 6)) {
				questLog.setJournalLine(player, 1, "");
				questLog.setJournalLine(player, 2, "<col=999999>It was the Duke of Lumbridge's birthday, but his cook had forgotten to buy the");
				questLog.setJournalLine(player, 3, "<col=999999>ingredients he needed to bake a birthdat cake. I brought the cook an egg, a pot");
				questLog.setJournalLine(player, 4, "<col=999999>of flour and a bucket of milk and the cook made a delicious-looking cake with");
				questLog.setJournalLine(player, 5, "<col=999999>them");
				questLog.setJournalLine(player, 6, "");
				questLog.setJournalLine(player, 7, "<col=FFFFFF>QUEST COMPLETE!");
				questLog.setJournalLine(player, 8, "<col=EB981F>I gained <col=EBE076>1 Quest Point<col=EB981F>, <col=EBE076>20 sardines<col=EB981F>, <col=EBE076>500 coins <col=EB981F>and <col=EBE076> 300 Cooking XP<col=EB981F>.");
				questLog.setJournalLine(player, 9, "<col=EB981F>I have also gained <col=EBE076>two prize keys<col=EB981F> for <col=EBE076>Treasure Hunter<col=EB981F>!");
				questLog.setJournalLine(player, 10, "<col=EB981F>The cook now also lets me use his high-quality <col=EBE076>range<col=EB981F>, which burns certain low-");
				questLog.setJournalLine(player, 11, "<col=EB981F>level dishes less often thsn other ranges.");
			} else {
				questLog.setJournalLine(player, 1, "");
				questLog.setJournalLine(player, 2, "<col=EB981F>I can start this quest by speaking to the <col=EBE076>Cook<col=EB981F> in the <col=EBE076>kitchen<col=EB981F> of <col=EBE076>Lumbridge");
				questLog.setJournalLine(player, 3, "<col=EBE076>Castle<col=EB981F>.");
			}
		}
}

var LocationListener = Java.extend(Java.type('org.virtue.engine.script.listeners.EventListener'), {
	invoke : function (event, locTypeId, args) {
		var player = args.player;
		var location = args.location;

		switch (locTypeId) {

case 47721:
if(questApi.isFinished(player, 6)) {
if(api.itemTotal(player, Inv.BACKPACK, 1925)) {
mesbox(player, "If you're after ordinary milk, you should use an ordinary dairy cow.");
} else {
api.sendMessage(player, "You'll need an empty bucket to collect the milk.");
}
} else if(questApi.isStarted(player, 6)) {

	if(api.itemTotal(player, Inv.BACKPACK, 15413)) {
	if(api.itemTotal(player, Inv.BACKPACK, 1925)) {
		api.sendMessage(player, "You've already got some top-quality milk; you should take it to the cook.");
		} else {
		api.sendMessage(player, "You'll need an empty bucket to collect the milk.");
		}
	} else {
	if(api.itemTotal(player, Inv.BACKPACK, 1925)) {
	api.runAnimation(player, 2305);
	//todo wait till end off anim then add items
		api.delCarriedItem(player, 1925,1);
		api.addCarriedItem(player, 15413,1);
  api.sendMessage(player, "You milk the cow for top-quality milk.");
	} else {
	api.sendMessage(player, "You'll need an empty bucket to collect the milk.");
	}
	}
} else {
if(api.itemTotal(player, Inv.BACKPACK, 1925)) {
mesbox(player, "If you're after ordinary milk, you should use an ordinary dairy cow.");
} else {
api.sendMessage(player, "You'll need an empty bucket to collect the milk.");
}

}

			return true;

default:
				return false;
		}
	}
});

/* Listen to the npc ids specified */
var listen = function(scriptManager) {
	var listener = new CookListener();
	scriptManager.registerListener(EventType.OPNPC1, 278, listener);

	var locs = [ 47721];
	var listener = new LocationListener();
	for (var i in locs) {
		scriptManager.registerListener(EventType.OPLOC1, locs[i], listener);
	}
};
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

MODEL({
  name: 'LabelArrayProperty',
  extendsModel: 'StringArrayProperty',

  help: "An array of String values, taken from labels.",

  properties: [
    {
      name: 'postSet',
      defaultValue: function(_, v, prop) {
        if ( ! Array.isArray(v) ) debugger;

        v.sort();

        feedback(this, 'labels', function() {
          this.replaceLabels(prop.name.capitalize(), v);
        });
      }
    },
    {
      name: 'compareProperty',
      defaultValue: function(o1, o2) {
        o1 = Array.isArray(o1) ? ( o1.length ? o1[o1.length-1] : 0 ) : o1;
        o2 = Array.isArray(o2) ? ( o2.length ? o2[o2.length-1] : 0 ) : o2;

        return o1.compareTo(o2);
      }
    },
    {
      name: 'transient',
      defaultValue: true
    }
  ]
});

MODEL({
  name: 'LabelStringProperty',
  extendsModel: 'StringProperty',

  help: "A String value, taken from labels.",

  properties: [
    {
      name: 'postSet',
      defaultValue: function(o, n, prop) {
        feedback(this, 'labels', function() {
          this.replaceLabels(prop.name.capitalize(), v);
        });

        // Test for LabelStringProperties that should be LabelArrayProperties.
        if ( o && o !== n ) debugger;
      }
    },
    {
      name: 'transient',
      defaultValue: true
    }
  ]
});

MODEL({
  name: 'LabelStringEnumProperty',
  extendsModel: 'LabelStringProperty',
  traits: ['EnumPropertyTrait']
});

GeneratedQIssue.properties.forEach(function(p) {
  if ( ! p["tableFormatter"] ) {
    p["tableFormatter"] = function(v) {
      return v || '----';
    };
  }
  if ( ! p["tableWidth"] ) {
    p["tableWidth"] = '80px;'
  }
});

<commit_msg>Fix LabelStringProperties update of the labels property.<commit_after>/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

MODEL({
  name: 'LabelArrayProperty',
  extendsModel: 'StringArrayProperty',

  help: "An array of String values, taken from labels.",

  properties: [
    {
      name: 'postSet',
      defaultValue: function(_, v, prop) {
        if ( ! Array.isArray(v) ) debugger;

        v.sort();

        feedback(this, 'labels', function() {
          this.replaceLabels(prop.name.capitalize(), v);
        });
      }
    },
    {
      name: 'compareProperty',
      defaultValue: function(o1, o2) {
        o1 = Array.isArray(o1) ? ( o1.length ? o1[o1.length-1] : 0 ) : o1;
        o2 = Array.isArray(o2) ? ( o2.length ? o2[o2.length-1] : 0 ) : o2;

        return o1.compareTo(o2);
      }
    },
    {
      name: 'transient',
      defaultValue: true
    }
  ]
});

MODEL({
  name: 'LabelStringProperty',
  extendsModel: 'StringProperty',

  help: "A String value, taken from labels.",

  properties: [
    {
      name: 'postSet',
      defaultValue: function(o, n, prop) {
        feedback(this, 'labels', function() {
          this.replaceLabels(prop.name.capitalize(), n);
        });

        // Test for LabelStringProperties that should be LabelArrayProperties.
        if ( o && o !== n ) debugger;
      }
    },
    {
      name: 'transient',
      defaultValue: true
    }
  ]
});

MODEL({
  name: 'LabelStringEnumProperty',
  extendsModel: 'LabelStringProperty',
  traits: ['EnumPropertyTrait']
});

GeneratedQIssue.properties.forEach(function(p) {
  if ( ! p["tableFormatter"] ) {
    p["tableFormatter"] = function(v) {
      return v || '----';
    };
  }
  if ( ! p["tableWidth"] ) {
    p["tableWidth"] = '80px;'
  }
});

<|endoftext|>


<commit_before>const Asset = require('@maxdome/request-maxdome').Asset;

module.exports = {
  detect: data => data instanceof Asset,
  from: 'asset',
  to: 'schema.org',
  run: asset => {
    const data = {
      '@context': 'http://schema.org',
      '@type': {
        episode: 'TVEpisode',
        movie: 'Movie',
        season: 'TVSeason',
        series: 'TVSeries',
      }[asset.type],
      '@id': asset.url,
      name: asset.title,
      url: asset.getCanonicalURL(),
      description: asset.description,
      potentialAction: [
        {
          '@type': 'WatchAction',
          target: {
            '@type': 'EntryPoint',
            urlTemplate: `${asset.url}?autoplay=true`,
            inLanguage: 'de',
            actionPlatform: [
              'http://schema.googleapis.com/GoogleVideoCast',
              'http://schema.org/DesktopWebPlatform',
              'http://schema.org/MobileWebPlatform',
              'http://schema.org/IOSPlatform',
              'http://schema.org/AndroidPlatform',
            ],
          },
          expectsAcceptanceOf: [
            {
              '@type': 'Offer',
              category: 'subscription',
              availabilityStarts: '1970-01-01T00:00+02:00',
              availabilityEnds: '2020-01-01T00:00+02:00',
              eligibleRegion: [
                {
                  '@type': 'Country',
                  name: 'DE',
                },
                {
                  '@type': 'Country',
                  name: 'AT',
                },
              ],
              seller: {
                '@type': 'Organization',
                name: 'maxdome',
              },
            },
          ],
        },
      ],
      actor: (asset.actors || []).map(actor => ({ '@type': 'Person', name: actor.name })),
      director: (asset.directors || []).map(director => ({ '@type': 'Person', name: director.name })),
    };

    if (asset.image) {
      const image = asset.getImage();
      data.image = {
        '@type': 'ImageObject',
        height: '' + image.height,
        url: image.url,
        width: '' + image.width,
      };
    }

    if (asset.type === 'episode') {
      data.name = asset.episodeTitle || `Staffel ${asset.seasonNumber} Episode ${asset.episodeNumber}`;
      data.episodeNumber = +asset.episodeNumber;
      data.partOfSeason = {
        '@type': 'TVSeason',
        '@id': `${asset.protocol}://${asset.hostnames.package}/${asset.seasonId}`,
        seasonNumber: +asset.seasonNumber,
      };
      data.partOfSeries = {
        '@type': 'TVSeries',
        '@id': `${asset.protocol}://${asset.hostnames.package}/${asset.seriesId}`,
        name: asset.title,
      };
    }

    if (asset.type === 'movie') {
      data.duration = `PT${parseInt(asset.duration / 60)}H${asset.duration % 60}M`;
    }

    if (asset.type === 'season') {
      delete data.name;
      data.seasonNumber = +asset.seasonNumber;
      data.partOfSeries = {
        '@type': 'TVSeries',
        '@id': `${asset.protocol}://${asset.hostnames.package}/${asset.seriesId}`,
        name: asset.title.replace(/ \(.*\)/, ''),
      };
    }

    if (['season', 'series'].includes(asset.type)) {
      data.potentialAction.push({
        '@type': 'ViewAction',
        target: {
          '@type': 'EntryPoint',
          urlTemplate: asset.url,
          inLanguage: 'de',
          actionPlatform: [
            'http://schema.org/DesktopWebPlatform',
            'http://schema.org/MobileWebPlatform',
            'http://schema.org/IOSPlatform',
            'http://schema.org/AndroidPlatform',
          ],
        },
      });
    }

    if (data.actor.length === 0) {
      delete data.actor;
    }

    if (data.director.length === 0) {
      delete data.director;
    }

    return data;
  },
};
<commit_msg>Add deeplink template url for iOS and Android in asset.schema.org transformer<commit_after>const Asset = require('@maxdome/request-maxdome').Asset;

module.exports = {
  detect: data => data instanceof Asset,
  from: 'asset',
  to: 'schema.org',
  run: asset => {
    const data = {
      '@context': 'http://schema.org',
      '@type': {
        episode: 'TVEpisode',
        movie: 'Movie',
        season: 'TVSeason',
        series: 'TVSeries',
      }[asset.type],
      '@id': asset.url,
      name: asset.title,
      url: asset.getCanonicalURL(),
      description: asset.description,
      potentialAction: [
        {
          '@type': 'WatchAction',
          target: [
            {
              '@type': 'EntryPoint',
              urlTemplate: `${asset.url}?autoplay=true`,
              inLanguage: 'de',
              actionPlatform: [
                'http://schema.googleapis.com/GoogleVideoCast',
                'http://schema.org/DesktopWebPlatform',
                'http://schema.org/MobileWebPlatform',
              ],
            },
            {
              '@type': 'EntryPoint',
              urlTemplate: `maxdome://${asset.type}/${asset.id}/play`,
              inLanguage: 'de',
              actionPlatform: [
                'http://schema.org/IOSPlatform',
                'http://schema.org/AndroidPlatform',
              ],
            },
          ],
          expectsAcceptanceOf: [
            {
              '@type': 'Offer',
              category: 'subscription',
              availabilityStarts: '1970-01-01T00:00+02:00',
              availabilityEnds: '2020-01-01T00:00+02:00',
              eligibleRegion: [
                {
                  '@type': 'Country',
                  name: 'DE',
                },
                {
                  '@type': 'Country',
                  name: 'AT',
                },
              ],
              seller: {
                '@type': 'Organization',
                name: 'maxdome',
              },
            },
          ],
        },
      ],
      actor: (asset.actors || []).map(actor => ({ '@type': 'Person', name: actor.name })),
      director: (asset.directors || []).map(director => ({ '@type': 'Person', name: director.name })),
    };

    if (asset.image) {
      const image = asset.getImage();
      data.image = {
        '@type': 'ImageObject',
        height: '' + image.height,
        url: image.url,
        width: '' + image.width,
      };
    }

    if (asset.type === 'episode') {
      data.name = asset.episodeTitle || `Staffel ${asset.seasonNumber} Episode ${asset.episodeNumber}`;
      data.episodeNumber = +asset.episodeNumber;
      data.partOfSeason = {
        '@type': 'TVSeason',
        '@id': `${asset.protocol}://${asset.hostnames.package}/${asset.seasonId}`,
        seasonNumber: +asset.seasonNumber,
      };
      data.partOfSeries = {
        '@type': 'TVSeries',
        '@id': `${asset.protocol}://${asset.hostnames.package}/${asset.seriesId}`,
        name: asset.title,
      };
    }

    if (asset.type === 'movie') {
      data.duration = `PT${parseInt(asset.duration / 60)}H${asset.duration % 60}M`;
    }

    if (asset.type === 'season') {
      delete data.name;
      data.seasonNumber = +asset.seasonNumber;
      data.partOfSeries = {
        '@type': 'TVSeries',
        '@id': `${asset.protocol}://${asset.hostnames.package}/${asset.seriesId}`,
        name: asset.title.replace(/ \(.*\)/, ''),
      };
    }

    if (['season', 'series'].includes(asset.type)) {
      data.potentialAction.push({
        '@type': 'ViewAction',
        target: [
          {
            '@type': 'EntryPoint',
            urlTemplate: asset.url,
            inLanguage: 'de',
            actionPlatform: [
              'http://schema.org/DesktopWebPlatform',
              'http://schema.org/MobileWebPlatform',
            ],
          },
          {
            '@type': 'EntryPoint',
            urlTemplate: `maxdome://${asset.type}/${asset.id}`,
            inLanguage: 'de',
            actionPlatform: [
              'http://schema.org/IOSPlatform',
              'http://schema.org/AndroidPlatform',
            ],
          }
        ],
      });
    }

    if (data.actor.length === 0) {
      delete data.actor;
    }

    if (data.director.length === 0) {
      delete data.director;
    }

    return data;
  },
};
<|endoftext|>


<commit_before>var _ = require('underscore');
var specHelper = require('../../spec-helper');
var HistogramContentView = require('../../../src/widgets/histogram/content-view');
var HistogramWidgetModel = require('../../../src/widgets/histogram/histogram-widget-model');

describe('widgets/histogram/content-view', function () {
  beforeEach(function () {
    var vis = specHelper.createDefaultVis();
    this.dataviewModel = vis.dataviews.createHistogramModel(vis.map.layers.first(), {
      id: 'widget_3',
      column: 'col'
    });

    this.widgetModel = new HistogramWidgetModel({
      title: 'Howdy'
    }, {
      dataviewModel: this.dataviewModel
    });

    this.view = new HistogramContentView({
      model: this.widgetModel,
      dataviewModel: this.dataviewModel
    });
  });

  it('should render the histogram', function () {
    spyOn(this.view, 'render').and.callThrough();
    this.dataviewModel._data.reset(genHistogramData(20));
    this.dataviewModel.trigger('change:data');
    expect(this.view.render).toHaveBeenCalled();
    expect(this.view.$('h3').text()).toBe('Howdy');
  });

  it('should revert the lockedByUser state when the model is changed', function () {
    spyOn(this.view, '_unsetRange').and.callThrough();

    this.dataviewModel.sync = function (method, model, options) {
      options.success({ 'response': true });
    };

    this.widgetModel.set('zoomed', true);
    this.dataviewModel.fetch();

    expect(this.view._unsetRange).not.toHaveBeenCalled();

    this.view.lockedByUser = true;
    this.dataviewModel.set('url', 'test');

    expect(this.view.lockedByUser).toBe(true);
  });

  it("shouldn't revert the lockedByUser state when the url is changed and the histogram is zoomed", function () {
    this.dataviewModel.sync = function (method, model, options) {
      options.success({ 'response': true });
    };

    this.view.lockedByUser = true;
    this.dataviewModel.fetch();
    this.dataviewModel.trigger('change:data');
    expect(this.view.lockedByUser).toBe(false);
  });

  it('should unset the range when the data is changed', function () {
    this.dataviewModel.sync = function (method, model, options) {
      options.success({ 'response': true });
    };

    spyOn(this.view, '_unsetRange').and.callThrough();
    this.view.unsettingRange = true;
    this.dataviewModel.fetch();
    this.dataviewModel._data.reset(genHistogramData(20));
    this.dataviewModel.trigger('change:data');
    expect(this.view._unsetRange).toHaveBeenCalled();
  });

  it("shouldn't unset the range when the url is changed and is zoomed", function () {
    spyOn(this.view, '_unsetRange').and.callThrough();

    this.dataviewModel.sync = function (method, model, options) {
      options.success({ 'response': true });
    };

    this.widgetModel.set('zoomed', true);
    this.dataviewModel.fetch();

    expect(this.view._unsetRange).not.toHaveBeenCalled();

    this.view.unsettingRange = true;
    this.dataviewModel.set('url', 'test');

    expect(this.view._unsetRange).not.toHaveBeenCalled();
  });

  it('should update the stats when the model is changed', function () {
    this.dataviewModel.sync = function (method, model, options) {
      options.success({ 'response': true });
    };

    spyOn(this.view, '_updateStats').and.callThrough();
    spyOn(this.view, '_onHistogramDataChanged').and.callThrough();
    this.dataviewModel.fetch();
    this.dataviewModel._data.reset(genHistogramData(20));
    this.dataviewModel.trigger('change:data');
    expect(this.view._onHistogramDataChanged).toHaveBeenCalled();
    expect(this.view._updateStats).toHaveBeenCalled();
  });

  it('should enable and disable filters on the dataviewModel when zooming in and out', function () {
    var histogramData = {
      'bin_width': 10,
      'bins_count': 2,
      'bins_start': 1,
      'nulls': 0,
      'bins': []
    };

    this.dataviewModel.sync = function (method, model, options) {
      options.success(histogramData);
    };

    this.dataviewModel.fetch();

    expect(this.dataviewModel.get('start')).toEqual(1);
    expect(this.dataviewModel.get('end')).toEqual(21);
    expect(this.dataviewModel.get('bins')).toEqual(2);

    spyOn(this.dataviewModel, 'enableFilter');

    // Click ZOOM
    this.view.$el.find('.js-zoom').click();

    expect(this.dataviewModel.enableFilter).toHaveBeenCalled();

    spyOn(this.dataviewModel, 'disableFilter');

    // Click CLEAR
    this.view.$el.find('.js-clear').click();

    expect(this.dataviewModel.disableFilter).toHaveBeenCalled();
  });

  it('should replace the data of the histogramChartView when user zooms in', function () {
    var i = 0;
    this.dataviewModel.sync = function (method, model, options) {
      options.success({
        'bin_width': 10,
        'bins_count': 2,
        'bins_start': i++,
        'nulls': 0,
        'bins': []
      });
    };

    this.dataviewModel.fetch();

    spyOn(this.view.histogramChartView, 'replaceData');

    // Click ZOOM
    this.view.$el.find('.js-zoom').click();

    expect(this.view.histogramChartView.replaceData).toHaveBeenCalled();
  });

  it('should update the stats values', function () {
    expect(this.widgetModel.get('min')).toBe(undefined);
    expect(this.widgetModel.get('max')).toBe(undefined);
    expect(this.widgetModel.get('avg')).toBe(undefined);
    expect(this.widgetModel.get('total')).toBe(undefined);

    this.dataviewModel._data.reset(genHistogramData(20));
    this.dataviewModel.trigger('change:data');

    expect(this.widgetModel.get('min')).not.toBe(0);
    expect(this.widgetModel.get('max')).not.toBe(0);
    expect(this.widgetModel.get('avg')).not.toBe(0);
    expect(this.widgetModel.get('total')).not.toBe(0);
  });

  it('should show stats when show_stats is true', function () {
    expect(this.view.$('.CDB-Widget-info').length).toBe(0);
    this.widgetModel.set('show_stats', true);
    this.view.render();
    expect(this.view.$('.CDB-Widget-info').length).toBe(1);
  });

  afterEach(function () {
    this.view.clean();
  });
});

function genHistogramData (n) {
  n = n || 1;
  var arr = [];
  _.times(n, function (i) {
    var start = (100 * i) + Math.round(Math.random() * 1000);
    var end = start + 100;
    var obj = {
      bin: i,
      freq: Math.round(Math.random() * 10),
      avg: Math.round(Math.random() * 10),
      start: start,
      end: end,
      max: end,
      min: start
    };
    arr.push(obj);
  });
  return arr;
}
<commit_msg>Adding spec for miniHistogramChar data update<commit_after>var _ = require('underscore');
var specHelper = require('../../spec-helper');
var HistogramContentView = require('../../../src/widgets/histogram/content-view');
var HistogramWidgetModel = require('../../../src/widgets/histogram/histogram-widget-model');

describe('widgets/histogram/content-view', function () {
  beforeEach(function () {
    var vis = specHelper.createDefaultVis();
    this.dataviewModel = vis.dataviews.createHistogramModel(vis.map.layers.first(), {
      id: 'widget_3',
      column: 'col'
    });

    this.widgetModel = new HistogramWidgetModel({
      title: 'Howdy'
    }, {
      dataviewModel: this.dataviewModel
    });

    this.view = new HistogramContentView({
      model: this.widgetModel,
      dataviewModel: this.dataviewModel
    });
  });

  it('should render the histogram', function () {
    spyOn(this.view, 'render').and.callThrough();
    this.dataviewModel._data.reset(genHistogramData(20));
    this.dataviewModel.trigger('change:data');
    expect(this.view.render).toHaveBeenCalled();
    expect(this.view.$('h3').text()).toBe('Howdy');
  });

  it('should revert the lockedByUser state when the model is changed', function () {
    spyOn(this.view, '_unsetRange').and.callThrough();

    this.dataviewModel.sync = function (method, model, options) {
      options.success({ 'response': true });
    };

    this.widgetModel.set('zoomed', true);
    this.dataviewModel.fetch();

    expect(this.view._unsetRange).not.toHaveBeenCalled();

    this.view.lockedByUser = true;
    this.dataviewModel.set('url', 'test');

    expect(this.view.lockedByUser).toBe(true);
  });

  it("shouldn't revert the lockedByUser state when the url is changed and the histogram is zoomed", function () {
    this.dataviewModel.sync = function (method, model, options) {
      options.success({ 'response': true });
    };

    this.view.lockedByUser = true;
    this.dataviewModel.fetch();
    this.dataviewModel.trigger('change:data');
    expect(this.view.lockedByUser).toBe(false);
  });

  it('should unset the range when the data is changed', function () {
    this.dataviewModel.sync = function (method, model, options) {
      options.success({ 'response': true });
    };

    spyOn(this.view, '_unsetRange').and.callThrough();
    this.view.unsettingRange = true;
    this.dataviewModel.fetch();
    this.dataviewModel._data.reset(genHistogramData(20));
    this.dataviewModel.trigger('change:data');
    expect(this.view._unsetRange).toHaveBeenCalled();
  });

  it("shouldn't unset the range when the url is changed and is zoomed", function () {
    spyOn(this.view, '_unsetRange').and.callThrough();

    this.dataviewModel.sync = function (method, model, options) {
      options.success({ 'response': true });
    };

    this.widgetModel.set('zoomed', true);
    this.dataviewModel.fetch();

    expect(this.view._unsetRange).not.toHaveBeenCalled();

    this.view.unsettingRange = true;
    this.dataviewModel.set('url', 'test');

    expect(this.view._unsetRange).not.toHaveBeenCalled();
  });

  it('should update the stats when the model is changed', function () {
    this.dataviewModel.sync = function (method, model, options) {
      options.success({ 'response': true });
    };

    spyOn(this.view, '_updateStats').and.callThrough();
    spyOn(this.view, '_onHistogramDataChanged').and.callThrough();
    this.dataviewModel.fetch();
    this.dataviewModel._data.reset(genHistogramData(20));
    this.dataviewModel.trigger('change:data');
    expect(this.view._onHistogramDataChanged).toHaveBeenCalled();
    expect(this.view._updateStats).toHaveBeenCalled();
  });

  it('should enable and disable filters on the dataviewModel when zooming in and out', function () {
    var histogramData = {
      'bin_width': 10,
      'bins_count': 2,
      'bins_start': 1,
      'nulls': 0,
      'bins': []
    };

    this.dataviewModel.sync = function (method, model, options) {
      options.success(histogramData);
    };

    this.dataviewModel.fetch();

    expect(this.dataviewModel.get('start')).toEqual(1);
    expect(this.dataviewModel.get('end')).toEqual(21);
    expect(this.dataviewModel.get('bins')).toEqual(2);

    spyOn(this.dataviewModel, 'enableFilter');

    // Click ZOOM
    this.view.$el.find('.js-zoom').click();

    expect(this.dataviewModel.enableFilter).toHaveBeenCalled();

    spyOn(this.dataviewModel, 'disableFilter');

    // Click CLEAR
    this.view.$el.find('.js-clear').click();

    expect(this.dataviewModel.disableFilter).toHaveBeenCalled();
  });

  it('should replace the data of the histogramChartView when user zooms in', function () {
    var i = 0;
    this.dataviewModel.sync = function (method, model, options) {
      options.success({
        'bin_width': 10,
        'bins_count': 2,
        'bins_start': i++,
        'nulls': 0,
        'bins': []
      });
    };

    this.dataviewModel.fetch();

    spyOn(this.view.histogramChartView, 'replaceData');

    // Click ZOOM
    this.view.$el.find('.js-zoom').click();

    expect(this.view.histogramChartView.replaceData).toHaveBeenCalled();
  });

  it('should update the stats values', function () {
    expect(this.widgetModel.get('min')).toBe(undefined);
    expect(this.widgetModel.get('max')).toBe(undefined);
    expect(this.widgetModel.get('avg')).toBe(undefined);
    expect(this.widgetModel.get('total')).toBe(undefined);

    this.dataviewModel._data.reset(genHistogramData(20));
    this.dataviewModel.trigger('change:data');

    expect(this.widgetModel.get('min')).not.toBe(0);
    expect(this.widgetModel.get('max')).not.toBe(0);
    expect(this.widgetModel.get('avg')).not.toBe(0);
    expect(this.widgetModel.get('total')).not.toBe(0);
  });

  it('should show stats when show_stats is true', function () {
    expect(this.view.$('.CDB-Widget-info').length).toBe(0);
    this.widgetModel.set('show_stats', true);
    this.view.render();
    expect(this.view.$('.CDB-Widget-info').length).toBe(1);
  });

  it('should update data of the mini histogram if there is a bins change and it is not zoomed', function () {
    var i = 0;
    this.dataviewModel.sync = function (method, model, options) {
      options.success({
        'bin_width': 10,
        'bins_count': 2,
        'bins_start': i++,
        'nulls': 0,
        'bins': []
      });
    };

    this.dataviewModel.fetch();

    spyOn(this.view, '_isZoomed').and.returnValue(false);
    spyOn(this.view.miniHistogramChartView, 'replaceData');
    // Change data
    this.dataviewModel.update({ bins: 10});
    expect(this.view.miniHistogramChartView.replaceData).toHaveBeenCalled();
  });

  afterEach(function () {
    this.view.clean();
  });
});

function genHistogramData (n) {
  n = n || 1;
  var arr = [];
  _.times(n, function (i) {
    var start = (100 * i) + Math.round(Math.random() * 1000);
    var end = start + 100;
    var obj = {
      bin: i,
      freq: Math.round(Math.random() * 10),
      avg: Math.round(Math.random() * 10),
      start: start,
      end: end,
      max: end,
      min: start
    };
    arr.push(obj);
  });
  return arr;
}
<|endoftext|>


<commit_before>'use strict';

var chalk = require('chalk');
var symbol = require('log-symbols');
var through = require('through2');
var utils = require('../utils');
var _ = require('lodash');

module.exports = function() {
  var verb = this;

  var conflicts = verb.get('argv.conflicts');
  var verbose = verb.get('argv.verbose');

  if (conflicts && verbose) {
    console.log();
    console.log(chalk.yellow('Checking for conflicts…'));
  }

  return through.obj(function (file, enc, cb) {
    if (file.isNull()) {
      this.push(file);
      return cb();
    }

    if (file.isStream()) {
      this.emit('error', new utils.PluginError('conflicts plugin', 'Streaming is not supported.'));
      return cb();
    }

    var str = file.contents.toString();
    var res = helpers(str);
    var conflicting = problematic(verb, file, res, verbose);
    var h = {};

    if (!conflicting.length) {
      this.push(file);
      return cb();
    }

    var ctx = {};
    ctx.options = _.extend({}, verb.options, file.options);
    ctx.context = file.locals || {};
    ctx.app = verb;

    file.locals = file.locals || {};
    file.locals.__ = file.locals.__ || {};

    for (var i = 0; i < conflicting.length; i++) {
      var name = conflicting[i];
      file.content = namespace(file.content, name);
      var syncFn = verb._.helpers[name];
      if (syncFn) {
        h[name] = _.bind(syncFn, ctx);
        file.locals.__[name] = _.bind(syncFn, ctx);
        verb.helpers({__: h});
        delete verb._.helpers[name];
      }

      var asyncFn = verb._.asyncHelpers[name];
      if (asyncFn) {
        h[name] = _.bind(asyncFn, ctx);
        file.locals.__[name] = _.bind(asyncFn, ctx);
        verb.asyncHelpers({__: h});
        delete verb._.asyncHelpers[name];
      }

      if (!asyncFn && !syncFn) {
        h[name] = noop(name);
        file.locals.__[name] = noop(name);
        verb.helpers({__: h});
      }
    }

    file.contents = new Buffer(file.content);
    this.push(file);
    cb();
  });
};

function noop(name) {
  return function () {
    var msg = '';
    msg += 'ERROR! Cannot find the {%= ';
    msg += name;
    msg += '() %} helper. Helpers may be ';
    msg += 'registered using `verb.helper()`.';
    // console.log(chalk.red(msg));
  };
}

function namespace(str, name) {
  return str.split('{%= ' + name).join('{%= __.' + name);
}

function helpers(str) {
  var re = /\{%=\s*((?!__\.)[\w.]+)(?:\(\)|\(([^)]*?)\))\s*%}/gm;
  var res = [], match;

  while (match = re.exec(str)) {
    if (res.indexOf(match[1]) === -1) {
      res.push(match[1].trim());
    }
  }
  return res;
}

function problematic(verb, file, helpers, verbose) {
  var dataKeys = Object.keys(verb.cache.data);
  dataKeys = _.union(dataKeys, Object.keys(file.data));

  var registered = Object.keys(verb._.asyncHelpers);
  registered = _.union(registered, Object.keys(verb._.helpers));

  var h = [], d = [];
  var len = helpers.length;

  while (len--) {
    var helper = helpers[len];
    // if the helper name is also a data prop, it's a conflict
    if (dataKeys.indexOf(helper) !== -1) {
      d.push(helper);
    }

    // if the helper is not registered, it's a conflict
    if (registered.indexOf(helper) === -1) {
      h.push(helper);
    }
  }

  message(h, d, verbose, file);
  return _.union(h, d);
}

function message(h, d, verbose, file) {
  if (!verbose) return;
  var fp = file.path.split(/[\\\/]/).slice(-2).join('/');

  var hlen = h.length;
  var dlen = d.length;

  if (hlen > 0) {
    console.log(' ', symbol.error, chalk.red(hlen + ' missing helper' + s(hlen) + ' found in', fp));
    h.forEach(function (ele) {
      console.log(' - ' + ele);
    });
  }

  if (dlen > 0) {
    console.log(' ', symbol.error, chalk.red(dlen + ' conflict' + s(dlen) + ' found in', fp));
    d.forEach(function (ele) {
      console.log('  -', ele, chalk.gray('(found both a helper and a data property with this name)'));
    });
  }
}

function s(len) {
  return len > 1 ? 's' : '';
}
<commit_msg>improve logging<commit_after>'use strict';

var chalk = require('chalk');
var symbol = require('log-symbols');
var through = require('through2');
var utils = require('../utils');
var _ = require('lodash');

module.exports = function() {
  var verb = this;

  var conflicts = verb.get('argv.conflicts');
  var verbose = verb.get('argv.verbose');

  if (conflicts && verbose) {
    console.log();
    console.log(chalk.yellow('Checking for conflicts…'));
  }

  return through.obj(function (file, enc, cb) {
    if (file.isNull()) {
      this.push(file);
      return cb();
    }

    if (file.isStream()) {
      this.emit('error', new utils.PluginError('conflicts plugin', 'Streaming is not supported.'));
      return cb();
    }

    var str = file.contents.toString();
    var res = helpers(str);
    var conflicting = problematic(verb, file, res, verbose);
    var h = {};

    if (!conflicting.length) {
      this.push(file);
      return cb();
    }

    var ctx = {};
    ctx.options = _.extend({}, verb.options, file.options);
    ctx.context = file.locals || {};
    ctx.app = verb;

    file.locals = file.locals || {};
    file.locals.__ = file.locals.__ || {};

    for (var i = 0; i < conflicting.length; i++) {
      var name = conflicting[i];
      file.content = namespace(file.content, name);
      var syncFn = verb._.helpers[name];
      if (syncFn) {
        h[name] = _.bind(syncFn, ctx);
        file.locals.__[name] = _.bind(syncFn, ctx);
        verb.helpers({__: h});
        delete verb._.helpers[name];
      }

      var asyncFn = verb._.asyncHelpers[name];
      if (asyncFn) {
        h[name] = _.bind(asyncFn, ctx);
        file.locals.__[name] = _.bind(asyncFn, ctx);
        verb.asyncHelpers({__: h});
        delete verb._.asyncHelpers[name];
      }

      if (!asyncFn && !syncFn) {
        h[name] = noop(name);
        file.locals.__[name] = noop(name);
        verb.helpers({__: h});
      }
    }

    file.contents = new Buffer(file.content);
    this.push(file);
    cb();
  });
};

function noop(name) {
  return function () {
    var msg = '';
    msg += 'ERROR! Cannot find the {%= ';
    msg += name;
    msg += '() %} helper. Helpers may be ';
    msg += 'registered using `verb.helper()`.';
    // console.log(chalk.red(msg));
  };
}

function namespace(str, name) {
  return str.split('{%= ' + name).join('{%= __.' + name);
}

function helpers(str) {
  var re = /\{%=\s*((?!__\.)[\w.]+)(?:\(\)|\(([^)]*?)\))\s*%}/gm;
  var res = [], match;

  while (match = re.exec(str)) {
    if (res.indexOf(match[1]) === -1) {
      res.push(match[1].trim());
    }
  }
  return res;
}

function problematic(verb, file, helpers, verbose) {
  var dataKeys = Object.keys(verb.cache.data);
  dataKeys = _.union(dataKeys, Object.keys(file.data));

  var registered = Object.keys(verb._.asyncHelpers);
  registered = _.union(registered, Object.keys(verb._.helpers));

  var h = [], d = [];
  var len = helpers.length;

  while (len--) {
    var helper = helpers[len];
    // if the helper name is also a data prop, it's a conflict
    if (dataKeys.indexOf(helper) !== -1) {
      d.push(helper);
    }

    // if the helper is not registered, it's a conflict
    if (registered.indexOf(helper) === -1) {
      h.push(helper);
    }
  }

  message(h, d, verbose, file);
  return _.union(h, d);
}

function message(h, d, verbose, file) {
  if (!verbose) return;
  var fp = file.path.split(/[\\\/]/).slice(-2).join('/');

  var hlen = h.length;
  var dlen = d.length;

  if (hlen > 0) {
    console.log(symbol.error, '', chalk.red(hlen + ' missing helper' + s(hlen) + ' found in', fp));
    h.forEach(function (ele) {
      console.log('   -', ele);
    });
    console.log();
  }

  if (dlen > 0) {
    console.log(symbol.warning, '', chalk.yellow(dlen + ' data/helper conflict' + s(dlen) + ' found in', fp));
    d.forEach(function (ele) {
      console.log('   -', ele);
    });
    console.log();
  }
}

function s(len) {
  return len > 1 ? 's' : '';
}
<|endoftext|>


<commit_before>'use strict';

//const sendInterviewTimes = require('./utils/app.js').sendInterviewTimes;
const cleanPayload = require('./utils/app.js').cleanPayload;
const client = require('../db/client.js');
const getInterviewDetails = require('../db/redis/getInterviewDetails.js');
const moveToNextInterviewStage = require('../db/redis/moveToNextInterviewStage');
const uuid = require('uuid');

const mailgun = require('./utils/mailgun.js');
const interviewConfirmation = require('./utils/mailgun.js').interviewConfirmation;

exports.register = (server, options, next) => {

    server.route([

        {
            method: 'POST',
            path: '/interview/proposed',
            config: {
                auth: {
                    strategy: 'hrns-cookie'
                    // scope: ['client', 'agent']
                },
                handler: (request, reply) => {
                    ///  must update stage in db;
                    const interview = request.payload;

                    const interviewId = uuid.v1() + 'interviewId';
                    interview.interviewId = interviewId;
                    interview.confirmed = false;

                    getInterviewDetails(interview, (interviewData) => {
                        if (interviewData) {
                            mailgun.proposedInterview.to = interviewData.agencyEmail;
                            mailgun.proposedInterview.html = mailgun.proposedInterview.html
                                .replace('-candidateName-', interview.candidateName)
                                .replace('-jobTitle-', interview.jobTitle)
                                .replace('-companyName-', interview.companyName)
                                .replace('-interviewId-', interview.interviewId);

                            mailgun.messages().send(mailgun.proposedInterview, (error, body) => {
                                if (error) {
                                    console.log(error);
                                } else {
                                    console.log(body);
                                    console.log('Interview', interviewData);
                                    client.hmset(interviewId, interviewData, (err,res) => {  ///HMSET contains an undefined vlaue.
                                        if(err){
                                            console.log('err', err);
                                            return reply(false);
                                        }
                                        if(res){
                                            console.log('res',res);
                                            return reply(true);
                                        }
                                    });

                                }
                            });

                        } else {
                            return reply(false);
                        }

                    });

                }
            }
        }, {
            method: 'GET',
            path: '/interview/confirmation/{interviewId}', /// route for email response.
            config: {
                auth: {
                    strategy: 'hrns-cookie'
                    // scope: ['client', 'agency','admin']
                },
                plugins: { 'hapi-auth-cookie': { redirectTo: false } },
                handler: (request, reply) => {
                    let layout = { layout: 'default' };
                    let opts = {};

                    let interviewId = request.params.interviewId;

                    client.hgetall(interviewId, (err, res) => {

                        if ((res) && (res.confirmed === 'false')) {
                            opts = res;

                            opts.interviewId = interviewId;
                            opts.title = 'Interview Page';
                            let cleanedPayload = cleanPayload(opts);
                            return reply.view('interview', cleanedPayload, layout);

                        } else {

                            opts.title = 'Interview Page';
                            opts.message = 'This link has expired';
                            return reply.view('message', opts, layout);
                        }

                    });

                }
            }
        }, {
            method: 'POST',
            path: '/change/interview',
            config: {
                auth: {
                    strategy: 'hrns-cookie'
                    // scope: ['client', 'agent']
                },
                handler: (request, reply) => {
                    const userType = request.auth.credentials.type;
                    const newTimes = request.payload;
                    const interviewId = newTimes.interviewId;

                    if (interviewId) {
                        let email;

                        client.hgetall(interviewId, (err, res) => {
                            let interviewData = res;

                            if (userType === 'client') {
                                email = interviewData.clientEmail;
                            } else {
                                email = interviewData.agencyEmail;
                            }

                            // add new times to interview object  compare objects if key value match overwrite.
                            interviewData.firstIntDate = newTimes.firstIntDate;
                            interviewData.firstIntTime = newTimes.firstIntTime;
                            interviewData.secondIntDate = newTimes.secondIntDate;
                            interviewData.secondIntTime = newTimes.secondIntTime;
                            interviewData.thirdIntDate = newTimes.thirdIntDate;
                            interviewData.thirdIntTime = newTimes.thirdIntTime;
                            interviewData.additionalComments = newTimes.additionalComments;
                            interviewData.interviewAddress = newTimes.interviewAddress;

                            mailgun.changeInterview.to = email;

                            mailgun.changeInterview.html = mailgun.changeInterview.html
                                .replace('-candidateName-', interviewData.candidateName)
                                .replace('-jobTitle-', interviewData.jobTitle)
                                .replace('-interviewId-', interviewData.interviewId);

                            mailgun.messages().send(mailgun.changeInterview, (error, body) => {
                                if (error) {
                                    reply(false);
                                } else if (body) {

                                    let cleanedPayload = cleanPayload(interviewData);

                                    client.hmset(interviewData.interviewId, cleanedPayload, (err, res) => {
                                        if (error) {
                                            console.log('ERROR');
                                            reply(false);
                                        } else if (res) {
                                            console.log('true');
                                            reply(cleanedPayload);
                                        }
                                    });

                                }
                            });

                        });
                    } else {
                        reply(false);

                    }
                }
            }
        }, {
            method: 'GET',
            path: '/interview/confirmed', ///////this should be connected to confirmation button.
            config: {
                auth: {
                    strategy: 'hrns-cookie'
                    // scope: ['client', 'agency']
                },
                handler: (request, reply) => {
                    let confirmedIntTime = request.query.confirmedIntTime;
                    let confirmedIntDate = request.query.confirmedIntDate;
                    let interviewId = request.query.interviewId;

                    client.hgetall(interviewId, (err, res) => {
                        if (err) {
                            return reply(false);
                        }
                        if (res) {
                            console.log('Interview', res);
                            let vid = res.vid;
                            let cvid = res.cvid;
                            let nextStage = res.stage;
                            let agencyEmail = res.agencyEmail;
                            let clientEmail = res.clientEmail;
                            let candidateName = res.candidateName;
                            let interviewAddress = res.interviewAddress;
                            let additionalComments = res.additionalComments;
                            let jobTitle = res.jobTitle;

                            interviewConfirmation.html = interviewConfirmation.html
                                .replace('-candidateName-', candidateName)
                                .replace('-interviewAddress-', interviewAddress)
                                .replace('-confirmedIntDate', confirmedIntDate)
                                .replace('-confirmedIntTime-', confirmedIntTime)
                                .replace('-jobTitle-',jobTitle);

                            if(typeof additionalComments === 'undefined') {
                              additionalComments = '';
                              interviewConfirmation.html = interviewConfirmation.html.replace('-additionalComments-', additionalComments);
                            }else {
                              additionalComments ='<h3>'+additionalComments+'</h3>';
                              interviewConfirmation.html = interviewConfirmation.html.replace('-additionalComments-', additionalComments);
                            }

                            let agencyDetails = interviewConfirmation;
                            let clientDetails = interviewConfirmation;

                            agencyDetails.to = agencyEmail;
                            clientDetails.to = clientEmail;

                            mailgun.messages().send(agencyDetails, (err, agencyEmailed) => {
                                if (err) {
                                    console.log(err);
                                    return reply(false);
                                }
                                if (agencyEmailed) {
                                    mailgun.messages().send(clientDetails, (err, clientEmailed) => {
                                        if (err) {
                                            console.log(err);
                                            return reply(false);
                                        }
                                        if (clientEmailed) {
                                            moveToNextInterviewStage(cvid, vid, nextStage, interviewId, (res)=>{
                                                if(res) {
                                                    return reply(true);

                                                }else {
                                                    return reply(false);
                                                }
                                            });

                                        }
                                    });
                                }
                            });
                        }
                    });

                }
            }
        }
    ]);
    return next();
};

exports.register.attributes = {
    name: 'interviews'
};
<commit_msg>redirect to home<commit_after>'use strict';

//const sendInterviewTimes = require('./utils/app.js').sendInterviewTimes;
const cleanPayload = require('./utils/app.js').cleanPayload;
const client = require('../db/client.js');
const getInterviewDetails = require('../db/redis/getInterviewDetails.js');
const moveToNextInterviewStage = require('../db/redis/moveToNextInterviewStage');
const uuid = require('uuid');

const mailgun = require('./utils/mailgun.js');
const interviewConfirmation = require('./utils/mailgun.js').interviewConfirmation;

exports.register = (server, options, next) => {

    server.route([

        {
            method: 'POST',
            path: '/interview/proposed',
            config: {
                auth: {
                    strategy: 'hrns-cookie'
                    // scope: ['client', 'agent']
                },
                handler: (request, reply) => {
                    ///  must update stage in db;
                    const interview = request.payload;

                    const interviewId = uuid.v1() + 'interviewId';
                    interview.interviewId = interviewId;
                    interview.confirmed = false;

                    getInterviewDetails(interview, (interviewData) => {
                        if (interviewData) {
                            mailgun.proposedInterview.to = interviewData.agencyEmail;
                            mailgun.proposedInterview.html = mailgun.proposedInterview.html
                                .replace('-candidateName-', interview.candidateName)
                                .replace('-jobTitle-', interview.jobTitle)
                                .replace('-companyName-', interview.companyName)
                                .replace('-interviewId-', interview.interviewId);

                            mailgun.messages().send(mailgun.proposedInterview, (error, body) => {
                                if (error) {
                                    console.log(error);
                                } else {
                                    console.log(body);
                                    console.log('Interview', interviewData);
                                    client.hmset(interviewId, interviewData, (err,res) => {  ///HMSET contains an undefined vlaue.
                                        if(err){
                                            console.log('err', err);
                                            return reply(false);
                                        }
                                        if(res){
                                            console.log('res',res);
                                            return reply(true);
                                        }
                                    });

                                }
                            });

                        } else {
                            return reply(false);
                        }

                    });

                }
            }
        }, {
            method: 'GET',
            path: '/interview/confirmation/{interviewId}', /// route for email response.
            config: {
                auth: {
                    strategy: 'hrns-cookie'
                    // scope: ['client', 'agency','admin']
                },
               // plugins: { 'hapi-auth-cookie': { redirectTo: false } },
                handler: (request, reply) => {
                    let layout = { layout: 'default' };
                    let opts = {};

                    let interviewId = request.params.interviewId;

                    client.hgetall(interviewId, (err, res) => {

                        if ((res) && (res.confirmed === 'false')) {
                            opts = res;

                            opts.interviewId = interviewId;
                            opts.title = 'Interview Page';
                            let cleanedPayload = cleanPayload(opts);
                            return reply.view('interview', cleanedPayload, layout);

                        } else {

                            opts.title = 'Interview Page';
                            opts.message = 'This link has expired';
                            return reply.view('message', opts, layout);
                        }

                    });

                }
            }
        }, {
            method: 'POST',
            path: '/change/interview',
            config: {
                auth: {
                    strategy: 'hrns-cookie'
                    // scope: ['client', 'agent']
                },
                handler: (request, reply) => {
                    const userType = request.auth.credentials.type;
                    const newTimes = request.payload;
                    const interviewId = newTimes.interviewId;

                    if (interviewId) {
                        let email;

                        client.hgetall(interviewId, (err, res) => {
                            let interviewData = res;

                            if (userType === 'client') {
                                email = interviewData.clientEmail;
                            } else {
                                email = interviewData.agencyEmail;
                            }

                            // add new times to interview object  compare objects if key value match overwrite.
                            interviewData.firstIntDate = newTimes.firstIntDate;
                            interviewData.firstIntTime = newTimes.firstIntTime;
                            interviewData.secondIntDate = newTimes.secondIntDate;
                            interviewData.secondIntTime = newTimes.secondIntTime;
                            interviewData.thirdIntDate = newTimes.thirdIntDate;
                            interviewData.thirdIntTime = newTimes.thirdIntTime;
                            interviewData.additionalComments = newTimes.additionalComments;
                            interviewData.interviewAddress = newTimes.interviewAddress;

                            mailgun.changeInterview.to = email;

                            mailgun.changeInterview.html = mailgun.changeInterview.html
                                .replace('-candidateName-', interviewData.candidateName)
                                .replace('-jobTitle-', interviewData.jobTitle)
                                .replace('-interviewId-', interviewData.interviewId);

                            mailgun.messages().send(mailgun.changeInterview, (error, body) => {
                                if (error) {
                                    reply(false);
                                } else if (body) {

                                    let cleanedPayload = cleanPayload(interviewData);

                                    client.hmset(interviewData.interviewId, cleanedPayload, (err, res) => {
                                        if (error) {
                                            console.log('ERROR');
                                            reply(false);
                                        } else if (res) {
                                            console.log('true');
                                            reply(cleanedPayload);
                                        }
                                    });

                                }
                            });

                        });
                    } else {
                        reply(false);

                    }
                }
            }
        }, {
            method: 'GET',
            path: '/interview/confirmed', ///////this should be connected to confirmation button.
            config: {
                auth: {
                    strategy: 'hrns-cookie'
                    // scope: ['client', 'agency']
                },
                handler: (request, reply) => {
                    let confirmedIntTime = request.query.confirmedIntTime;
                    let confirmedIntDate = request.query.confirmedIntDate;
                    let interviewId = request.query.interviewId;

                    client.hgetall(interviewId, (err, res) => {
                        if (err) {
                            return reply(false);
                        }
                        if (res) {
                            console.log('Interview', res);
                            let vid = res.vid;
                            let cvid = res.cvid;
                            let nextStage = res.stage;
                            let agencyEmail = res.agencyEmail;
                            let clientEmail = res.clientEmail;
                            let candidateName = res.candidateName;
                            let interviewAddress = res.interviewAddress;
                            let additionalComments = res.additionalComments;
                            let jobTitle = res.jobTitle;

                            interviewConfirmation.html = interviewConfirmation.html
                                .replace('-candidateName-', candidateName)
                                .replace('-interviewAddress-', interviewAddress)
                                .replace('-confirmedIntDate', confirmedIntDate)
                                .replace('-confirmedIntTime-', confirmedIntTime)
                                .replace('-jobTitle-',jobTitle);

                            if(typeof additionalComments === 'undefined') {
                              additionalComments = '';
                              interviewConfirmation.html = interviewConfirmation.html.replace('-additionalComments-', additionalComments);
                            }else {
                              additionalComments ='<h3>'+additionalComments+'</h3>';
                              interviewConfirmation.html = interviewConfirmation.html.replace('-additionalComments-', additionalComments);
                            }

                            let agencyDetails = interviewConfirmation;
                            let clientDetails = interviewConfirmation;

                            agencyDetails.to = agencyEmail;
                            clientDetails.to = clientEmail;

                            mailgun.messages().send(agencyDetails, (err, agencyEmailed) => {
                                if (err) {
                                    console.log(err);
                                    return reply(false);
                                }
                                if (agencyEmailed) {
                                    mailgun.messages().send(clientDetails, (err, clientEmailed) => {
                                        if (err) {
                                            console.log(err);
                                            return reply(false);
                                        }
                                        if (clientEmailed) {
                                            moveToNextInterviewStage(cvid, vid, nextStage, interviewId, (res)=>{
                                                if(res) {
                                                    return reply(true);

                                                }else {
                                                    return reply(false);
                                                }
                                            });

                                        }
                                    });
                                }
                            });
                        }
                    });

                }
            }
        }
    ]);
    return next();
};

exports.register.attributes = {
    name: 'interviews'
};
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import chroma from 'chroma-js'
import titleCase from 'title-case'
import styled from 'styled-components'
import {Box, Flex, Heading, Text} from '@primer/components'
import {colors, variables, getBackgroundPalette} from './color-variables'

export {gradientPalettes} from './color-variables'

const {black, white} = colors
export {black, white}

export function ColorVariable({hue, ...rest}) {
  const values = colors[hue]
  return (
    <Flex.Item as={Box} minWidth={240} pr={4} mb={6} className="col-12 col-md-6 markdown-no-margin" {...rest}>
      <Box bg={colors[hue][5]} my={2} p={3} color="white">
        <Heading as="div" pb={3} fontSize={56} fontWeight="light">
          {titleCase(hue)}
        </Heading>
        <Flex justifyContent="space-between">
          <Flex.Item as={Var} fontWeight="bold">
            ${hue}-500
          </Flex.Item>
          <Text justifySelf="end" fontFamily="mono">
            {values[5]}
          </Text>
        </Flex>
      </Box>
      {values.map((value, index) => (
        <Swatch name={hue} index={index} key={value} />
      ))}
    </Flex.Item>
  )
}

ColorVariable.propTypes = {
  hue: PropTypes.oneOf(Object.keys(colors)).isRequired
}

export function FadeVariables({hue, color, bg, over, children, ...rest}) {
  const colorValue = colors[hue]
  const alphas = [15, 30, 50, 70, 85]
  const values = alphas.map(alpha => {
    const value = chroma(colorValue)
      .alpha(alpha / 100)
      .css()
    return {
      variable: `${hue}-fade-${alpha}`,
      textColor: fadeTextColor(value, over),
      value
    }
  })
  const boxProps = {color, bg}
  return (
    <Flex.Item as={Box} pr={4} mb={6} width={1 / 2} className="markdown-no-margin" {...rest}>
      {/* <Heading as="div">{titleCase(hue)}</Heading> */}
      <Box my={2} p={3} {...boxProps}>
        <Heading as="div" pb={3} fontSize={56} fontWeight="light">
          {titleCase(hue)}
        </Heading>
        <Flex justifyContent="space-between">
          <Flex.Item flex="1 1 auto" as={Var} fontWeight="bold">
            ${hue}
          </Flex.Item>
          <Text fontFamily="mono">
            {chroma(colorValue).css()}
            {' / '}
            {colorValue}
          </Text>
        </Flex>
        {children}
      </Box>
      <Box bg={over}>
        {values.map(swatchProps => (
          <Swatch {...swatchProps} key={swatchProps.name} />
        ))}
      </Box>
    </Flex.Item>
  )
}

FadeVariables.propTypes = {
  bg: Box.propTypes.color,
  color: Box.propTypes.color,
  hue: PropTypes.oneOf(['black', 'white']),
  over: PropTypes.string
}

export function Swatch(props) {
  const {
    name,
    index,
    value = colors[name][index],
    textColor = overlayColor(value),
    variable = `${name}-${index}00`,
    children,
    ...rest
  } = props

  return (
    <Flex bg={value} color={textColor} {...rest}>
      {children}
      {variable ? (
        <Box as={Var} pr={4}>
          ${variable}
        </Box>
      ) : null}
      <Box as={Text} fontFamily="mono">
        {value}
      </Box>
    </Flex>
  )
}

Swatch.defaultProps = {
  as: Text,
  flexWrap: 'wrap',
  fontSize: 1,
  justifyContent: 'space-between',
  p: 3
}

Swatch.propTypes = {
  index: PropTypes.number.isRequired,
  name: PropTypes.string.isRequired,
  textColor: PropTypes.string,
  value: PropTypes.string.isRequired
}

export function BackgroundHueSwatches({hue, ...rest}) {
  const namedUtilities = Object.keys(variables).filter(name => name.startsWith(`bg-${hue}`))

  const namedUtilitiesByValue = {}
  for (const name of namedUtilities) {
    const value = variables[name]
    namedUtilitiesByValue[value] = name
  }

  const {values} = getBackgroundPalette(hue)
  const rows = values.map(({value, ...rest}) => ({
    value,
    named: namedUtilitiesByValue[value],
    ...rest
  }))

  return (
    <ColorTable {...rest}>

          <ColorCell as="th">Default class</ColorCell>
          Indexed?
          Variable
          CSS value

        {rows.map(({value, named, slug, variable}) => {
          const overlay = overlayColor(value)
          return (
            <ColorRow key={slug}>
              <ColorCell bg={named ? value : null} color={overlay}>
                {named ? `.${named}` : null}
              </ColorCell>
              <ColorCell bg={value} color={overlay}>
                .bg-{slug}
              </ColorCell>
              <ColorCell bg={value} color={overlay}>
                <Var>${variable}</Var>
              </ColorCell>
              <ColorCell bg={value} color={overlay}>
                <Text fontFamily="mono">{value}</Text>
              </ColorCell>
            </ColorRow>
          )
        })}

    </ColorTable>
  )
}

export function Var(props) {
  return <Text as="var" fontFamily="mono" fontStyle="normal" {...props} />
}

export function overlayColor(bg) {
  return chroma(bg).luminance() > 0.5 ? black : white
}

const ColorTable = styled.table`
  display: table !important;
  table-layout: fixed;
  border-collapse: separate;
  border-spacing: 0 4px;

  tr,
  td,
  th {
    border: 0 !important;
  }

  td,
  th {
    text-align: left;
    width: 25%;
  }

  tr {
    background-color: transparent !important;
  }
`

const ColorRow = styled(Box).attrs({as: 'tr'})`
  border-bottom: 1px solid ${colors.gray[2]} !important;
`

const ColorCell = styled(Box).attrs({as: 'td'})``

function fadeTextColor(fg, bg = white) {
  const rgb = compositeRGB(fg, bg)
  return overlayColor(rgb)
}

/**
 * Composite ("flatten") a foreground RGBA value with an RGB background into an
 * RGB color for the purposes of measuring contrast or luminance.
 */
function compositeRGB(foreground, background) {
  const [fr, fg, fb, fa] = chroma(foreground).rgba()
  const [br, bg, bb] = chroma(background).rgb()
  return chroma([(1 - fa) * br + fa * fr, (1 - fa) * bg + fa * fg, (1 - fa) * bb + fa * fb]).css()
}
<commit_msg>update bg utility table headings /cc @emilybrick<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import chroma from 'chroma-js'
import titleCase from 'title-case'
import styled from 'styled-components'
import {Box, Flex, Heading, Text} from '@primer/components'
import {colors, variables, getBackgroundPalette} from './color-variables'

export {gradientPalettes} from './color-variables'

const {black, white} = colors
export {black, white}

export function ColorVariable({hue, ...rest}) {
  const values = colors[hue]
  return (
    <Flex.Item as={Box} minWidth={240} pr={4} mb={6} className="col-12 col-md-6 markdown-no-margin" {...rest}>
      <Box bg={colors[hue][5]} my={2} p={3} color="white">
        <Heading as="div" pb={3} fontSize={56} fontWeight="light">
          {titleCase(hue)}
        </Heading>
        <Flex justifyContent="space-between">
          <Flex.Item as={Var} fontWeight="bold">
            ${hue}-500
          </Flex.Item>
          <Text justifySelf="end" fontFamily="mono">
            {values[5]}
          </Text>
        </Flex>
      </Box>
      {values.map((value, index) => (
        <Swatch name={hue} index={index} key={value} />
      ))}
    </Flex.Item>
  )
}

ColorVariable.propTypes = {
  hue: PropTypes.oneOf(Object.keys(colors)).isRequired
}

export function FadeVariables({hue, color, bg, over, children, ...rest}) {
  const colorValue = colors[hue]
  const alphas = [15, 30, 50, 70, 85]
  const values = alphas.map(alpha => {
    const value = chroma(colorValue)
      .alpha(alpha / 100)
      .css()
    return {
      variable: `${hue}-fade-${alpha}`,
      textColor: fadeTextColor(value, over),
      value
    }
  })
  const boxProps = {color, bg}
  return (
    <Flex.Item as={Box} pr={4} mb={6} width={1 / 2} className="markdown-no-margin" {...rest}>
      {/* <Heading as="div">{titleCase(hue)}</Heading> */}
      <Box my={2} p={3} {...boxProps}>
        <Heading as="div" pb={3} fontSize={56} fontWeight="light">
          {titleCase(hue)}
        </Heading>
        <Flex justifyContent="space-between">
          <Flex.Item flex="1 1 auto" as={Var} fontWeight="bold">
            ${hue}
          </Flex.Item>
          <Text fontFamily="mono">
            {chroma(colorValue).css()}
            {' / '}
            {colorValue}
          </Text>
        </Flex>
        {children}
      </Box>
      <Box bg={over}>
        {values.map(swatchProps => (
          <Swatch {...swatchProps} key={swatchProps.name} />
        ))}
      </Box>
    </Flex.Item>
  )
}

FadeVariables.propTypes = {
  bg: Box.propTypes.color,
  color: Box.propTypes.color,
  hue: PropTypes.oneOf(['black', 'white']),
  over: PropTypes.string
}

export function Swatch(props) {
  const {
    name,
    index,
    value = colors[name][index],
    textColor = overlayColor(value),
    variable = `${name}-${index}00`,
    children,
    ...rest
  } = props

  return (
    <Flex bg={value} color={textColor} {...rest}>
      {children}
      {variable ? (
        <Box as={Var} pr={4}>
          ${variable}
        </Box>
      ) : null}
      <Box as={Text} fontFamily="mono">
        {value}
      </Box>
    </Flex>
  )
}

Swatch.defaultProps = {
  as: Text,
  flexWrap: 'wrap',
  fontSize: 1,
  justifyContent: 'space-between',
  p: 3
}

Swatch.propTypes = {
  index: PropTypes.number.isRequired,
  name: PropTypes.string.isRequired,
  textColor: PropTypes.string,
  value: PropTypes.string.isRequired
}

export function BackgroundHueSwatches({hue, ...rest}) {
  const namedUtilities = Object.keys(variables).filter(name => name.startsWith(`bg-${hue}`))

  const namedUtilitiesByValue = {}
  for (const name of namedUtilities) {
    const value = variables[name]
    namedUtilitiesByValue[value] = name
  }

  const {values} = getBackgroundPalette(hue)
  const rows = values.map(({value, ...rest}) => ({
    value,
    named: namedUtilitiesByValue[value],
    ...rest
  }))

  return (
    <ColorTable {...rest}>

          Default classes
          Extended classes
          Variable
          CSS value

        {rows.map(({value, named, slug, variable}) => {
          const overlay = overlayColor(value)
          return (
            <ColorRow key={slug}>
              <ColorCell bg={named ? value : null} color={overlay}>
                {named ? `.${named}` : null}
              </ColorCell>
              <ColorCell bg={value} color={overlay}>
                .bg-{slug}
              </ColorCell>
              <ColorCell bg={value} color={overlay}>
                <Var>${variable}</Var>
              </ColorCell>
              <ColorCell bg={value} color={overlay}>
                <Text fontFamily="mono">{value}</Text>
              </ColorCell>
            </ColorRow>
          )
        })}

    </ColorTable>
  )
}

export function Var(props) {
  return <Text as="var" fontFamily="mono" fontStyle="normal" {...props} />
}

export function overlayColor(bg) {
  return chroma(bg).luminance() > 0.5 ? black : white
}

const ColorTable = styled.table`
  display: table !important;
  table-layout: fixed;
  border-collapse: separate;
  border-spacing: 0 4px;

  tr,
  td,
  th {
    border: 0 !important;
  }

  td,
  th {
    text-align: left;
    width: 25%;
  }

  tr {
    background-color: transparent !important;
  }
`

const ColorRow = styled(Box).attrs({as: 'tr'})`
  border-bottom: 1px solid ${colors.gray[2]} !important;
`

const ColorCell = styled(Box).attrs({as: 'td'})``

function fadeTextColor(fg, bg = white) {
  const rgb = compositeRGB(fg, bg)
  return overlayColor(rgb)
}

/**
 * Composite ("flatten") a foreground RGBA value with an RGB background into an
 * RGB color for the purposes of measuring contrast or luminance.
 */
function compositeRGB(foreground, background) {
  const [fr, fg, fb, fa] = chroma(foreground).rgba()
  const [br, bg, bb] = chroma(background).rgb()
  return chroma([(1 - fa) * br + fa * fr, (1 - fa) * bg + fa * fg, (1 - fa) * bb + fa * fb]).css()
}
<|endoftext|>