The Idea is to load only 50 items at a time to help with loading the page.
I have the code that will load the first 50 items form a json file.
I then want to load the next 50 when the user scrolls halfway down the page and keep going tell there is no more items to load.
This is what I have so far.
//This loads the first 50 items from external Json file. No issue here
$(window).load(function(){
var picarioAPI = "https://sdlbytheyard.picarioxpo.com/xpo/api/v1/designs/search/Customizable&Customizable/?apiKey=f02ac05d0a664db08274c7d7c4c0b594&skip=0&take=50";
var newtext = document.getElementById("DeisgnLibraryPopupButtom").innerHTML
$.getJSON(picarioAPI, function (json) {
var text = "";
for (i in json.values)
for (var j in json.values[i].labels) {
if (json.values[i].labels[j].name == "Show") {
// This is for a popup function.
var b = 'data-options={"src": "#hidden-content-3'+json.values[i].id+'", "touch": false}';
text += '<div class="prod" style="float:left;"><a data-fancybox ' + b + ' href="javascript:;" onclick="test()"><img class="lazyload" src="' + json.values[i].displayUrl + '"><p class="title">' + json.values[i].name + '</p></a></div><div style="display: none;max-width:500px;" id="hidden-content-3'+json.values[i].id+'"><img class="lazyload" src="' + json.values[i].displayUrl + '" data-height="'+json.values[i].height+'"data-width="'+json.values[i].width+'"data-url="'+json.values[i].displayUrl+'"data-full="'+json.values[i].renderUrl +'"data-name="'+json.values[i].name+'"><p class="title">' + json.values[i].name + '</p>' + newtext + '</div>';
document.getElementById("design1").innerHTML = text;
}
};
});
});
I then load a scroll function to load the next 50 items and so on. I use the number to add 50 items to the end of the Json file API
//This is the part I'm not getting correct.
var number = 0;
$(window).scroll(function () {
if ($(window).scrollTop() > $('body').height() / 2) {
number++;
// I use the number to dynamically load the next 50 items as the user scrolls.
var total = number + 50;
var picarioAPI = 'https://sdlbytheyard.picarioxpo.com/xpo/api/v1/designs/search/Customizable&Customizable/?apiKey=f02ac05d0a664db08274c7d7c4c0b594&skip='+total+'&take=50';
var newtext = document.getElementById("DeisgnLibraryPopupButtom").innerHTML
$.getJSON(picarioAPI, function (json) {
var text = "";
for (i in json.values)
for (var j in json.values[i].labels) {
if (json.values[i].labels[j].name == "Show") {
//this is for a popup function
var b = 'data-options={"src": "#hidden-content-3'+json.values[i].id+'", "touch": false}';
text += '<div class="prod" style="float:left;"><a data-fancybox ' + b + ' href="javascript:;" onclick="test()"><img class="lazyload" src="' + json.values[i].displayUrl + '"><p class="title">' + json.values[i].name + '</p></a></div><div style="display: none;max-width:500px;" id="hidden-content-3'+json.values[i].id+'"><img class="lazyload" src="' + json.values[i].displayUrl + '" data-height="'+json.values[i].height+'"data-width="'+json.values[i].width+'"data-url="'+json.values[i].displayUrl+'"data-full="'+json.values[i].renderUrl +'"data-name="'+json.values[i].name+'"><p class="title">' + json.values[i].name + '</p>' + newtext + '</div>';
document.getElementById("design1").innerHTML += document.getElementById("design1").innerHTML + text;
}
};
});
};
});
The issue is when I scroll halfway down the page it will start to load all 2000 items instead of just the next 50.
Any help would be great.
unless you stop scrolling EXACTLY when you've reached half way, you'll be getting multiple triggers of scroll - you need to introduce some flag to indicate that a request is in flight, and ignore the scroll event until the new data is loaded
var inflight = false;
var number = 0;
$(window).scroll(function() {
if (!inflight && $(window).scrollTop() > $('body').height() / 2) {
inflight = true;
number++;
// I use the number to dynamically load the next 50 items as the user scrolls.
var total = number + 50;
var picarioAPI = 'https://sdlbytheyard.picarioxpo.com/xpo/api/v1/designs/search/Customizable&Customizable/?apiKey=f02ac05d0a664db08274c7d7c4c0b594&skip=' + total + '&take=50';
var newtext = document.getElementById("DeisgnLibraryPopupButtom").innerHTML
$.getJSON(picarioAPI, function(json) {
var text = "";
for (i in json.values) {
for (var j in json.values[i].labels) {
if (json.values[i].labels[j].name == "Show") {
//this is for a popup function
var b = 'data-options={"src": "#hidden-content-3' + json.values[i].id + '", "touch": false}';
text += '<div class="prod" style="float:left;"><a data-fancybox ' + b + ' href="javascript:;" onclick="test()"><img class="lazyload" src="' + json.values[i].displayUrl + '"><p class="title">' + json.values[i].name + '</p></a></div><div style="display: none;max-width:500px;" id="hidden-content-3' + json.values[i].id + '"><img class="lazyload" src="' + json.values[i].displayUrl + '" data-height="' + json.values[i].height + '"data-width="' + json.values[i].width + '"data-url="' + json.values[i].displayUrl + '"data-full="' + json.values[i].renderUrl + '"data-name="' + json.values[i].name + '"><p class="title">' + json.values[i].name + '</p>' + newtext + '</div>';
document.getElementById("design1").innerHTML += document.getElementById("design1").innerHTML + text;
}
}
}
inflight = false;
});
}
});
I have code below that renders a few products on a page. Each of these products shares the same data attribute "data-item-upc". There is also a button that is rendered for each product on the page (6 total buttons to be exact). They all share this same data-item-upc data attribute.
I am able to successfully grab the value of the data atrribute and match it to the item with the same UPC value in the second database. But for some reason only the first button works and shows the modal. Not sure whats going on. Hoping someone can help me out would really appreciate it.
//declare variable to store JSON data
var product_data = {};
var nutritional_data = {};
$(document).ready(function() {
'use strict';
//grab product data
$.ajax({
dataType: "jsonp",
url: 'path to URL',
cache: true,
success: function(data){
//assign JSON to product data variable
product_data = JSON.parse(JSON.stringify(data).replace(/"\s+|\s+"/g,'"'));
//grab nutrional data
$.ajax({
dataType: "jsonp",
url: 'path to URL',
cache: true,
success: function(json){
//assign JSON to product data variable
nutritional_data = JSON.parse(JSON.stringify(json).replace(/"\s+|\s+"/g,'"'));
//declare divs to store data
var productDivOne = '';
var productDivTwo = '';
$.each(product_data, function(i, item) {
//convert JSON strings to uppercase for comparison
var brandLetter = item.itemBrandLetter.toUpperCase();
var foodService = item.itemDeli.toUpperCase();
var brandItem = item.itemName;
if (brandLetter == "LB" && foodService == "N") {
if (brandItem.indexOf("Panettone") >= 0) {
productDivOne +=
'<div class="item col-xs-12 col-sm-4 col-md-4 col-lg-4">' +
'<div class="thumbnail">' +
'<img class="scale-down-seperate-prods" src="' + item.imageURL + '" alt="' + item.itemName + '" />' +
'<div class="caption">' + '<br>' +
'<h3 class="group inner list-group-item-heading">' + item.itemName + '</h3>' +
'<h4 class="group inner list-group-item-text">' + item.itemFullUPC.slice(1, -1) + ' • ' + item.itemPackSize.toLowerCase().substring(item.itemPackSize.lastIndexOf("/") + 1) + '</h4>' +
'<button type="button" class="btn btn-info btn-lg showNutritionFacts" data-item-upc="' + item.itemFullUPC + '" value="itemFullUPC">Nutrition Facts</button>' +
'</div>' +
'</div>' +
'</div>';
}
if (brandItem.indexOf("Egg") >= 0) {
productDivTwo +=
'<div class="item col-xs-12 col-sm-4 col-md-4 col-lg-4">' +
'<div class="thumbnail">' +
'<img class="scale-down-seperate-prods" src="' + item.imageURL + '" alt="' + item.itemName + '" />' +
'<div class="caption">' + '<br>' +
'<h3 class="group inner list-group-item-heading">' + item.itemName + '</h3>' +
'<h4 class="group inner list-group-item-text">' + item.itemFullUPC.slice(1, -1) + ' • ' + item.itemPackSize.toLowerCase().substring(item.itemPackSize.lastIndexOf("/") + 1) + '</h4>' +
'<button type="button" class="btn btn-info btn-lg showNutritionFacts" data-item-upc="' + item.itemFullUPC + '" value="itemFullUPC">Nutrition Facts</button>' +
'</div>' +
'</div>' +
'</div>';
}
}
});
//show nutritional information on button click
$("body").on('click', ".showNutritionFacts", function(event){
//get passed data from other function
var clickedItemUPC = $(this).data('item-upc');
alert(clickedItemUPC);
//declare variables to store data
var servingSize = '';
var servingPerContainer = '';
var calories = '';
var caloriesFat = '';
var totalFatGrams = '';
var totalFatPercentage = '';
var saturatedFatGrams = '';
var saturatedFatPercentage = '';
var transFatGrams = '';
var polyunsaturatedFatGrams = '';
var monounsaturatedFatGrams = '';
var cholesterolGrams = '';
var cholesterolPercentage = '';
var sodiumGrams = '';
var sodiumPercentage = '';
var totalCarbohydrateGrams = '';
var totalCarbohydratePercentage = '';
var dietaryFiberGrams = '';
var dietaryFiberPercentage = '';
var sugarGrams = '';
var sugarGramsAdded = '';
var sugarGramsAddedPercentage = '';
var proteinGrams = '';
var vitaminAPercentage = '';
var vitaminCGrams = '';
var vitaminCPercentage = '';
var vitaminDGrams = '';
var vitaminDPercentage = '';
var calciumGrams = '';
var calciumPercentage = '';
var ironGrams = '';
var ironPercentage = '';
var potassiumGrams = '';
var potassiumPercentage = '';
var thiamineGrams = '';
var thiaminePercentage = '';
var riboflavinGrams = '';
var riboflavinPercentage = '';
var niacinGrams = '';
var niacinPercentage = '';
var ingredients = '';
//comparison UPC variable
var compareNutUPC;
$.each(nutritional_data, function (i, item) {
//assign comparison UPC to itemNum
compareNutUPC = item.itemNum;
//compare product UPC in nutritional and product data
if (clickedItemUPC == compareNutUPC) {
servingSize += item.servingSize;
servingPerContainer += item.itemServings;
calories += item.itemCalories;
caloriesFat += item.itemCaloriesFromFat;
transFatGrams += item.itemTransFat + 'g';
polyunsaturatedFatGrams += item.itemPolyUnsatFat + 'g';
monounsaturatedFatGrams += item.itemMonoUnsatFat + 'g';
saturatedFatGrams += item.itemSaturFat + 'g';
saturatedFatPercentage += item.itemSaturFatPerc + '%';
totalFatGrams += item.itemTotalFat + 'g';
totalFatPercentage += item.itemTotalFatPerc + '%';
cholesterolGrams += item.itemCholesterol + 'mg';
cholesterolPercentage += item.itemCholesterolPerc + '%';
sodiumGrams += item.itemSodium + 'mg';
sodiumPercentage += item.itemSodiumPerc + '%';
totalCarbohydrateGrams += item.itemTotalCarb + 'g';
totalCarbohydratePercentage += item.itemTotalCarbPerc + '%';
sugarGrams += item.itemSugars + 'g';
sugarGramsAdded += item.itemSugarsAdded + 'g';
sugarGramsAddedPercentage += item.itemSugarsAddedPerc + '%';
dietaryFiberGrams += item.itemDietFiber + 'g';
dietaryFiberPercentage += item.itemDietFiberPerc + '%';
proteinGrams += item.itemProtein + 'g';
vitaminAPercentage += item.itemVitaminA + '%';
vitaminCPercentage += item.itemVitaminC + '%';
vitaminDGrams += item.itemVitaminDMeasure;
vitaminDPercentage += item.itemVitaminD + '%';
calciumGrams += item.itemCalciumMeasure;
calciumPercentage += item.itemCalcium + '%';
ironGrams += item.itemIronMeasure;
ironPercentage += item.itemIron + '%';
thiaminePercentage += item.itemThiamin + '%';
riboflavinPercentage += item.itemRiboflavin + '%';
niacinPercentage += item.itemNiacin + '%';
potassiumGrams += item.itemPotassium;
potassiumPercentage += item.itemPotassiumPerc + '%';
ingredients += item.itemIngredients;
}
});
$(".servingSize").html(servingSize.replace(/\s+(?=g)/g, '').toLowerCase());
$(".servingPerContainer").html(servingPerContainer);
$(".calories").html(calories);
$(".caloriesFat").html(caloriesFat);
$(".transFatGrams").html(transFatGrams);
$(".polyunsaturatedFatGrams").html(polyunsaturatedFatGrams);
$(".monounsaturatedFatGrams").html(monounsaturatedFatGrams);
$(".saturatedFatGrams").html(saturatedFatGrams);
$(".saturatedFatPercentage").html(saturatedFatPercentage);
$(".totalFatGrams").html(totalFatGrams);
$(".totalFatPercentage").html(totalFatPercentage);
$(".cholesterolGrams").html(cholesterolGrams);
$(".cholesterolPercentage").html(cholesterolPercentage);
$(".sodiumGrams").html(sodiumGrams);
$(".sodiumPercentage").html(sodiumPercentage);
$(".totalCarbohydrateGrams").html(totalCarbohydrateGrams);
$(".totalCarbohydratePercentage").html(totalCarbohydratePercentage);
$(".sugarGrams").html(sugarGrams);
$(".sugarGramsAdded").html(sugarGramsAdded);
$(".sugarGramsAddedPercentage").html(sugarGramsAddedPercentage);
$(".dietaryFiberGrams").html(dietaryFiberGrams);
$(".dietaryFiberPercentage").html(dietaryFiberPercentage);
$(".proteinGrams").html(proteinGrams);
$(".vitaminAPercentage").html(vitaminAPercentage);
$(".vitaminCPercentage").html(vitaminCPercentage);
$(".vitaminDGrams").html(vitaminDGrams);
$(".vitaminDPercentage").html(vitaminDPercentage);
$(".calciumGrams").html(calciumGrams);
$(".calciumPercentage").html(calciumPercentage);
$(".ironGrams").html(ironGrams);
$(".ironPercentage").html(ironPercentage);
$(".thiaminePercentage").html(thiaminePercentage);
$(".riboflavinPercentage").html(riboflavinPercentage);
$(".niacinPercentage").html(niacinPercentage);
$(".potassiumGrams").html(potassiumGrams);
$(".potassiumPercentage").html(potassiumPercentage);
$(".ingredients").html(ingredients.toUpperCase());
//determine which modal to show
if ($('.vitaminDGrams:contains("mcg")').length > 0 && $('.calciumGrams:contains("mg")').length > 0 && $('.ironGrams:contains("mg")').length > 0) {
$('.nutritionPopupAlternate').modal('show');
} else if (servingSize == 0) {
$('.nutritionPopupNoInfo').modal('show');
} else {
$('.nutritionPopupStandard').modal('show');
}
});
//append to appropriate div
$('#productDivOne').html(productDivOne);
$('#productDivTwo').html(productDivTwo);
}
});
//end of prod data
}
});
//end of nut data
});
Thanks to Sandy i was able to minify my code and find the issue. Turns out it was looking for something that was added later from a different source code that I took, after editing the DIV it works perfectly now.
I'm trying to build viewer that pulls from the twitch API to show which channels are online / offline.
I have 3 buttons: All (displays online and offline results), Online(displays only online results), and Offline (you guessed it...displays only offline results).
My code to display all results is as follows:`
var getAll = function () {
$(".twitch-viewer-information").empty()
twitchUsernames.forEach(function (elem) {
$.when($.getJSON(twitchApi + elem + apiCallback), $.getJSON(twitchStreamApi + elem + apiCallback)).done(function(data1,data2) {
var twitchChannel = elem;
var twitchLogo = data1[0].logo ? data1[0].logo : "https://www.skillsilo.com/images/profile-photo-default-256.png";
var twitchStatus = checkStatus(data2);
var twitchUrl = data1[0].url;
var twitchStreamMessage = data2[0].stream ? data2[0].stream.channel.status.substring(0,33)+"..." : "";
tableRow =$(
'<tr class="twitch-viewer-channel-data" data-href="'+ twitchUrl +'">' +
'<td class="channel-pic"> <img class="channel-image" src="' + twitchLogo + '"</td>' +
'<td class="twitch-viewer-channel-name">' + twitchChannel + '<br> <span class="twitch-stream-message">' + twitchStreamMessage +'</span></td>' +
'<td class="twitch-viewer-channel-status">' + twitchStatus + '</td>' +
'<tr>'
);
$(".twitch-viewer-information").append(tableRow);
tableRow.click(function() {
window.location.href = $(this).data("href");
});
});
});
}
I'd like to now build a function that only returns the channels that are online, using as little code as possible. I have been rewriting the entire function, along with an if statement at the end to accomplish this...but there has got to be a simpler way:
var getOnline = function () {
$(".twitch-viewer-information").empty()
twitchUsernames.forEach(function (elem) {
$.when($.getJSON(twitchApi + elem + apiCallback), $.getJSON(twitchStreamApi + elem + apiCallback)).done(function(data1,data2) {
var twitchChannel = elem;
var twitchLogo = data1[0].logo ? data1[0].logo : "https://www.skillsilo.com/images/profile-photo-default-256.png";
var twitchStatus = checkStatus(data2);
var twitchUrl = data1[0].url;
var twitchStreamMessage = data2[0].stream ? data2[0].stream.channel.status.substring(0,33)+"..." : "";
tableRow =$(
'<tr class="twitch-viewer-channel-data" data-href="'+ twitchUrl +'">' +
'<td class="channel-pic"> <img class="channel-image" src="' + twitchLogo + '"</td>' +
'<td class="twitch-viewer-channel-name">' + twitchChannel + '<br> <span class="twitch-stream-message">' +twitchStreamMessage +'</span></td>' +
'<td class="twitch-viewer-channel-status">' + twitchStatus + '</td>' +
'<tr>'
);
if(twitchStatus === "Online") {
$(".twitch-viewer-information").append(tableRow);
tableRow.click(function() {
window.location.href = $(this).data("href");
});
}
});
});
}
What is the shortest amount of code that I can user to duplicate my getAll function, while allowing me to filter for just the twitchStatus's that are online?
I could not figure out what I am doing wrong?
Also i am having problem storing data in javascript 2d array.
Fiddle
$.getJSON(url,
function (data) {
/*Insert your titles you wanna show*/
var titles = ["box closing", "e"];
var nope = [
[],
[],
[]
];
// var len = titles.length;
var count = 0;
var col = 0;
var row=0;
$.each(data.photos.photo, function (i, item) {
var purl = 'http://farm' + item.farm + '.static.flickr.com/' + item.server + '/' + item.id + '_' + item.secret + '_m.jpg';
// var pid = item.id;
var container = '<tr><td class="col-md-8"><a target="_blank" href="http://www.flickr.com/photos/' + userid + '/' + item.id + '/"><img class="span4" alt="' + item.title + '" src="' + purl + ' width=100 height=200"/></td></tr>';
var title = '<tr><td class="col-md-4" >' + item.title + '</td></tr>';
nope[row][0] = item.title;
nope[row][1] = container;
nope[row][2]=title;
/*Show only image with in titles*/
if (item.title == titles[count]) {
$(container).appendTo('#contain');
$(title).appendTo('#contain');
//$("a.imageurl").append(" ");
//$("#name").append(title);
//$("a.imageurl").append(purl);
//$("a.imageurl").append(" ");
//purl = '
$("#demo").append(nope[row][col]);
$("#demo").append(nope[row][col]);
$("#demo").append(nope[row][col]);
}
col++;
count = count + 1;
});
});
I am working on preparing some dynamic html with jquery and json object. but the problem is that when my json object has around 1500 rows it takes ages to load.
is there a way to load the thing faster.
Some code.
$(jQuery.each(jsonObject.AvailableColumns, function (i, l) {
if (type == "manual") {
innerList1 += '<li newText="" valueFormat="' + l.ValueFormat + '" scaleID="' + l.ScaleID + '" scaleType="' + l.ScaleType + '" hasWeights="' + l.HasWeights + '" customColumnType="' + l.CustomColumnType + '" class="" id="li_' + controlId + '"><span id="span_' + controlId + '" title = "' + l.QuestionText + '">' + getDisplayString(l.QuestionText) + '</span><a class="actionLeft"></a></li>';
}
else if (type = "exportall") {
innerList2 += CreateLiWithSpans('li_' + controlId, l.QuestionText, true, false, l.ScaleID, l.ScaleType, l.HasWeights, l.CustomColumnType, l.ValueFormat);
}
controlId++;
}));
$("#itemList").html(innerlist1);
EDIT : createliwithspan method
function CreateLiWithSpans(id, html, isLeft, isAddAll, scaleID, scaleType, hasWeights, customColumnType, valueFormat, newText) {
var ancClass = isLeft ? 'actionRight' : 'actionLeft';
var liObject = "";
if (newText == null) {
newText = "";
}
if (isLeft) {
liObject = '<li newtext="' + newText + '" valueFormat="' + valueFormat + '" scaleID="' + scaleID + '" scaleType="' + scaleType + '" hasWeights="' + hasWeights + '" customColumnType="' + customColumnType + '" class="" id="' + id + '"><span id="span_' + id + '" title = "' + html + '">' + getDisplayString(html) + '</span><span style="margin:0 10px 0 20px;pagging:0"><input title = "' + (newText == "" ? html : newText) + '" type="text" id="' + id + 'displayText" value="' + (newText == "" ? html : newText) + '" /><span style="color:Red; width:100%;" id="' + id + 'displayTextError"></span></span><span style="float:left">' + CreateDropDown('ddl_' + id, valueFormat, hasWeights) + '</span><a class="' + ancClass + '"></a></li>';
}
else {
liObject = '<li newtext="' + newText + '" valueFormat="' + valueFormat + '" scaleID="' + scaleID + '" scaleType="' + scaleType + '" hasWeights="' + hasWeights + '" customColumnType="' + customColumnType + '" class="" id="' + id + '"><span id="span_' + id + '" title = "' + html + '">' + getDisplayString(html) + '</span><a class="' + ancClass + '"></a></li>';
}
return liObject;
}
You can use for loop instead of jQuery.each, that will be faster. Store the itemCount before the loop, and use that:
itemCount = jsonData.items.length;
for(var i = 0; i < itemCount; i++ ) {
...
You can also use use an array instead of string concatenation, like so:
var innerList = [];
... // inside the loop
innerList.push(CreateLiWithSpans('li_' + controlId, l.QuestionText, true, false, l.ScaleID, l.ScaleType, l.HasWeights, l.CustomColumnType, l.ValueFormat));
... // after the loop
$("#itemList").html(innerList.join(''));
This will be faster in IE, I'm not sure about other js engines.
These two methods will not make a significant difference, so you should try implementing a client side pagination from json. (Not by hiding and showing divs, by rendering only visible page into the DOM).
Instead of waiting for the loop to end to append your data, why not actively append the data as you process it. This will allow the user to get immediate feedback instead of waiting for the whole thing to process. Other than this, I'd stick with my original comment to page the data.
$(jQuery.each(jsonObject.AvailableColumns, function (i, l) {
if (type == "manual") {
$("#itemList").append( '<li newText="" valueFormat="' + l.ValueFormat + '" scaleID="' + l.ScaleID + '" scaleType="' + l.ScaleType + '" hasWeights="' + l.HasWeights + '" customColumnType="' + l.CustomColumnType + '" class="" id="li_' + controlId + '"><span id="span_' + controlId + '" title = "' + l.QuestionText + '">' + getDisplayString(l.QuestionText) + '</span><a class="actionLeft"></a></li>');
}
else if (type = "exportall") {
$("#itemList2").append(CreateLiWithSpans('li_' + controlId, l.QuestionText, true, false, l.ScaleID, l.ScaleType, l.HasWeights, l.CustomColumnType, l.ValueFormat));
}
controlId++;
}));
Try replacing jQuery.each with a plain old for...in loop. Using jQuery.each adds overhead that you don't need.
Don't concatenate strings inside your loop. Instead, .push them onto an array variable and use .join('') to build the string all at once at the end.
You may need to eliminate CreateLiWithSpans as a separate function in order to fully implement (2).
Changing from using jQuery.each to a standard javascript for loop should speed it up a bit. Make sure that you save the length to a variable like this though:
for(var i = 0, len = jsonObject.AvailableColumns.length; i < len; i++){
var l = jsonObject.AvailableColumns[i];
// Continue with rest of code
}
Probably won't be a huge increase but every little helps.
Also try lowering the number of function calls you make as these have added overhead (not usually an issue, but in a large loop it can help). Unless the code is shared between functions try doing it inline and see how much that speeds it up.