问:
d3 javascript series chart

I am trying to create this particular d3 application where a series of data can be dynamically displayed like this. Each segment contains two pieces of data.

The first step is to print the circles so there is sufficient space between the series but also the largest circle is always under the smaller circle.

//version 3 -- with correct labels and legend--
http://jsfiddle.net/0ht35rpb/33/

//******version 2 fiddle******
http://jsfiddle.net/1oka61mL/10/

-- How to set the diagonal labels properly - same angles, aligned properly?
-- Add legend?
-- Mask the bottom pointers in an opposite color then continue the line in a different color?

//******Latest Jsfiddle******
http://jsfiddle.net/0ht35rpb/26/

```<code>var width = 600;
var height = 400;
var svg = d3.select('svg').attr("width", width).attr("height", height);

//Count
//Checkins
//Popularity

var data = [{
  "name": "Twitter",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 200
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 1000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 30
  }]
}, {
  "name": "Facebook",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 500
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 300
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 740
  }]
}, {
  "name": "Ebay",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 4000
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 1000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 40
  }]
}, {
  "name": "Foursquare",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 2000
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 3000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 4500
  }]
}];

var outerRadius = [];
// organise the data.
// Insert indices and sort items in each series
// keep a running total of max circle size in each series
// for later positioning
var x = 0;
var totalWidth = d3.sum(
  data.map(function(series) {
    series.items.forEach(function(item, i) {
      item.index = i;
    });
    series.items.sort(function(a, b) {
      return b.value - a.value;
    });
    var maxr = Math.sqrt(series.items[0].value);
    outerRadius.push(maxr);
    x += maxr;
    series.xcentre = x;
    x += maxr;
    return maxr * 2;
  })
);

// make scales for position and colour
var scale = d3.scale.linear().domain([0, totalWidth]).range([0, width]);
//var colScale = d3.scale.category10();

function colores_google(n) {
  var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f"];
  return colores_g[n % colores_g.length];
}

// add a group per series, position the group according to the values and position scale  we calculated above
var groups = svg.selectAll("g").data(data);
groups.enter().append("g");
groups.attr("transform", function(d) {
  return ("translate(" + d.xcentre + ",0)");
});

// then add circles per series, biggest first as items are sorted
// colour according to index (the property we inserted previously so we can
// keep track of their original position in the series)
var circles = groups.selectAll("circle").data(function(d) {
  return d.items;
}, function(d) {
  return d.index;
});
circles.enter().append("circle").attr("cy", height / 2).attr("cx", 0);

circles
  .attr("r", function(d) {
    return Math.sqrt(d.value);
  })
  .style("fill", function(d) {
    return colores_google(d.index);
  });

var labelsgroups = svg.selectAll("text").data(data);
labelsgroups.enter().append("text");
labelsgroups
  .attr("y", function(d, i) {
    d.y = 300;
    d.cy = 200;
    return 300;
  })
  .attr("x", function(d) {
    d.x = d.xcentre;
    d.cx = d.xcentre;
    return d.xcentre;
  })
  .text(function(d) {
    return d.name;
  })
  .each(function(d) {
    var bbox = this.getBBox();
    d.sx = d.x - bbox.width / 2 - 2;
    d.ox = d.x + bbox.width / 2 + 2;
    d.sy = d.oy = d.y + 5;
  })
  .attr("text-anchor", "middle");

var pointersgroups = svg.selectAll("path.pointer").data(data);
pointersgroups.enter().append("path");
pointersgroups
  .attr("class", "pointer")
  .attr("marker-end", "url(#circ)");

pointersgroups
  .attr("d", function(d) {
    return "M" + (d.xcentre) + "," + (d.oy - 25) + "L" + (d.xcentre) + "," + (d.sy - 25) + " " + d.xcentre + "," + (d.cy);
  })

function fetchValue(items, label) {
  for (i = 0; i <= items.length; i++) {
    if (items[i].label == label) {
      return items[i].value;
    }
  }
}

function fetchRadius(items, label) {
  for (i = 0; i <= items.length; i++) {
    if (items[i].label == label) {
      return Math.sqrt(items[i].value);
    }
  }
}

/*
var labels1groups = svg.selectAll(".label1").data(data);
labels1groups.enter().append("text");
labels1groups
  .attr("class", "label1")
  .attr("y", function(d, i) {
    d.y = 100;
    d.cy = 100;
    return 100;
  })
  .attr("x", function(d) {
    d.x = d.xcentre;
    d.cx = d.xcentre+50;
    return d.xcentre+50;
  })
  .text(function(d) {
    return fetchValue(d.items, "Count");
  })
  .attr("transform", function(d, i) {
            return "translate(" + (15 * i) + "," + (i * 45) + ") rotate(-45)";

  })
  .each(function(d) {
    var bbox = this.getBBox();
    d.sx = d.x - bbox.width / 2 - 2;
    d.ox = d.x + bbox.width / 2 + 2;
    d.sy = d.oy = d.y ;
  })
  .attr("text-anchor", "left");

*/

var gridSize = 100;

var labels1groups = svg.selectAll(".label2")
  .data(data)
  .enter().append("text")
  .text(function(d) {
    return fetchValue(d.items, "Count");
    //return d;
  })
  .attr("x", function(d, i) {

    d.x = i * gridSize + 50;
    d.cx = i * gridSize + 50;

    return i * gridSize;
  })
  .attr("y", function(d, i) {
    d.y = 105;
    d.cy = 50;
    return 0;
  })
  .attr("transform", function(d, i) {
    return "translate(" + gridSize / 2 + ", -6)" +
      "rotate(-45 " + ((i + 0.5) * gridSize) + " " + (-6) + ")";
  })
  .each(function(d) {
    var bbox = this.getBBox();
    d.sx = d.x - bbox.width / 2 - 2;
    d.ox = d.x + bbox.width / 2 + 2;
    d.sy = d.oy = d.y;
  })
  .style("text-anchor", "end")
  .attr("class", function(d, i) {
    return ((i >= 8 && i <= 16) ?
      "timeLabel mono axis axis-worktime" :
      "timeLabel mono axis");
  });

var pointers1groups = svg.selectAll("path.pointer1").data(data);
pointers1groups.enter().append("path");
pointers1groups
  .attr("class", "pointer1")
  .attr("marker-end", "url(#circ)");

pointers1groups
  .attr("d", function(d, i) {

    //d.y = outerRadius[i];
    //d.y = d.oy - d.cy;
    //fetchRadius(d.items, "Count");

    //(d.xcentre+100)
    // + " " + d.cx + "," + d.cy

    //return "M "+ (d.xcentre) +" 25 ,L "+ dist +" 75";

    return "M" + (d.xcentre) + "," + (d.y + d.oy - fetchRadius(d.items, "Count") - 10) + "L" + (d.xcentre + 80) + "," + d.cy;

  })
</code>```

//Older Jsfiddle
http://jsfiddle.net/59bunh8u/51/

```<code>var rawData = [{
    "name": "Twitter",
    "items" : [
        {
            "label" : "15 billion",
            "unit" : "per day",
            "value" : 1500
        },
        {
            "label" : "450 checkins",
            "unit" : "per day",
            "value" : 450
        }
    ]
},
{
    "name": "Facebook",
    "items" : [
        {
            "label" : "5 billion",
            "unit" : "per day",
            "value" : 5000
        },
        {
            "label" : "2000 checkins",
            "unit" : "per day",
            "value" : 2000
        }
    ]
}];

$.each(rawData, function(index, value) {
    var total = 0;
    var layerSet = [];
    var ratios = [25, 100];

    $.each(value["items"], function(i, v) {
        total += v["value"];
    });

    value["total"] = total;
});

var w = $this.data("width");
var h = $this.data("height");

var el = $this;

var margin = {
    top: 65,
    right: 90,
    bottom: 5,
    left: 150
};

var svg = d3.select(el[0]).append("svg")
    .attr("class", "series")
    .attr("width", w + margin.left + margin.right)
    .attr("height", h + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var defs = svg.append("svg:defs");

$.each(rawData, function(i, v) {
    circleDraw(i, v["items"]);
});

//calculates where each element should be placed
function calculateDistance (d, i, items) {
    var dcx = 0;
    for (var k = 0; k < i; k++) {
      dcx += Math.sqrt(items[k].value);
    }
    return dcx + 10 * i;
}

function getPercentage(value, total) {
    return ((value / total) * 100);
}

function circleDraw(index, data){
    data.sort(function(a, b) {
        return parseFloat(b.value) - parseFloat(a.value);
    });

    var circlelayer = svg.append("g")
      .attr("class", "circlelayer");

    var circle = circlelayer.selectAll("circle")
      .data(data);

    circle.enter().append("circle")
        .attr("class", function(d, i) {
            if (i == 0) {
              return "blue";
            }
            return "gold";
        })
        .attr("cy", 60)
        .attr("cx", function(d, i) {
            return calculateDistance(d, index, data);
        })
        .attr("r", function(d, i) {
            return Math.sqrt(d.value);
        });

    circle.exit().remove();
}
</code>```

答:
I've managed to get the diagonal markers and pointers in alignment, pointing to the correct circle colors to represent that set. I am keen to fine tune this chart and have more control over the padding and chart width/height parameters. The chart looks stable but would be keen to test it with different values and sized data sets.

/LATEST/
http://jsfiddle.net/0ht35rpb/33/

```<code>var width = 760;
var height = 400;

var svg = d3.select('#serieschart')
  .append("svg:svg")
  .attr("width", width)
  .attr("height", height);

//Count
//Checkins
//Popularity

var data = [{
  "name": "Twitter",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 200
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 1000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 30
  }]
}, {
  "name": "Facebook",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 500
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 300
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 740
  }]
}, {
  "name": "Ebay",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 4000
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 1000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 40
  }]
}, {
  "name": "Foursquare",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 2000
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 3000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 4500
  }]
}];

var legend_group = svg.append("g")
  .attr("class", "legend")
  .attr("width", 80)
  .attr("height", 100)
  .append("svg:g")
  .attr("class", "legendsection")
  .attr("transform", "translate(0,30)");

var legend = legend_group.selectAll("circle").data(data[0].items);

legend.enter().append("circle")
  .attr("cx", 70)
  .attr("cy", function(d, i) {
    return 15 * i;
  })
  .attr("r", 7)
  .attr("width", 18)
  .attr("height", 18)
  .style("fill", function(d, i) {
    return colores_google(i);
  });

legend.exit().remove();

var legendtext = legend_group.selectAll("text").data(data[0].items);

legendtext.enter().append("text")
  .attr("class", "labels")
  .attr("dy", function(d, i) {
    return 15 * i;
  })
  .attr("text-anchor", function(d) {
    return "start";
  })
  .text(function(d) {
    return d.label;
  });

legendtext.exit().remove();

var m = [80, 20, 20, 10];
var w =+ width - m[0];
var h =+ height - m[1];

var chart = svg.append("g")
  .attr("class", "serieschart")
  .attr("width", w)
  .attr("height", h);

var outerRadius = [];
// organise the data.
// Insert indices and sort items in each series
// keep a running total of max circle size in each series
// for later positioning
var x = 0;
var totalWidth = d3.sum(
  data.map(function(series) {
    series.items.forEach(function(item, i) {
      item.index = i;
    });
    series.items.sort(function(a, b) {
      return b.value - a.value;
    });
    var maxr = Math.sqrt(series.items[0].value);
    outerRadius.push(maxr);
    x += maxr;
    series.xcentre = x;
    x += maxr;
    return maxr * 2;
  })
);

// make scales for position and colour
var scale = d3.scale.linear().domain([0, totalWidth]).range([0, w]);
//var colScale = d3.scale.category10();

function colores_google(n) {
  var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f"];
  return colores_g[n % colores_g.length];
}

function fetchValue(items, label) {
  for (i = 0; i <= items.length; i++) {
    if (items[i].label == label) {
      return items[i].value;
    }
  }
}

function fetchRadius(items, label) {
  for (i = 0; i <= items.length; i++) {
    if (items[i].label == label) {
      return Math.sqrt(items[i].value);
    }
  }
}

// add a group per series, position the group according to the values and position scale  we calculated above
var groups = chart.selectAll("g.seriesGroup").data(data);
var newGroups = groups.enter().append("g").attr("class", "seriesGroup");
newGroups.append("text")
  .attr("class", "seriesName")
  .attr("text-anchor", "middle");
newGroups.append("line")
  .attr("class", "seriesName")
  .attr("y1", h - 40)
  .attr("y2", h / 2);
newGroups.append("text")
  .attr("class", "datumValue")
  .attr("y", 10)
  //.attr("transform", "rotate(-45)")
;
newGroups.append("g").attr("class", "circleGroup");
newGroups.append("g").attr("class", "datumLine")
  .append("line")
  .attr("class", "datumValue")
  .attr("y2", 40);

var focus = "Count";
groups.attr("transform", function(d) {
  return "translate(" + scale(d.xcentre) + ",0)";
});

groups.select("text.seriesName")
  .text(function(d) {
    return d.name;
  })
  .attr("y", h - 20);

groups.select("text.datumValue")
  .text(function(d) {
    return fetchValue(d.items, focus);
  })
  .attr("transform", function(d) {
    return "translate(" + ((h / 2) - 20 - scale(fetchRadius(d.items, focus))) + ",20) rotate(-45)";
  });

groups.select("line.datumValue")
  .attr("y1", function(d) {
    return (h / 2) - scale(fetchRadius(d.items, focus));
  })
  .attr("x2", function(d) {
    return (h / 2) - scale(fetchRadius(d.items, focus) + 20);
  });

// then add circles per series, biggest first as items are sorted
// colour according to index (the property we inserted previously so we can
// keep track of their original position in the series)
var circles = groups
  .select(".circleGroup")
  .selectAll("circle").data(function(d) {
    return d.items;
  }, function(d) {
    return d.index;
  });
circles.enter().append("circle").attr("cy", h / 2).attr("cx", 0);

circles
  .attr("r", function(d) {
    return scale(Math.sqrt(d.value));
  })
  .style("fill", function(d) {
    return colores_google(d.index);
  });
</code>```

Title: d3 javascript series chart

Body:
I am trying to create this particular d3 application where a series of data can be dynamically displayed like this. Each segment contains two pieces of data.

The first step is to print the circles so there is sufficient space between the series but also the largest circle is always under the smaller circle.

//version 3 -- with correct labels and legend--
http://jsfiddle.net/0ht35rpb/33/

//******version 2 fiddle******
http://jsfiddle.net/1oka61mL/10/

-- How to set the diagonal labels properly - same angles, aligned properly?
-- Add legend?
-- Mask the bottom pointers in an opposite color then continue the line in a different color?

//******Latest Jsfiddle******
http://jsfiddle.net/0ht35rpb/26/

var width = 600;
var height = 400;
var svg = d3.select('svg').attr("width", width).attr("height", height);

//Count
//Checkins
//Popularity

var data = [{
  "name": "Twitter",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 200
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 1000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 30
  }]
}, {
  "name": "Facebook",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 500
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 300
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 740
  }]
}, {
  "name": "Ebay",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 4000
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 1000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 40
  }]
}, {
  "name": "Foursquare",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 2000
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 3000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 4500
  }]
}];

var outerRadius = [];
// organise the data.
// Insert indices and sort items in each series
// keep a running total of max circle size in each series
// for later positioning
var x = 0;
var totalWidth = d3.sum(
  data.map(function(series) {
    series.items.forEach(function(item, i) {
      item.index = i;
    });
    series.items.sort(function(a, b) {
      return b.value - a.value;
    });
    var maxr = Math.sqrt(series.items[0].value);
    outerRadius.push(maxr);
    x += maxr;
    series.xcentre = x;
    x += maxr;
    return maxr * 2;
  })
);

// make scales for position and colour
var scale = d3.scale.linear().domain([0, totalWidth]).range([0, width]);
//var colScale = d3.scale.category10();

function colores_google(n) {
  var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f"];
  return colores_g[n % colores_g.length];
}

// add a group per series, position the group according to the values and position scale  we calculated above
var groups = svg.selectAll("g").data(data);
groups.enter().append("g");
groups.attr("transform", function(d) {
  return ("translate(" + d.xcentre + ",0)");
});

// then add circles per series, biggest first as items are sorted
// colour according to index (the property we inserted previously so we can
// keep track of their original position in the series)
var circles = groups.selectAll("circle").data(function(d) {
  return d.items;
}, function(d) {
  return d.index;
});
circles.enter().append("circle").attr("cy", height / 2).attr("cx", 0);

circles
  .attr("r", function(d) {
    return Math.sqrt(d.value);
  })
  .style("fill", function(d) {
    return colores_google(d.index);
  });

var labelsgroups = svg.selectAll("text").data(data);
labelsgroups.enter().append("text");
labelsgroups
  .attr("y", function(d, i) {
    d.y = 300;
    d.cy = 200;
    return 300;
  })
  .attr("x", function(d) {
    d.x = d.xcentre;
    d.cx = d.xcentre;
    return d.xcentre;
  })
  .text(function(d) {
    return d.name;
  })
  .each(function(d) {
    var bbox = this.getBBox();
    d.sx = d.x - bbox.width / 2 - 2;
    d.ox = d.x + bbox.width / 2 + 2;
    d.sy = d.oy = d.y + 5;
  })
  .attr("text-anchor", "middle");

var pointersgroups = svg.selectAll("path.pointer").data(data);
pointersgroups.enter().append("path");
pointersgroups
  .attr("class", "pointer")
  .attr("marker-end", "url(#circ)");

pointersgroups
  .attr("d", function(d) {
    return "M" + (d.xcentre) + "," + (d.oy - 25) + "L" + (d.xcentre) + "," + (d.sy - 25) + " " + d.xcentre + "," + (d.cy);
  })

function fetchValue(items, label) {
  for (i = 0; i <= items.length; i++) {
    if (items[i].label == label) {
      return items[i].value;
    }
  }
}

function fetchRadius(items, label) {
  for (i = 0; i <= items.length; i++) {
    if (items[i].label == label) {
      return Math.sqrt(items[i].value);
    }
  }
}

/*
var labels1groups = svg.selectAll(".label1").data(data);
labels1groups.enter().append("text");
labels1groups
  .attr("class", "label1")
  .attr("y", function(d, i) {
    d.y = 100;
    d.cy = 100;
    return 100;
  })
  .attr("x", function(d) {
    d.x = d.xcentre;
    d.cx = d.xcentre+50;
    return d.xcentre+50;
  })
  .text(function(d) {
    return fetchValue(d.items, "Count");
  })
  .attr("transform", function(d, i) {
            return "translate(" + (15 * i) + "," + (i * 45) + ") rotate(-45)";

  })
  .each(function(d) {
    var bbox = this.getBBox();
    d.sx = d.x - bbox.width / 2 - 2;
    d.ox = d.x + bbox.width / 2 + 2;
    d.sy = d.oy = d.y ;
  })
  .attr("text-anchor", "left");

*/

var gridSize = 100;

var labels1groups = svg.selectAll(".label2")
  .data(data)
  .enter().append("text")
  .text(function(d) {
    return fetchValue(d.items, "Count");
    //return d;
  })
  .attr("x", function(d, i) {

    d.x = i * gridSize + 50;
    d.cx = i * gridSize + 50;

    return i * gridSize;
  })
  .attr("y", function(d, i) {
    d.y = 105;
    d.cy = 50;
    return 0;
  })
  .attr("transform", function(d, i) {
    return "translate(" + gridSize / 2 + ", -6)" +
      "rotate(-45 " + ((i + 0.5) * gridSize) + " " + (-6) + ")";
  })
  .each(function(d) {
    var bbox = this.getBBox();
    d.sx = d.x - bbox.width / 2 - 2;
    d.ox = d.x + bbox.width / 2 + 2;
    d.sy = d.oy = d.y;
  })
  .style("text-anchor", "end")
  .attr("class", function(d, i) {
    return ((i >= 8 && i <= 16) ?
      "timeLabel mono axis axis-worktime" :
      "timeLabel mono axis");
  });

var pointers1groups = svg.selectAll("path.pointer1").data(data);
pointers1groups.enter().append("path");
pointers1groups
  .attr("class", "pointer1")
  .attr("marker-end", "url(#circ)");

pointers1groups
  .attr("d", function(d, i) {

    //d.y = outerRadius[i];
    //d.y = d.oy - d.cy;
    //fetchRadius(d.items, "Count");

    //(d.xcentre+100)
    // + " " + d.cx + "," + d.cy

    //return "M "+ (d.xcentre) +" 25 ,L "+ dist +" 75";

    return "M" + (d.xcentre) + "," + (d.y + d.oy - fetchRadius(d.items, "Count") - 10) + "L" + (d.xcentre + 80) + "," + d.cy;

  })

//Older Jsfiddle
http://jsfiddle.net/59bunh8u/51/

var rawData = [{
    "name": "Twitter",
    "items" : [
        {
            "label" : "15 billion",
            "unit" : "per day",
            "value" : 1500
        },
        {
            "label" : "450 checkins",
            "unit" : "per day",
            "value" : 450
        }
    ]
},
{
    "name": "Facebook",
    "items" : [
        {
            "label" : "5 billion",
            "unit" : "per day",
            "value" : 5000
        },
        {
            "label" : "2000 checkins",
            "unit" : "per day",
            "value" : 2000
        }
    ]
}];

$.each(rawData, function(index, value) {
    var total = 0;
    var layerSet = [];
    var ratios = [25, 100];

    $.each(value["items"], function(i, v) {
        total += v["value"];
    });

    value["total"] = total;
});

var w = $this.data("width");
var h = $this.data("height");

var el = $this;

var margin = {
    top: 65,
    right: 90,
    bottom: 5,
    left: 150
};

var svg = d3.select(el[0]).append("svg")
    .attr("class", "series")
    .attr("width", w + margin.left + margin.right)
    .attr("height", h + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var defs = svg.append("svg:defs");

$.each(rawData, function(i, v) {
    circleDraw(i, v["items"]);
});

//calculates where each element should be placed
function calculateDistance (d, i, items) {
    var dcx = 0;
    for (var k = 0; k < i; k++) {
      dcx += Math.sqrt(items[k].value);
    }
    return dcx + 10 * i;
}

function getPercentage(value, total) {
    return ((value / total) * 100);
}

function circleDraw(index, data){
    data.sort(function(a, b) {
        return parseFloat(b.value) - parseFloat(a.value);
    });

    var circlelayer = svg.append("g")
      .attr("class", "circlelayer");

    var circle = circlelayer.selectAll("circle")
      .data(data);

    circle.enter().append("circle")
        .attr("class", function(d, i) {
            if (i == 0) {
              return "blue";
            }
            return "gold";
        })
        .attr("cy", 60)
        .attr("cx", function(d, i) {
            return calculateDistance(d, index, data);
        })
        .attr("r", function(d, i) {
            return Math.sqrt(d.value);
        });

    circle.exit().remove();
}

Body:
I've managed to get the diagonal markers and pointers in alignment, pointing to the correct circle colors to represent that set. I am keen to fine tune this chart and have more control over the padding and chart width/height parameters. The chart looks stable but would be keen to test it with different values and sized data sets.

/LATEST/
http://jsfiddle.net/0ht35rpb/33/

var width = 760;
var height = 400;

var svg = d3.select('#serieschart')
  .append("svg:svg")
  .attr("width", width)
  .attr("height", height);

//Count
//Checkins
//Popularity

var data = [{
  "name": "Twitter",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 200
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 1000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 30
  }]
}, {
  "name": "Facebook",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 500
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 300
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 740
  }]
}, {
  "name": "Ebay",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 4000
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 1000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 40
  }]
}, {
  "name": "Foursquare",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 2000
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 3000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 4500
  }]
}];

var legend_group = svg.append("g")
  .attr("class", "legend")
  .attr("width", 80)
  .attr("height", 100)
  .append("svg:g")
  .attr("class", "legendsection")
  .attr("transform", "translate(0,30)");

var legend = legend_group.selectAll("circle").data(data[0].items);

legend.enter().append("circle")
  .attr("cx", 70)
  .attr("cy", function(d, i) {
    return 15 * i;
  })
  .attr("r", 7)
  .attr("width", 18)
  .attr("height", 18)
  .style("fill", function(d, i) {
    return colores_google(i);
  });

legend.exit().remove();

var legendtext = legend_group.selectAll("text").data(data[0].items);

legendtext.enter().append("text")
  .attr("class", "labels")
  .attr("dy", function(d, i) {
    return 15 * i;
  })
  .attr("text-anchor", function(d) {
    return "start";
  })
  .text(function(d) {
    return d.label;
  });

legendtext.exit().remove();

var m = [80, 20, 20, 10];
var w =+ width - m[0];
var h =+ height - m[1];

var chart = svg.append("g")
  .attr("class", "serieschart")
  .attr("width", w)
  .attr("height", h);

var outerRadius = [];
// organise the data.
// Insert indices and sort items in each series
// keep a running total of max circle size in each series
// for later positioning
var x = 0;
var totalWidth = d3.sum(
  data.map(function(series) {
    series.items.forEach(function(item, i) {
      item.index = i;
    });
    series.items.sort(function(a, b) {
      return b.value - a.value;
    });
    var maxr = Math.sqrt(series.items[0].value);
    outerRadius.push(maxr);
    x += maxr;
    series.xcentre = x;
    x += maxr;
    return maxr * 2;
  })
);

// make scales for position and colour
var scale = d3.scale.linear().domain([0, totalWidth]).range([0, w]);
//var colScale = d3.scale.category10();

function colores_google(n) {
  var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f"];
  return colores_g[n % colores_g.length];
}

function fetchValue(items, label) {
  for (i = 0; i <= items.length; i++) {
    if (items[i].label == label) {
      return items[i].value;
    }
  }
}

function fetchRadius(items, label) {
  for (i = 0; i <= items.length; i++) {
    if (items[i].label == label) {
      return Math.sqrt(items[i].value);
    }
  }
}

// add a group per series, position the group according to the values and position scale  we calculated above
var groups = chart.selectAll("g.seriesGroup").data(data);
var newGroups = groups.enter().append("g").attr("class", "seriesGroup");
newGroups.append("text")
  .attr("class", "seriesName")
  .attr("text-anchor", "middle");
newGroups.append("line")
  .attr("class", "seriesName")
  .attr("y1", h - 40)
  .attr("y2", h / 2);
newGroups.append("text")
  .attr("class", "datumValue")
  .attr("y", 10)
  //.attr("transform", "rotate(-45)")
;
newGroups.append("g").attr("class", "circleGroup");
newGroups.append("g").attr("class", "datumLine")
  .append("line")
  .attr("class", "datumValue")
  .attr("y2", 40);

var focus = "Count";
groups.attr("transform", function(d) {
  return "translate(" + scale(d.xcentre) + ",0)";
});

groups.select("text.seriesName")
  .text(function(d) {
    return d.name;
  })
  .attr("y", h - 20);

groups.select("text.datumValue")
  .text(function(d) {
    return fetchValue(d.items, focus);
  })
  .attr("transform", function(d) {
    return "translate(" + ((h / 2) - 20 - scale(fetchRadius(d.items, focus))) + ",20) rotate(-45)";
  });

groups.select("line.datumValue")
  .attr("y1", function(d) {
    return (h / 2) - scale(fetchRadius(d.items, focus));
  })
  .attr("x2", function(d) {
    return (h / 2) - scale(fetchRadius(d.items, focus) + 20);
  });

// then add circles per series, biggest first as items are sorted
// colour according to index (the property we inserted previously so we can
// keep track of their original position in the series)
var circles = groups
  .select(".circleGroup")
  .selectAll("circle").data(function(d) {
    return d.items;
  }, function(d) {
    return d.index;
  });
circles.enter().append("circle").attr("cy", h / 2).attr("cx", 0);

circles
  .attr("r", function(d) {
    return scale(Math.sqrt(d.value));
  })
  .style("fill", function(d) {
    return colores_google(d.index);
  });


来源: stackexchange

问:
Parsing a Quickbook IIF format file
I'm working with Quickbook's IIF file format and I need to write a parser to read and write IIF files and I'm running into some issues reading the files.

The files are simple, they're tab deliminated. Every line is either a table definition or a row. Definitions begin with'!' and the table name, and rows begin with just the table name. Here's the problem I'm running into: some of the fields allow line breaks.

When I first encountered this, I thought, okay just parse it tab by tab instead of line by line, but to do that I had to replace the line breaks with tabs, and wound up with more values than there were columns, but I wound up with the values with line breaks spread out across too many columns.

How would you parse such a file?

Edit: An example

```<code>!CUST   NAME    REFNUM  TIMESTAMP   BADDR1  BADDR2  BADDR3  BADDR4  BADDR5  SADDR1  SADDR2  SADDR3  SADDR4  SADDR5  PHONE1  PHONE2  FAXNUM  CONT1   CONT2   CTYPE   TERMS   TAXABLE LIMIT   RESALENUM   REP TAXITEM NOTEPAD SALUTATION  COMPANYNAME FIRSTNAME   MIDINIT LASTNAME    CUSTFLD1    CUSTFLD2    CUSTFLD3    CUSTFLD4    CUSTFLD5    CUSTFLD6    CUSTFLD7    CUSTFLD8    CUSTFLD9    CUSTFLD10   CUSTFLD11   CUSTFLD12   CUSTFLD13   CUSTFLD14   CUSTFLD15   JOBDESC JOBTYPE JOBSTATUS   JOBSTART    JOBPROJEND  JOBEND  HIDDEN  DELCOUNT
CUST    St. Mark    359 1176670332  Saint Mark Catholic Church  609 W Main St   City, State Zip
!CLASS  NAME    REFNUM  TIMESTAMP   HIDDEN  DELCOUNT
!INVITEM    NAME    REFNUM  TIMESTAMP   INVITEMTYPE DESC    PURCHASEDESC    ACCNT   ASSETACCNT  COGSACCNT   QNTY    QNTY    PRICE   COST    TAXABLE PAYMETH TAXVEND TAXDIST PREFVEND    REORDERPOINT    EXTRA   CUSTFLD1    CUSTFLD2    CUSTFLD3    CUSTFLD4    CUSTFLD5    DEP_TYPE    ISPASSEDTHRU    HIDDEN  DELCOUNT    USEID
INVITEM Labor   1   1119915308  SERV    Labor                                                                                0
!TIMEACT    DATE    JOB EMP ITEM    PITEM   DURATION    PROJ    NOTE    XFERTOPAYROLL   BILLINGSTATUS
TIMEACT 3/8/08  876 Development Jane Doe {Consultant}   Labor       00:15       Renewing all domain name for 876 Development.
REIMBURSEMENT: 44.72 for one year renewal on all domain names.  N   1
TIMEACT 3/17/08 Greg:Bridge Jane Doe {Consultant}   Labor       01:00       Preparing Studio    N   1
TIMEACT 3/17/08 John Doe and Associates Jane Doe {Consultant}   Labor       00:06       REIMBURSEMENT: Toner cartridge on ebay & Fuser from FastPrinters- ask wendell before invoicing to see if this fixed the problem
49.99 (include tax) toner
$175.18 (include tax) fuser
    N   1
TIMEACT 3/17/08 John Doe II Jane Doe {Consultant}   Labor       01:00       Fixing Kandis's computer - replaced entire computer with similar system N   1
</code>```

答: Why not replace line breaks with spaces instead of tabs?</p>

OwnerDisplayName: Malfist

ContentLicense: CC BY-SA 3.0

Title: Parsing a Quickbook IIF format file

Body:
I'm working with Quickbook's IIF file format and I need to write a parser to read and write IIF files and I'm running into some issues reading the files.

The files are simple, they're tab deliminated. Every line is either a table definition or a row. Definitions begin with'!' and the table name, and rows begin with just the table name. Here's the problem I'm running into: some of the fields allow line breaks.

When I first encountered this, I thought, okay just parse it tab by tab instead of line by line, but to do that I had to replace the line breaks with tabs, and wound up with more values than there were columns, but I wound up with the values with line breaks spread out across too many columns.

How would you parse such a file?

Edit: An example

!CUST   NAME    REFNUM  TIMESTAMP   BADDR1  BADDR2  BADDR3  BADDR4  BADDR5  SADDR1  SADDR2  SADDR3  SADDR4  SADDR5  PHONE1  PHONE2  FAXNUM  CONT1   CONT2   CTYPE   TERMS   TAXABLE LIMIT   RESALENUM   REP TAXITEM NOTEPAD SALUTATION  COMPANYNAME FIRSTNAME   MIDINIT LASTNAME    CUSTFLD1    CUSTFLD2    CUSTFLD3    CUSTFLD4    CUSTFLD5    CUSTFLD6    CUSTFLD7    CUSTFLD8    CUSTFLD9    CUSTFLD10   CUSTFLD11   CUSTFLD12   CUSTFLD13   CUSTFLD14   CUSTFLD15   JOBDESC JOBTYPE JOBSTATUS   JOBSTART    JOBPROJEND  JOBEND  HIDDEN  DELCOUNT
CUST    St. Mark    359 1176670332  Saint Mark Catholic Church  609 W Main St   City, State Zip
!CLASS  NAME    REFNUM  TIMESTAMP   HIDDEN  DELCOUNT
!INVITEM    NAME    REFNUM  TIMESTAMP   INVITEMTYPE DESC    PURCHASEDESC    ACCNT   ASSETACCNT  COGSACCNT   QNTY    QNTY    PRICE   COST    TAXABLE PAYMETH TAXVEND TAXDIST PREFVEND    REORDERPOINT    EXTRA   CUSTFLD1    CUSTFLD2    CUSTFLD3    CUSTFLD4    CUSTFLD5    DEP_TYPE    ISPASSEDTHRU    HIDDEN  DELCOUNT    USEID
INVITEM Labor   1   1119915308  SERV    Labor                                                                                0
!TIMEACT    DATE    JOB EMP ITEM    PITEM   DURATION    PROJ    NOTE    XFERTOPAYROLL   BILLINGSTATUS
TIMEACT 3/8/08  876 Development Jane Doe {Consultant}   Labor       00:15       Renewing all domain name for 876 Development.
REIMBURSEMENT: 44.72 for one year renewal on all domain names.  N   1
TIMEACT 3/17/08 Greg:Bridge Jane Doe {Consultant}   Labor       01:00       Preparing Studio    N   1
TIMEACT 3/17/08 John Doe and Associates Jane Doe {Consultant}   Labor       00:06       REIMBURSEMENT: Toner cartridge on ebay & Fuser from FastPrinters- ask wendell before invoicing to see if this fixed the problem
49.99 (include tax) toner
$175.18 (include tax) fuser
    N   1
TIMEACT 3/17/08 John Doe II Jane Doe {Consultant}   Labor       01:00       Fixing Kandis's computer - replaced entire computer with similar system N   1

LastEditorDisplayName: Malfist

OwnerDisplayName: Dmitri Nesteruk

ContentLicense: CC BY-SA 2.5


问:
JavaScript regular expression for two-letter tokens separated by commas
I am trying to get the regular expression that accepts only characters with specific pattern like two characters separated by comma, but I am not able to get it.

Here i included the acceptable sting

```<code>string = ab,ca,ls,gz,tv......
</code>```

I tried:

```<code>/^([a-zA-Z]{2},)|([a-zA-Z]{2})*$/
</code>```

but it is not working as expected.

答:
Try this.

```<code>/^[a-z]{2}(,[a-z]{2})*$/i
</code>```

var string1 = "ab,ca,ls,gz,tv"
var string2 = "ab,c,ls"
var string3 = "ab,ca"

var regex = /^[a-z]{2}(,[a-z]{2})*$/i

document.getElementById("test").innerHTML =
    regex.test(string1) + "
" + // true
    regex.test(string2) + "
" + // false
    regex.test(string3)            // true```
<pre class="snippet-code-html lang-html prettyprint-override"><code><p id="test"></p></code>```

Body:
I am trying to get the regular expression that accepts only characters with specific pattern like two characters separated by comma, but I am not able to get it.

Here i included the acceptable sting

string = ab,ca,ls,gz,tv......

I tried:

/^([a-zA-Z]{2},)|([a-zA-Z]{2})*$/

but it is not working as expected.

Body:
Try this.

/^[a-z]{2}(,[a-z]{2})*$/i

var string1 = "ab,ca,ls,gz,tv"
var string2 = "ab,c,ls"
var string3 = "ab,ca"

var regex = /^[a-z]{2}(,[a-z]{2})*$/i

document.getElementById("test").innerHTML =
    regex.test(string1) + "<br>" + // true
    regex.test(string2) + "<br>" + // false
    regex.test(string3)            // true

<p id="test"></p>


问:
how to find the middle number in python
Given 3 numbers, I need to find which number lies between the two others.

ie,given 3,5,2
I need 3 to be returned.

I tried to implement this by going thru all three and using if else conditions to check if each is between the other two.But this seems a naive way to do this.Is there a better way?

答:
If you wish to avoid sorting, you can do:</p>

```<code>def find_median(x):
    return sum(x) - max(x) - min(x)
</code>```

Title: how to find the middle number in python

Body:
If you wish to avoid sorting, you can do:

def find_median(x):
    return sum(x) - max(x) - min(x)


问:
Twitter API tweets
I do know about the whole deprecated version of their API. I hate it, but I was following this:

Simplest PHP example for retrieving user_timeline with Twitter API version 1.1

and I got the keys working, and followed the stuff.

On the index page, it shows this:

How can I get inside and customize how my tweets look? Stupid question, I know.

答:
Convert response to json

replace url with expanded_url in message text

print in your html with Jquery $.each

Title: Twitter API tweets


问:
grails 2.4.2 ehcache plugin 1.0.5 evicts keys prematurely
Using grails 2.4.2, cache:1.1.8 and cache-ehcache:1.0.5, I find the cache only holds a single entry. As soon as a second entry is added, the first one disappears.

Configuration

BuildConfig.groovy:

```<code>compile ":cache:1.1.8"
compile ":cache-ehcache:1.0.5"
</code>```

Config.groovy:

```<code>grails.hibernate.cache.queries = true

grails {
  cache {
    order = 2000
    enabled = true
    clearAtStartup = true
    shared = true
    ehcache {
      reloadable = false
    }
  }
}

grails.cache.clearAtStartup = true

grails.cache.config = {
  cache {
    name 'siteSettings'
  }
  provider {
    updateCheck false
    monitoring 'on'
    dynamicConfig false
  }
  defaultCache {
    maxElementsInMemory 10000
    timeToIdleSeconds 600
    timeToLiveSeconds 600
    overflowToDisk false
    diskPersistent false
    memoryStoreEvictionPolicy 'LRU'
  }
  defaults {
    maxElementsInMemory 10000
    timeToIdleSeconds 600
    timeToLiveSeconds 600
    overflowToDisk false
    diskPersistent false
    memoryStoreEvictionPolicy 'LRU'
  }
}
</code>```

cached method in SettingsService.groovy:

```<code>@Cacheable(value='siteSettings')
public JSONElement getSiteSettings(Integer site){
  log.info "NOT CACHED for this request (${site})"
</code>```

Logging Output

1)  first request where site=229 (nothing cached):

```<code>    Initialised cache: siteSettings
    CacheDecoratorFactory not configured for defaultCache. Skipping for 'siteSettings'.
    siteSettings size: 0
    cacheKeys: 0
    NOT CACHED for this request (229)
    put at siteSettings: [ key = grails.plugin.cache.CustomCacheKeyGenerator$CacheKey@490f0efa, value={"test":229}, version=1, hitCount=3, CreationTime = 1489534645017, LastAccessTime = 1489534976819 ]
</code>```

2)  second request where site=229 (cache holds 229):

```<code>    siteSettings size: 1
    cacheKeys: 1
    key 229: [test:229]
</code>```

3)  first request where site=282 (cache holds 229):

```<code>    siteSettings size: 1
    cacheKeys: 1
    key 229: [test:229]
    NOT CACHED for this request (282)
    evicted from siteSettings: [ key = grails.plugin.cache.CustomCacheKeyGenerator$CacheKey@490f0efa, value={"test":229}, version=1, hitCount=3, CreationTime = 1489534645017, LastAccessTime = 1489534976819 ]
    put at siteSettings: [ key = grails.plugin.cache.CustomCacheKeyGenerator$CacheKey@492726a5, value={"test":282}, version=1, hitCount=0, CreationTime = 1489534976848, LastAccessTime = 1489534976848 ]
</code>```

4)  second request where site=282 (cache holds 282, not 229):

```<code>    siteSettings size: 1
    cacheKeys: 1
    key 282: [test:282]
</code>```

5)  third request where site=229 (cache holds 282, not 229):

```<code>    siteSettings size: 1
    cacheKeys: 1
    key 282: [test:282]
    NOT CACHED for this request (229)
    evicted from siteSettings: [ key = grails.plugin.cache.CustomCacheKeyGenerator$CacheKey@492726a5, value={"test":282}, version=1, hitCount=3, CreationTime = 1489534976848, LastAccessTime = 1489535172110 ]
    put at siteSettings: [ key = grails.plugin.cache.CustomCacheKeyGenerator$CacheKey@490f0efa, value={"test":229}, version=1, hitCount=0, CreationTime = 1489535172193, LastAccessTime = 1489535172193 ]
</code>```

Analysis

on the first request where site=229, nothing has been cached. AS EXPECTED

on the second request where site=229, the entry keyed on 229 is cached. AS EXPECTED

on the first request where site=282, the entry keyed on 229 is cached, but the entry keyed on 282 is not cached. AS EXPECTED

on the second request where site=282, the entry keyed on 282 is cached, but the entry keyed on 229 is no longer cached. UNEXPECTED - expected both keys to be cached.

on the third request where site=229, the entry keyed on 282 is still cached, but the entry keyed on 229 is not cached. UNEXPECTED - expected both keys to be cached (subsequently, 282 is evicted, while 229 is put, which matches the observed behavior)

What am I doing wrong? Thanks for your help.

答:
I'm sorry to say, but this whole thread turns out to be based on a mistake. The underlying problem was fixed by removing a line from a grails external config .properties file that appears to have masked the correct definition of grails.cache.config in Config.groovy. The external config was:

```<code>grails.cache.config.defaultCache.diskStore='java.io.tmpdir'
</code>```

The suggested fix of adding an equals-sign to the grails.cache declaration is incorrect.

Body:
Using grails 2.4.2, cache:1.1.8 and cache-ehcache:1.0.5, I find the cache only holds a single entry. As soon as a second entry is added, the first one disappears.

Configuration

BuildConfig.groovy:

compile ":cache:1.1.8"
compile ":cache-ehcache:1.0.5"

Config.groovy:

grails.hibernate.cache.queries = true

grails {
  cache {
    order = 2000
    enabled = true
    clearAtStartup = true
    shared = true
    ehcache {
      reloadable = false
    }
  }
}

grails.cache.clearAtStartup = true

grails.cache.config = {
  cache {
    name 'siteSettings'
  }
  provider {
    updateCheck false
    monitoring 'on'
    dynamicConfig false
  }
  defaultCache {
    maxElementsInMemory 10000
    timeToIdleSeconds 600
    timeToLiveSeconds 600
    overflowToDisk false
    diskPersistent false
    memoryStoreEvictionPolicy 'LRU'
  }
  defaults {
    maxElementsInMemory 10000
    timeToIdleSeconds 600
    timeToLiveSeconds 600
    overflowToDisk false
    diskPersistent false
    memoryStoreEvictionPolicy 'LRU'
  }
}

cached method in SettingsService.groovy:

@Cacheable(value='siteSettings')
public JSONElement getSiteSettings(Integer site){
  log.info "NOT CACHED for this request (${site})"

Logging Output

1)  first request where site=229 (nothing cached):

    Initialised cache: siteSettings
    CacheDecoratorFactory not configured for defaultCache. Skipping for 'siteSettings'.
    siteSettings size: 0
    cacheKeys: 0
    NOT CACHED for this request (229)
    put at siteSettings: [ key = grails.plugin.cache.CustomCacheKeyGenerator$CacheKey@490f0efa, value={"test":229}, version=1, hitCount=3, CreationTime = 1489534645017, LastAccessTime = 1489534976819 ]

2)  second request where site=229 (cache holds 229):

    siteSettings size: 1
    cacheKeys: 1
    key 229: [test:229]

3)  first request where site=282 (cache holds 229):

    siteSettings size: 1
    cacheKeys: 1
    key 229: [test:229]
    NOT CACHED for this request (282)
    evicted from siteSettings: [ key = grails.plugin.cache.CustomCacheKeyGenerator$CacheKey@490f0efa, value={"test":229}, version=1, hitCount=3, CreationTime = 1489534645017, LastAccessTime = 1489534976819 ]
    put at siteSettings: [ key = grails.plugin.cache.CustomCacheKeyGenerator$CacheKey@492726a5, value={"test":282}, version=1, hitCount=0, CreationTime = 1489534976848, LastAccessTime = 1489534976848 ]

4)  second request where site=282 (cache holds 282, not 229):

    siteSettings size: 1
    cacheKeys: 1
    key 282: [test:282]

5)  third request where site=229 (cache holds 282, not 229):

    siteSettings size: 1
    cacheKeys: 1
    key 282: [test:282]
    NOT CACHED for this request (229)
    evicted from siteSettings: [ key = grails.plugin.cache.CustomCacheKeyGenerator$CacheKey@492726a5, value={"test":282}, version=1, hitCount=3, CreationTime = 1489534976848, LastAccessTime = 1489535172110 ]
    put at siteSettings: [ key = grails.plugin.cache.CustomCacheKeyGenerator$CacheKey@490f0efa, value={"test":229}, version=1, hitCount=0, CreationTime = 1489535172193, LastAccessTime = 1489535172193 ]

Analysis

on the first request where site=229, nothing has been cached. AS EXPECTED

on the second request where site=229, the entry keyed on 229 is cached. AS EXPECTED

on the first request where site=282, the entry keyed on 229 is cached, but the entry keyed on 282 is not cached. AS EXPECTED

on the second request where site=282, the entry keyed on 282 is cached, but the entry keyed on 229 is no longer cached. UNEXPECTED - expected both keys to be cached.

on the third request where site=229, the entry keyed on 282 is still cached, but the entry keyed on 229 is not cached. UNEXPECTED - expected both keys to be cached (subsequently, 282 is evicted, while 229 is put, which matches the observed behavior)

What am I doing wrong? Thanks for your help.

Body:
I'm sorry to say, but this whole thread turns out to be based on a mistake. The underlying problem was fixed by removing a line from a grails external config .properties file that appears to have masked the correct definition of grails.cache.config in Config.groovy. The external config was:

grails.cache.config.defaultCache.diskStore='java.io.tmpdir'

The suggested fix of adding an equals-sign to the grails.cache declaration is incorrect.


问:
Java create DKIM with jDKIM
Can you give me an example for create DKIM with jDKIM?
I don't see any example for this.

http://james.apache.org/jdkim/

Thanks!

答:
Have a look if this helps. I am also starting with jDKIM. I just wrote a method to list the signature records for the input message. Puzzled how to parse the signature records.</p>

```<code>import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.james.jdkim.DKIMVerifier;
import org.apache.james.jdkim.api.SignatureRecord;
import org.apache.james.jdkim.exceptions.FailException;
import org.apache.mailet.Mail;
import org.apache.mailet.Mailet;
public class AlgorithmDkimVerification {

    public List<SignatureRecord> verifyDkim(InputStream messageStream)
    {
        DKIMVerifier verifier = new DKIMVerifier();
        List<SignatureRecord> records = null;
        try {
            records = verifier.verify(messageStream);
        } catch (IOException | FailException e) {
            e.printStackTrace();
        }
        System.out.println(records);
        return records;
    }

}
</code>```

Title: Java create DKIM with jDKIM

Body:
Have a look if this helps. I am also starting with jDKIM. I just wrote a method to list the signature records for the input message. Puzzled how to parse the signature records.

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.james.jdkim.DKIMVerifier;
import org.apache.james.jdkim.api.SignatureRecord;
import org.apache.james.jdkim.exceptions.FailException;
import org.apache.mailet.Mail;
import org.apache.mailet.Mailet;
public class AlgorithmDkimVerification {

    public List<SignatureRecord> verifyDkim(InputStream messageStream)
    {
        DKIMVerifier verifier = new DKIMVerifier();
        List<SignatureRecord> records = null;
        try {
            records = verifier.verify(messageStream);
        } catch (IOException | FailException e) {
            e.printStackTrace();
        }
        System.out.println(records);
        return records;
    }

}


问:
Rendering svg in IE 7/8
Button displays fine in FF, Chrome, Safari. Will not render in IE 7/8.

Here's the code I've been given:

```<code><!DOCTYPE html>
  <html>
    <head>
      <link rel="stylesheet" type="text/css" href="RadMenu.css">
    </head>
  <body>
     <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
     <g id="g" shape-rendering="inherit" pointer-events="all">
     <circle cx="400" cy="210" r="25.6" fill="white" stroke="#505055" strokewidth="2">
     </circle>
       <foreignObject x="383" y="192" width="32" height="32" id="PBtn16400210">
         <html>
         <body>
            <div class="Btn3D" title="" style="width: 101%; height: 100%; background-color:   rgb(218, 184, 82); text-align: center; vertical-align: middle; background-position: initial initial; background-repeat: initial initial;"></div>
         </body>
         </html>
      </foreignObject></g>
     </svg>
   </body>
</html>
</code>```

Title: Rendering svg in IE 7/8

Body:
Button displays fine in FF, Chrome, Safari. Will not render in IE 7/8.

Here's the code I've been given:

<!DOCTYPE html>

      <link rel="stylesheet" type="text/css" href="RadMenu.css">

     <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
     <g id="g" shape-rendering="inherit" pointer-events="all">
     <circle cx="400" cy="210" r="25.6" fill="white" stroke="#505055" strokewidth="2">
     </circle>
       <foreignObject x="383" y="192" width="32" height="32" id="PBtn16400210">

      </foreignObject></g>
     </svg>

Body:
Here's the solution: adding this code after the SVG.

  <!--[if lte IE 8]><img src="image.png"><![endif]-->

(Source: https://j.eremy.net/inline-svg-with-ie8-fallback-support/)

On the testing html, the image between the top and bottom buttons is a SVG, blue. For Explorer 8 is a PNG, red.

a {text-decoration:none}
button {
padding-bottom:2px;
width: 159px;
height: 29px;
border: 3px solid transparent;
border-radius: 75px;
color: #fff;
display: block;
font-weight: bold;
font-size: 1.25em;
margin: 0.75em auto;
position: relative;
cursor: pointer;
}

.btn-TOP {border: #7766A6;
  background-color: #7766A6;
}

.btn-BOT {border:#F47320;
background-color: #F47320;
}

.CENTER {margin: 0 auto;
position:relative;
display: block;
}

<a href=""><button class="btn-TOP" id="CT">TOP</button></a>

<p><?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg class="CENTER" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="160px" height="30px"
  viewBox="0 0 159 29" enable-background="new 0 0 159 29" xml:space="preserve">
<g>
 <path fill="#0072BB" d="M17.7,0.6l11.5,14L17.8,28.4h123.4l-11.4-13.9l11.5-14H17.7z"/>
 <g>
  <path fill="#FFFFFF" d="M51.3,15.8c0,1.9,0,3.2-0.1,4c-0.1,0.8-0.3,1.5-0.7,2.1c-0.4,0.6-1,1.1-1.7,1.5c-0.7,0.3-1.5,0.5-2.5,0.5
   c-0.9,0-1.7-0.2-2.4-0.5c-0.7-0.3-1.3-0.8-1.7-1.5s-0.7-1.4-0.8-2.1c-0.1-0.8-0.1-2.1-0.1-4v-3.2c0-1.9,0-3.2,0.1-4
   c0.1-0.8,0.3-1.5,0.7-2.1c0.4-0.6,1-1.1,1.7-1.5c0.7-0.3,1.5-0.5,2.5-0.5c0.9,0,1.7,0.2,2.4,0.5c0.7,0.3,1.3,0.8,1.7,1.5
   c0.4,0.7,0.7,1.4,0.8,2.1c0.1,0.8,0.1,2.1,0.1,4V15.8z M46.9,9.7c0-0.9,0-1.4-0.1-1.7c-0.1-0.2-0.3-0.4-0.5-0.4
   c-0.2,0-0.4,0.1-0.5,0.3c-0.1,0.2-0.2,0.8-0.2,1.7v8.7c0,1.1,0,1.7,0.1,2c0.1,0.3,0.3,0.4,0.6,0.4c0.3,0,0.5-0.1,0.6-0.4
   c0.1-0.3,0.1-1,0.1-2.1V9.7z"/>
  <path fill="#FFFFFF" d="M52.9,4.9H56c2.1,0,3.5,0.1,4.2,0.3c0.7,0.2,1.3,0.6,1.8,1.4c0.5,0.7,0.7,1.9,0.7,3.5
   c0,1.4-0.2,2.4-0.5,2.9c-0.3,0.5-1,0.8-1.9,0.9c0.9,0.2,1.5,0.6,1.7,1c0.3,0.4,0.5,0.8,0.6,1.1c0.1,0.3,0.1,1.3,0.1,2.8v4.9h-4.1
   v-6.2c0-1-0.1-1.6-0.2-1.8c-0.1-0.2-0.5-0.4-1.1-0.4v8.4h-4.4V4.9z M57.3,8.1v4.1c0.5,0,0.8-0.1,1-0.2c0.2-0.1,0.3-0.6,0.3-1.5v-1
   c0-0.6-0.1-1-0.3-1.2C58.1,8.2,57.8,8.1,57.3,8.1z"/>
  <path fill="#FFFFFF" d="M68.8,4.9v18.6h-4.4V4.9H68.8z"/>
  <path fill="#FFFFFF" d="M80.6,11.8h-4.4v-1.7c0-1.1,0-1.7-0.1-2c-0.1-0.3-0.3-0.4-0.6-0.4c-0.3,0-0.5,0.1-0.6,0.3
   c-0.1,0.2-0.1,0.8-0.1,1.8v8.9c0,0.8,0,1.4,0.1,1.6c0.1,0.3,0.3,0.4,0.6,0.4c0.3,0,0.5-0.1,0.7-0.4c0.1-0.3,0.2-0.9,0.2-1.7v-2.2
   h-0.9v-2.8h5.1v10h-2.8l-0.4-1.3c-0.3,0.6-0.7,1-1.1,1.3c-0.5,0.3-1,0.4-1.6,0.4c-0.7,0-1.4-0.2-2.1-0.6c-0.6-0.4-1.1-0.9-1.5-1.5
   c-0.3-0.6-0.5-1.2-0.6-1.8c-0.1-0.6-0.1-1.6-0.1-2.9v-5.5c0-1.8,0.1-3.1,0.3-3.9c0.2-0.8,0.7-1.5,1.5-2.2c0.8-0.7,1.9-1,3.2-1
   c1.3,0,2.3,0.3,3.2,0.9C79.4,6,80,6.7,80.2,7.5c0.3,0.8,0.4,2,0.4,3.5V11.8z"/>
  <path fill="#FFFFFF" d="M86.7,4.9v18.6h-4.4V4.9H86.7z"/>
  <path fill="#FFFFFF" d="M98.2,4.9v18.6h-3.8l-2.3-8.5v8.5h-3.7V4.9h3.7l2.5,8.4V4.9H98.2z"/>
  <path fill="#FFFFFF" d="M107.6,4.9l2.5,18.6h-4.5l-0.2-3.3h-1.6l-0.3,3.3H99l2.2-18.6H107.6z M105.2,16.9
   c-0.2-2.1-0.4-4.7-0.7-7.8c-0.4,3.6-0.7,6.2-0.8,7.8H105.2z"/>
  <path fill="#FFFFFF" d="M115.2,4.9v14.9h2.7v3.7h-7.1V4.9H115.2z"/>
 </g>
 <g>
  <polygon fill="#FFFF00" points="146.9,5.1 149.4,10.1 154.9,11 150.9,14.9 151.9,20.4 146.9,17.8 141.9,20.4 142.9,14.9 138.9,11
   144.4,10.1   "/>
  <polygon fill="#FFFF00" points="12.1,5.1 14.6,10.1 20.1,11 16.1,14.9 17.1,20.4 12.1,17.8 7.1,20.4 8.1,14.9 4.1,11 9.6,10.1
   "/>
 </g>
</g>
</svg>

  <!--[if lte IE 8]>
  <img src="https://image.ibb.co/juwfov/FLAG.png" class="CENTER">
<![endif]-->
</p>

<a href=""><button class="btn-BOT" id="CT">BOTTOM</button></a>

Test html:
https://danielillo.neocities.org/testSVG.html


问:
Destructor causes corruption of the heap.
I'm playing around with destructors and I don't understand why I get an error for this code when the main function terminates.

```<code>#include <iostream>
#include <math.h>
#include <string>
#include <cstdint>
#include <cassert>
using namespace std;

class RGBA {
    uint8_t _red, _blue, _green, _alpha;
    int *_arr;
    int _length;
public:
    RGBA(int *arr, int length, uint8_t r = 0, uint8_t b = 0, uint8_t g = 0, uint8_t a = 255):
      _red (r), _blue (b), _green (g), _alpha (a) {
      _arr = arr;
      _length = length;
      }
      ~RGBA() {
          cout << "Destroying object" << endl;
          delete[] _arr;
      }

    void print() {
        for (int i = 0; i < _length; ++i) {
            cout << _arr[i] << endl;
        }
        cout << static_cast<int>(_red) << " " << static_cast<int>(_blue) << " " << static_cast<int>(_green) << " " << static_cast<int>(_alpha) << endl;
    }
};

int main() {
    int arr[3] = {1,2,3};
    RGBA rgba(arr, 3);
    rgba.print();

    cin.get();
    return 0;
}
</code>```

It outputs, but then when I press Enter, it prints 'Destroying object' with the following error "This may be due to a corruption of the heap, which indicates a bug in testcpp.exe or any of the DLLs it has loaded.".

```<code>1
2
3
0 0 0 255
</code>```

I use VS2010 on Win7.

答:
In your case, this is effectively what is happening:

```<code>int arr[3] = {1,2,3};
delete[] arr;
</code>```

Your arr in main is in automatic storage. You pass it into your object, which assumes ownership and assumes the memory was dynamically allocated with new.

You should only delete [] what you new [].

Body:
I'm playing around with destructors and I don't understand why I get an error for this code when the main function terminates.

#include <iostream>
#include <math.h>
#include <string>
#include <cstdint>
#include <cassert>
using namespace std;

class RGBA {
    uint8_t _red, _blue, _green, _alpha;
    int *_arr;
    int _length;
public:
    RGBA(int *arr, int length, uint8_t r = 0, uint8_t b = 0, uint8_t g = 0, uint8_t a = 255):
      _red (r), _blue (b), _green (g), _alpha (a) {
      _arr = arr;
      _length = length;
      }
      ~RGBA() {
          cout << "Destroying object" << endl;
          delete[] _arr;
      }

    void print() {
        for (int i = 0; i < _length; ++i) {
            cout << _arr[i] << endl;
        }
        cout << static_cast<int>(_red) << " " << static_cast<int>(_blue) << " " << static_cast<int>(_green) << " " << static_cast<int>(_alpha) << endl;
    }
};

int main() {
    int arr[3] = {1,2,3};
    RGBA rgba(arr, 3);
    rgba.print();

    cin.get();
    return 0;
}

It outputs, but then when I press Enter, it prints 'Destroying object' with the following error "This may be due to a corruption of the heap, which indicates a bug in testcpp.exe or any of the DLLs it has loaded.".

1
2
3
0 0 0 255

I use VS2010 on Win7.

Body:
In your case, this is effectively what is happening:

int arr[3] = {1,2,3};
delete[] arr;

Your arr in main is in automatic storage. You pass it into your object, which assumes ownership and assumes the memory was dynamically allocated with new.

You should only delete [] what you new [].


问:
How to programmatically add/remove an image to navigation bar title in Swift 3/Xcode
So I currently have a menu bar open and close on the left side of the app, and I want a certain image to appear on the navigation bar title when I open the menu. Below is my function for opening and closing the menu.

```<code>@IBAction func openMenu(_ sender: Any) {

    if (menuShowing) {
        self.navigationController?.navigationBar.barTintColor = UIColor(red:0.00, green:0.20, blue:0.63, alpha:1.0)
        navigationItem.leftBarButtonItem?.tintColor = UIColor.white
        navigationItem.titleView = ""
        leadingConstraint.constant = -240
        shadowLeadingConstraint.constant = -250
        UIView.animate(withDuration: 0.6, animations: {
            self.view.layoutIfNeeded()
        })

    }
    else {
        self.navigationController?.navigationBar.barTintColor = UIColor.white
        navigationItem.leftBarButtonItem?.tintColor = UIColor(red:0.00, green:0.20, blue:0.63, alpha:1.0)

        let image = UIImage(named: "MenuBarTransparent")
        navigationItem.titleView = UIImageView(image: image)
        navigationItem.titleView?.frame=CGRect(x:10, y:0, width:30, height:360)

        leadingConstraint.constant = 0
        shadowLeadingConstraint.constant = 0
        UIView.animate(withDuration: 0.3, animations: {
            self.view.layoutIfNeeded()
        })
    }
    menuShowing = !menuShowing
}
</code>```

This portion of code in the above function makes the image appear when I want it to, but manipulating the x and y-coordinate has no effect whatsoever so I can't center the image correctly:

```<code>let image = UIImage(named: "MenuBarTransparent")
        navigationItem.titleView = UIImageView(image: image)
        navigationItem.titleView?.frame=CGRect(x:10, y:0, width:30,  height:360)
</code>```

Also, this portion of code from above does not let me delete the image from the nav bar title whenever I close the menu again, it says "Cannot assign value of type 'String' to type 'UIView?':

```<code>navigationItem.titleView = ""
</code>```

Thanks in advance for any help.

答: You are assigning a string to the title view. Instead of navigationItem.titleView = "" , I think you should use navigationItem.titleView = nil.

Body:
So I currently have a menu bar open and close on the left side of the app, and I want a certain image to appear on the navigation bar title when I open the menu. Below is my function for opening and closing the menu.

@IBAction func openMenu(_ sender: Any) {

    if (menuShowing) {
        self.navigationController?.navigationBar.barTintColor = UIColor(red:0.00, green:0.20, blue:0.63, alpha:1.0)
        navigationItem.leftBarButtonItem?.tintColor = UIColor.white
        navigationItem.titleView = ""
        leadingConstraint.constant = -240
        shadowLeadingConstraint.constant = -250
        UIView.animate(withDuration: 0.6, animations: {
            self.view.layoutIfNeeded()
        })

    }
    else {
        self.navigationController?.navigationBar.barTintColor = UIColor.white
        navigationItem.leftBarButtonItem?.tintColor = UIColor(red:0.00, green:0.20, blue:0.63, alpha:1.0)

        let image = UIImage(named: "MenuBarTransparent")
        navigationItem.titleView = UIImageView(image: image)
        navigationItem.titleView?.frame=CGRect(x:10, y:0, width:30, height:360)

        leadingConstraint.constant = 0
        shadowLeadingConstraint.constant = 0
        UIView.animate(withDuration: 0.3, animations: {
            self.view.layoutIfNeeded()
        })
    }
    menuShowing = !menuShowing
}

This portion of code in the above function makes the image appear when I want it to, but manipulating the x and y-coordinate has no effect whatsoever so I can't center the image correctly:

let image = UIImage(named: "MenuBarTransparent")
        navigationItem.titleView = UIImageView(image: image)
        navigationItem.titleView?.frame=CGRect(x:10, y:0, width:30,  height:360)

Also, this portion of code from above does not let me delete the image from the nav bar title whenever I close the menu again, it says "Cannot assign value of type 'String' to type 'UIView?':

navigationItem.titleView = ""

Thanks in advance for any help.


问:
Performance: Android JCIFS file reading is slow
First of all, I saw an existing question (JCIFS: file retrieval is too slow to be usable), but it was for Java, not Android, and none of the suggested answers worked.

I created a default project for Android SDK 25 (7.1.1) in Android Studio 2.3, linked the library with compile 'jcifs:jcifs:1.3.17', and typed the following simple test code. The result is below the code.

```<code>protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    jcifs.Config.setProperty("jcifs.util.loglevel", "3");
    //jcifs.Config.setProperty("jcifs.smb.client.dfs.disabled", "false");
    //jcifs.Config.setProperty("jcifs.resolveOrder", "DNS");

    try
    {
        NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("", ID, PASSWORD);
        final SmbFile smb = new SmbFile("smb://192.168.XX.XX/Share/FileName", auth);

        Thread t = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                Log.d(TAG, "Test Start");

                for(int i = 1000; i<10000; i+=1000)
                    measure(i);

                Log.d(TAG, "Test End");
            }

            private void measure(int bufferSize)
            {
                Log.d(TAG, "=====Buffer: " + bufferSize + "============");
                try
                {
                    byte[] buffer = new byte[bufferSize];
                    int read = 0;
                    InputStream str = smb.getInputStream();
                    long start = System.nanoTime();

                    while(read < 1000000)
                        read += str.read(buffer);

                    long end = System.nanoTime();
                    str.close();
                    float time = (float) ((end - start) / 1000000000d);
                    float speed = (float) read / 1048576 / time;
                    Log.d(TAG, "Time:" + time + ", size =" + read);
                    Log.d(TAG, "Speed =  " + speed + "MB/s");
                }
                catch(IOException exc)
                {
                    exc.printStackTrace();
                }
            }
        });
        t.start();
    }
    catch(Exception exc)
    {
        Log.d(TAG, exc.toString());
    }
}
</code>```

Result

```<code>Test Start
=====Buffer: 1000============
Time:2.210785, size =1000000
Speed =  0.43137363MB/s
=====Buffer: 2000============
Time:1.4158936, size =1000000
Speed =  0.6735495MB/s
=====Buffer: 3000============
Time:1.0556641, size =1002000
Speed =  0.9051948MB/s
=====Buffer: 4000============
Time:0.7543335, size =1000000
Speed =  1.2642609MB/s
=====Buffer: 5000============
Time:3.6557617, size =1000000
Speed =  0.26086885MB/s
=====Buffer: 6000============
Time:3.292389, size =1002000
Speed =  0.2902396MB/s
=====Buffer: 7000============
Time:2.9179688, size =1001000
Speed =  0.32715496MB/s
=====Buffer: 8000============
Time:2.462616, size =1000000
Speed =  0.38726068MB/s
=====Buffer: 9000============
Time:3.9379272, size =1008000
Speed =  0.24411413MB/s
Test End
</code>```

Read speed is about 0.2MB/s ~ 1.2MB/s. The device is connected to a 150Mbps Wi-Fi, so, theoretically it can achieve above 10MB/s. The SMB server is not slow either. When I copied the file to a laptop, the read speed was about 30MB/s.

Why is this so slow? What should I check? Why is the read speed about 5 times higher (1.2MB/s) if the buffer size is 4000?

By the way, I have tested copying the same file with other commercial apps. File Commander, Asus File Manager showed similary low speed, ES File Explorer showed about 2MB/s, and Solid Explorer showed about 5MB/s. Since I am pretty sure that all of them use JCIFS (albeit perhaps slightly different versions of it), there must be a way to achieve at least 5MB/s as Solid Explorer does.

答:
After using WireShark (network analysis tool) on the Windows computer, I have found that no matter which buffer size I set, the read SMB command always gives 4286 bytes to the Windows computer. It seems that SmbFileInputStream.java is using the max buffer size from the server.

But when I saw the packets from Soild Explorer, it was 32768 bytes. So, I decompiled Solid Explorer's APK (it was of course obfuscated), and saw the SmbFileInputStream.java file inside of it (that file belongs to JCIFS). It seems that the developers of Solid Explorer has modified that file, and set a bigger readSize. So, I tried a similar thing. And then I achieved 5MB/s for the same code above.

Since JCIFS comes with LGPL, the fact that Solid Explorer is using a modified JCIFS without disclosing the source code is a violation of JCIFS' licence. But, oh well, it seems a lot of Android app developers ignores licence of the libraries they use anyway. They do not even properly credit the open-source libraries they used.

ContentLicense: CC BY-SA 4.0

Body:
First of all, I saw an existing question (JCIFS: file retrieval is too slow to be usable), but it was for Java, not Android, and none of the suggested answers worked.

I created a default project for Android SDK 25 (7.1.1) in Android Studio 2.3, linked the library with compile 'jcifs:jcifs:1.3.17', and typed the following simple test code. The result is below the code.

protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    jcifs.Config.setProperty("jcifs.util.loglevel", "3");
    //jcifs.Config.setProperty("jcifs.smb.client.dfs.disabled", "false");
    //jcifs.Config.setProperty("jcifs.resolveOrder", "DNS");

    try
    {
        NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("", ID, PASSWORD);
        final SmbFile smb = new SmbFile("smb://192.168.XX.XX/Share/FileName", auth);

        Thread t = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                Log.d(TAG, "Test Start");

                for(int i = 1000; i<10000; i+=1000)
                    measure(i);

                Log.d(TAG, "Test End");
            }

            private void measure(int bufferSize)
            {
                Log.d(TAG, "=====Buffer: " + bufferSize + "============");
                try
                {
                    byte[] buffer = new byte[bufferSize];
                    int read = 0;
                    InputStream str = smb.getInputStream();
                    long start = System.nanoTime();

                    while(read < 1000000)
                        read += str.read(buffer);

                    long end = System.nanoTime();
                    str.close();
                    float time = (float) ((end - start) / 1000000000d);
                    float speed = (float) read / 1048576 / time;
                    Log.d(TAG, "Time:" + time + ", size =" + read);
                    Log.d(TAG, "Speed =  " + speed + "MB/s");
                }
                catch(IOException exc)
                {
                    exc.printStackTrace();
                }
            }
        });
        t.start();
    }
    catch(Exception exc)
    {
        Log.d(TAG, exc.toString());
    }
}

Result

Test Start
=====Buffer: 1000============
Time:2.210785, size =1000000
Speed =  0.43137363MB/s
=====Buffer: 2000============
Time:1.4158936, size =1000000
Speed =  0.6735495MB/s
=====Buffer: 3000============
Time:1.0556641, size =1002000
Speed =  0.9051948MB/s
=====Buffer: 4000============
Time:0.7543335, size =1000000
Speed =  1.2642609MB/s
=====Buffer: 5000============
Time:3.6557617, size =1000000
Speed =  0.26086885MB/s
=====Buffer: 6000============
Time:3.292389, size =1002000
Speed =  0.2902396MB/s
=====Buffer: 7000============
Time:2.9179688, size =1001000
Speed =  0.32715496MB/s
=====Buffer: 8000============
Time:2.462616, size =1000000
Speed =  0.38726068MB/s
=====Buffer: 9000============
Time:3.9379272, size =1008000
Speed =  0.24411413MB/s
Test End

Read speed is about 0.2MB/s ~ 1.2MB/s. The device is connected to a 150Mbps Wi-Fi, so, theoretically it can achieve above 10MB/s. The SMB server is not slow either. When I copied the file to a laptop, the read speed was about 30MB/s.

Why is this so slow? What should I check? Why is the read speed about 5 times higher (1.2MB/s) if the buffer size is 4000?

By the way, I have tested copying the same file with other commercial apps. File Commander, Asus File Manager showed similary low speed, ES File Explorer showed about 2MB/s, and Solid Explorer showed about 5MB/s. Since I am pretty sure that all of them use JCIFS (albeit perhaps slightly different versions of it), there must be a way to achieve at least 5MB/s as Solid Explorer does.


问:
Regex that matches only when whole pattern is found
I have this text:

arnaldo felix toro calzadilla tomo 133 l 002353 p 119 numero 119

and using this regex: t[^\s]{0,4} (\d*)\s* to find the string tomo 133, that matches the whole pattern.

Instead I'm getting 2 matches:

toro and

tomo 133

I want to match only the second one.

As you can see is not multiline, anchor or case-sensitive problem. Anchors don't solve the problem 'cause i'm not dealing with whole lines inputs.

I'm using PHP7, using preg_match_all(), but preg_match() don't make a difference.

Save the expression here in case you want to play with it https://regex101.com/r/aRxqvI/1.

Thanks for your time

答: \d* matches a digit character 0 or more times (so optional) because of the *.  You want + for 1 or more times: \d+


问:
checkbox $.change is being triggered by itself and looping because it is being modified inside $.change
I have a group of checkboxes that when you click ONE, they should ALL be checked.

When a user clicks one checkbox, it checks all the other checkboxes starting with that class name. What I want is for the user to click a checkbox, and $(".atpSelections").change is triggered only once per click.

Here's the code:

```<code>        $(".atpSelections").change(function() {
            console.log("CHANGED");

            //Check ALL other checkboxes starting with that class name:
            var className = $(this).attr("class");
            className=className.replace("atpSelections ", "");
            className=className.trim();
            className=className.split("-");

            //Get current checkbox state
            var currentState = $(this).attr("checked");

            //Now loop through all other checkboxes starting
            //with the same class name and check them:
            $("input[class*='"+className[0]+"-']").each(function(i){
                    //THIS IS TRIGGERING "$(".atpSelections").change"!!
                    if(currentState && currentState=="checked")
                    {
                        $(this).prop('checked', true);
                    }else
                    {
                        $(this).prop('checked', false);
                    }
                });
        });
</code>```

The Problem

The problem is that when the user clicks one checkbox, the $(".atpSelections").change method gets triggered over and over because $(this).prop('checked', true); triggers $(".atpSelections").change again, and it just goes round and round.

So 1 click to a checkbox triggers 100s "change" events, when I only want it triggered once.

How do I alter the checkbox's state inside $(".atpSelections").change without triggering $(".atpSelections").change again?

Attempts

I tried changing $(".atpSelections").change to $(".atpSelections").click but it had the same issue. I think $(this).prop('checked', true); triggers the click event.

Solution

I used @James 's answer and changed

var currentState = $(this).attr("checked");

to

var currentState = $(this).prop("checked") ? "checked" : "";

and it worked perfectly! Thanks.

Here's the JSFiddle: https://jsfiddle.net/zL7amo0y/

答:
I'm thinking know what is your problem, I got it with a plugin of checkboxes too.

Try this

```<code>$(".atpSelections").on('change.custom', function(e) {
   console.log("CHANGED CUSTOM");

   //Check ALL other checkboxes starting with that class name:
   var className = $(this).attr("class");
   className=className.replace("atpSelections ", "");
   className=className.trim();
   className=className.split("-");

   //Get current checkbox state
   var currentState = $(this).attr("checked");

   //Now loop through all other checkboxes starting
   //with the same class name and check them:
   $("input[class*='"+className[0]+"-']")
     .off('change.custom')
     .each(function(i){
       //THIS IS TRIGGERING "$(".atpSelections").change"!!
       if(currentState && currentState=="checked"){
         $(this).prop('checked', true);
       }else{
         $(this).prop('checked', false);
       }
   });
 });
</code>```

Normally it's okay :)

Body:
I have a group of checkboxes that when you click ONE, they should ALL be checked.

When a user clicks one checkbox, it checks all the other checkboxes starting with that class name. What I want is for the user to click a checkbox, and $(".atpSelections").change is triggered only once per click.

Here's the code:

        $(".atpSelections").change(function() {
            console.log("CHANGED");

            //Check ALL other checkboxes starting with that class name:
            var className = $(this).attr("class");
            className=className.replace("atpSelections ", "");
            className=className.trim();
            className=className.split("-");

            //Get current checkbox state
            var currentState = $(this).attr("checked");

            //Now loop through all other checkboxes starting
            //with the same class name and check them:
            $("input[class*='"+className[0]+"-']").each(function(i){
                    //THIS IS TRIGGERING "$(".atpSelections").change"!!
                    if(currentState && currentState=="checked")
                    {
                        $(this).prop('checked', true);
                    }else
                    {
                        $(this).prop('checked', false);
                    }
                });
        });

The Problem

The problem is that when the user clicks one checkbox, the $(".atpSelections").change method gets triggered over and over because $(this).prop('checked', true); triggers $(".atpSelections").change again, and it just goes round and round.

So 1 click to a checkbox triggers 100s "change" events, when I only want it triggered once.

How do I alter the checkbox's state inside $(".atpSelections").change without triggering $(".atpSelections").change again?

Attempts

I tried changing $(".atpSelections").change to $(".atpSelections").click but it had the same issue. I think $(this).prop('checked', true); triggers the click event.

Solution

I used @James 's answer and changed

var currentState = $(this).attr("checked");

to

var currentState = $(this).prop("checked") ? "checked" : "";

and it worked perfectly! Thanks.

Here's the JSFiddle: https://jsfiddle.net/zL7amo0y/

Body:
I'm thinking know what is your problem, I got it with a plugin of checkboxes too.

Try this

$(".atpSelections").on('change.custom', function(e) {
   console.log("CHANGED CUSTOM");

   //Check ALL other checkboxes starting with that class name:
   var className = $(this).attr("class");
   className=className.replace("atpSelections ", "");
   className=className.trim();
   className=className.split("-");

   //Get current checkbox state
   var currentState = $(this).attr("checked");

   //Now loop through all other checkboxes starting
   //with the same class name and check them:
   $("input[class*='"+className[0]+"-']")
     .off('change.custom')
     .each(function(i){
       //THIS IS TRIGGERING "$(".atpSelections").change"!!
       if(currentState && currentState=="checked"){
         $(this).prop('checked', true);
       }else{
         $(this).prop('checked', false);
       }
   });
 });

Normally it's okay :)


问:
How to parse parts of a string and insert them into columns
I have a column in my database that stores data like so:

```<code> Description - (Width 1 Height 1)
</code>```

I need to parse this string and insert the Width and Height into 2 new columns.

I currently have this query:

```<code>SELECT CASE
        WHEN Description LIKE '%Width %' THEN SUBSTRING(Description, CHARINDEX('Width ', Description) + 6, 1)
      END AS Width,
      CASE
        WHEN Description LIKE '%Height %' THEN SUBSTRING(Description, CHARINDEX('Height ', Description) + 7, 1)
      END AS Height
FROM table
</code>```

It works great with this query, but if I have an entry like this, it only grabs the first digit:

```<code>Description - (Width 25 Height 10)
</code>```

I know this is because I am using '1' as the length of my SUBSTRING, but I am not sure how I can make this work properly.

答:
If you're using SQL 2016, you can use STRING_SPLIT and parse the individual pieces.

If not, it's a bit more difficult:

```<code>declare @testString varchar(50) = '(Width 25 Height 10)',
        @widthStart int,
        @widthEnd int,
        @heightStart int,
        @heightEnd int

select  @widthStart = CHARINDEX('Width ', @testString),
        @heightStart = CHARINDEX('Height ', @testString)

select  @widthEnd = @widthStart + LEN('Width '),
        @heightEnd = @heightStart + LEN('Height ')

select  Width = SUBSTRING(@testString, @widthEnd, @heightStart - @widthEnd),
        Height = SUBSTRING(@testString, @heightEnd, LEN(@testString) - @heightEnd)
</code>```

Here I've made a bunch of different variables to show how SUBSTRING is working. Basically, get the index after width, and go until you hit the next space - do the same for height, except we're looking at LEN(@testString) to end it.

This will correctly return 25, 10 for Width and Height. This works as long as you can guarantee the format the string will be in - it will not work if this format changes.

Ideally, these values would be stored in separate columns in the database - then you don't need to worry about SQL splitting strings.

EDIT:

As a side note, you'll (likely) end up wanting to LTRIM(RTRIM(Width)) and Height to remove any spaces that end up in the resulting substring.

Body:
I have a column in my database that stores data like so:

 Description - (Width 1 Height 1)

I need to parse this string and insert the Width and Height into 2 new columns.

I currently have this query:

SELECT CASE
        WHEN Description LIKE '%Width %' THEN SUBSTRING(Description, CHARINDEX('Width ', Description) + 6, 1)
      END AS Width,
      CASE
        WHEN Description LIKE '%Height %' THEN SUBSTRING(Description, CHARINDEX('Height ', Description) + 7, 1)
      END AS Height
FROM table

It works great with this query, but if I have an entry like this, it only grabs the first digit:

Description - (Width 25 Height 10)

I know this is because I am using '1' as the length of my SUBSTRING, but I am not sure how I can make this work properly.

Body:
If you're using SQL 2016, you can use STRING_SPLIT and parse the individual pieces.

If not, it's a bit more difficult:

declare @testString varchar(50) = '(Width 25 Height 10)',
        @widthStart int,
        @widthEnd int,
        @heightStart int,
        @heightEnd int

select  @widthStart = CHARINDEX('Width ', @testString),
        @heightStart = CHARINDEX('Height ', @testString)

select  @widthEnd = @widthStart + LEN('Width '),
        @heightEnd = @heightStart + LEN('Height ')

select  Width = SUBSTRING(@testString, @widthEnd, @heightStart - @widthEnd),
        Height = SUBSTRING(@testString, @heightEnd, LEN(@testString) - @heightEnd)

Here I've made a bunch of different variables to show how SUBSTRING is working. Basically, get the index after width, and go until you hit the next space - do the same for height, except we're looking at LEN(@testString) to end it.

This will correctly return 25, 10 for Width and Height. This works as long as you can guarantee the format the string will be in - it will not work if this format changes.

Ideally, these values would be stored in separate columns in the database - then you don't need to worry about SQL splitting strings.

EDIT:

As a side note, you'll (likely) end up wanting to LTRIM(RTRIM(Width)) and Height to remove any spaces that end up in the resulting substring.


问:
Gem::LoadError when updating rubyntlm
I just update rubyntlm and then did gem cleanup
now none of the gem command works!
What should I do?

/opt/chefdk/embedded/lib/ruby/site_ruby/2.1.0/rubygems/dependency.rb:319:in
  to_specs': Could not find 'rubyntlm' (= 0.6.0) - did find:
  [rubyntlm-0.6.1] (Gem::LoadError) Checked in
  'GEM_PATH=/root/.chefdk/gem/ruby/2.1.0:/opt/chefdk/embedded/lib/ruby/gems/2.1.0',
  executegem envfor more information
          from /opt/chefdk/embedded/lib/ruby/site_ruby/2.1.0/rubygems/dependency.rb:328:in
  to_spec'
          from /opt/chefdk/embedded/lib/ruby/site_ruby/2.1.0/rubygems/core_ext/kernel_gem.rb:65:in
  `gem'

答: Erase ~/.chefdk/gem and it should be better. For the future, don't run things as root, ChefDK is intended for use on user workstations</p>

Title: Gem::LoadError when updating rubyntlm


问:
Safari javascript console getElementById returning null
I am trying to find an element on a page and set its value from the safari console, I am able to get the exact same thing working on chrome but not safari. The page I am using is a Shopify payment page on this site https://kith.com. To reach it you have to add and item and pretend to checkout

Page should look like this

The javascript I am using is

```<code>document.getElementById('number').value = '000011112222333';
</code>```

Safari returns a TypeError: null is not a object message.

Here is the form code

```<code><form>
    <label for="number" class="visually-hidden" aria-hidden="true">Credit Card Number</label>
      <input autocomplete="cc-number" id="number" name="number" type="tel" aria-describedby="error-for-number" data-current-field="number" class="input-placeholder-color--lvl-34" placeholder="Card number" style="color: rgb(51, 51, 51); font-family: Lato; padding: 0.94em 0.8em; transition: padding 0.2s ease-out;">
      <span id="error-for-number" class="input-error-message visually-hidden"></span>

    <label for="name" class="visually-hidden" aria-hidden="true">Name on card</label>
      <input autocomplete="cc-name" id="name" name="name" type="text" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    <label for="expiry_month" class="visually-hidden" aria-hidden="true">Expiry month</label>
      <input autocomplete="cc-exp-month" id="expiry_month" name="expiry_month" type="tel" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    <label for="expiry_year" class="visually-hidden" aria-hidden="true">Expiry year</label>
      <input autocomplete="cc-exp-year" id="expiry_year" name="expiry_year" type="tel" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    <label for="expiry" class="visually-hidden" aria-hidden="true">MM / YY</label>
      <input autocomplete="cc-exp" id="expiry" name="expiry" type="tel" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    <label for="verification_value" class="visually-hidden" aria-hidden="true">CVV</label>
      <input autocomplete="off" id="verification_value" name="verification_value" type="tel" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    <label for="issue_date" class="visually-hidden" aria-hidden="true">Issue date (MM / YY)</label>
      <input autocomplete="off" id="issue_date" name="issue_date" type="tel" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    <label for="issue_number" class="visually-hidden" aria-hidden="true">Issue number</label>
      <input autocomplete="off" id="issue_number" name="issue_number" type="tel" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    <button type="submit" class="visually-hidden" tabindex="-1">
<script src="https://checkout.shopifycs.com/build/boot-2a790b3233.js"></script>
</code>```

答: You can check the order of the 'number' element and the script. The element must have been defined before the access via script. </p>

Body:
I am trying to find an element on a page and set its value from the safari console, I am able to get the exact same thing working on chrome but not safari. The page I am using is a Shopify payment page on this site https://kith.com. To reach it you have to add and item and pretend to checkout

Page should look like this

The javascript I am using is

document.getElementById('number').value = '000011112222333';

Safari returns a TypeError: null is not a object message.

Here is the form code

<form>
    Credit Card Number
      <input autocomplete="cc-number" id="number" name="number" type="tel" aria-describedby="error-for-number" data-current-field="number" class="input-placeholder-color--lvl-34" placeholder="Card number" style="color: rgb(51, 51, 51); font-family: Lato; padding: 0.94em 0.8em; transition: padding 0.2s ease-out;">

    Name on card
      <input autocomplete="cc-name" id="name" name="name" type="text" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    Expiry month
      <input autocomplete="cc-exp-month" id="expiry_month" name="expiry_month" type="tel" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    Expiry year
      <input autocomplete="cc-exp-year" id="expiry_year" name="expiry_year" type="tel" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    MM / YY
      <input autocomplete="cc-exp" id="expiry" name="expiry" type="tel" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    CVV
      <input autocomplete="off" id="verification_value" name="verification_value" type="tel" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    Issue date (MM / YY)
      <input autocomplete="off" id="issue_date" name="issue_date" type="tel" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    Issue number
      <input autocomplete="off" id="issue_number" name="issue_number" type="tel" class="visually-hidden" aria-hidden="true" data-honeypot-field="" tabindex="-1">

    <button type="submit" class="visually-hidden" tabindex="-1">


问:
T-SQL: calculate age then add character to result
Been stuck on this one for a while now. Let's say I have a Client table like the one here:

```<code>Name   BirthDayNum   BirthMonthNum   BirthYearNum
--------------------------------------------------
John       23             12             1965
Jane        4              9             1975
Joe         6              3             1953
</code>```

Currently I am calculating the age using this syntax: (sorry if it is hard to read)

```<code>DATEDIFF(year, CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2))
+ '-' + CAST(client.BirthDayNum AS varchar(2))
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101), GETDATE())
- (CASE WHEN dateadd(YY, DATEDIFF(year, CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2))
+ '-' + CAST(client.BirthDayNum AS varchar(2))
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101), GETDATE()),
CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2))
+ '-' + CAST(client.BirthDayNum AS varchar(2))
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101)) > getdate() THEN 1 ELSE 0 END) AS 'Client Age'
</code>```

This will give me the age in years. Of course if I want months, I just change the DATEDIFF(year to month. So, what I am trying to do now is this.

Continue to calculate the age, but instead of returning either years or months, I would like to return the age in years and months, but also, concat a 'y' and 'm' within the value as well.  Ex.  41y 11m for Jane above.

So basically I am trying to figure out how to add a char to the return value, as well as calculate the remaining months beyond the year calculation.

Any help would be greatly appreciated!

答:
Yes it is easier to save as DOB.. But one simple method

```<code>select concat( floor(datediff(year, datefromparts(birthyearnum,birthmonthnum,birthdaynum), getdate()))-1, 'y ', datediff(month, datefromparts(birthyearnum,birthmonthnum,birthdaynum), getdate())%12, 'm')
    from #yourDates
</code>```

How age for 1965 is 41y?

Input table:

```<code>create table #yourdates(Name varchar(10), BirthdayNum int, BirthMonthNum int, BirthYearNum int)

insert into #yourdates
(Name, BirthdayNum, BirthMonthNum, BirthYearNum) values
 ('John',      23        ,     12     ,        1965  )
,('Jane',       4        ,      9     ,        1975  )
,('Joe ',       6        ,      3     ,        1953  )
</code>```

Body:
Been stuck on this one for a while now. Let's say I have a Client table like the one here:

Name   BirthDayNum   BirthMonthNum   BirthYearNum
--------------------------------------------------
John       23             12             1965
Jane        4              9             1975
Joe         6              3             1953

Currently I am calculating the age using this syntax: (sorry if it is hard to read)

DATEDIFF(year, CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2))
+ '-' + CAST(client.BirthDayNum AS varchar(2))
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101), GETDATE())
- (CASE WHEN dateadd(YY, DATEDIFF(year, CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2))
+ '-' + CAST(client.BirthDayNum AS varchar(2))
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101), GETDATE()),
CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2))
+ '-' + CAST(client.BirthDayNum AS varchar(2))
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101)) > getdate() THEN 1 ELSE 0 END) AS 'Client Age'

This will give me the age in years. Of course if I want months, I just change the DATEDIFF(year to month. So, what I am trying to do now is this.

Continue to calculate the age, but instead of returning either years or months, I would like to return the age in years and months, but also, concat a 'y' and 'm' within the value as well.  Ex.  41y 11m for Jane above.

So basically I am trying to figure out how to add a char to the return value, as well as calculate the remaining months beyond the year calculation.

Any help would be greatly appreciated!

Body:
Yes it is easier to save as DOB.. But one simple method

select concat( floor(datediff(year, datefromparts(birthyearnum,birthmonthnum,birthdaynum), getdate()))-1, 'y ', datediff(month, datefromparts(birthyearnum,birthmonthnum,birthdaynum), getdate())%12, 'm')
    from #yourDates

How age for 1965 is 41y?

Input table:

create table #yourdates(Name varchar(10), BirthdayNum int, BirthMonthNum int, BirthYearNum int)

insert into #yourdates
(Name, BirthdayNum, BirthMonthNum, BirthYearNum) values
 ('John',      23        ,     12     ,        1965  )
,('Jane',       4        ,      9     ,        1975  )
,('Joe ',       6        ,      3     ,        1953  )


问:
R: Sum columns based on match table, merging column names
I have a data frame like this (where the letters are column names):

```<code>a   b   c   B   C   A
1   2   3   6   7   8
1   2   3   6   7   8
1   2   3   6   7   8
1   2   3   6   7   8
</code>```

And I would like to sum the columns based on this match table:

```<code>a   A
b   B
c   C
</code>```

While also merging the column names, so that the result would be:

```<code>a/A b/B c/C
9   8   10
9   8   10
9   8   10
9   8   10
</code>```

Please keep in mind that the solution need to be applicable to large data frames, so I cannot be specifying the new column names manually.

Thanks a lot!

答:
Basically involves using match a couple of times. Using @Lyngbakr's data.

```<code>#DATA
df = structure(list(a = c(1, 1, 1, 1, 1), b = c(2, 2, 2, 2, 2), c = c(3,
3, 3, 3, 3), A = c(8, 8, 8, 8, 8), C = c(7, 7, 7, 7, 7), B = c(6,
6, 6, 6, 6)), .Names = c("a", "b", "c", "A", "C", "B"), row.names = c(NA,
-5L), class = "data.frame")
df.names = structure(list(First = c("a", "b", "c"), Second = c("A", "B",
"C")), .Names = c("First", "Second"), row.names = c(NA, -3L), class = "data.frame")

toadd = which(colnames(df) %in% df.names[,1])
addto = match(df.names[,2][match(colnames(df)[toadd], df.names[,1])], colnames(df))
setNames(object = df[,addto] + df[,toadd], nm = paste(colnames(df)[toadd], colnames(df)[addto], sep = "/"))
#  a/A b/B c/C
#1   9   8  10
#2   9   8  10
#3   9   8  10
#4   9   8  10
#5   9   8  10
</code>```

Body:
I have a data frame like this (where the letters are column names):

a   b   c   B   C   A
1   2   3   6   7   8
1   2   3   6   7   8
1   2   3   6   7   8
1   2   3   6   7   8

And I would like to sum the columns based on this match table:

a   A
b   B
c   C

While also merging the column names, so that the result would be:

a/A b/B c/C
9   8   10
9   8   10
9   8   10
9   8   10

Please keep in mind that the solution need to be applicable to large data frames, so I cannot be specifying the new column names manually.

Thanks a lot!

Body:
Basically involves using match a couple of times. Using @Lyngbakr's data.

#DATA
df = structure(list(a = c(1, 1, 1, 1, 1), b = c(2, 2, 2, 2, 2), c = c(3,
3, 3, 3, 3), A = c(8, 8, 8, 8, 8), C = c(7, 7, 7, 7, 7), B = c(6,
6, 6, 6, 6)), .Names = c("a", "b", "c", "A", "C", "B"), row.names = c(NA,
-5L), class = "data.frame")
df.names = structure(list(First = c("a", "b", "c"), Second = c("A", "B",
"C")), .Names = c("First", "Second"), row.names = c(NA, -3L), class = "data.frame")

toadd = which(colnames(df) %in% df.names[,1])
addto = match(df.names[,2][match(colnames(df)[toadd], df.names[,1])], colnames(df))
setNames(object = df[,addto] + df[,toadd], nm = paste(colnames(df)[toadd], colnames(df)[addto], sep = "/"))
#  a/A b/B c/C
#1   9   8  10
#2   9   8  10
#3   9   8  10
#4   9   8  10
#5   9   8  10


问:
How to pass TestNG groups through terminal?
```<code>build.gradle

  test {
        jvmArgs "-DisParallel=true"
        useTestNG(){
            suites testngxml

        }
    }
</code>```

when i am trying to run gradlew clean test -Dgroups='sanityTests' will not run tests in that specific group but will run all tests. Can you please provide some insight on this.

答:
```<code>test {
    jvmArgs "-DisParallel=true"
    useTestNG(){
        suites testngxml
        includeGroups System.properties['groups']
    }
}
</code>```

Body:
build.gradle

  test {
        jvmArgs "-DisParallel=true"
        useTestNG(){
            suites testngxml

        }
    }

when i am trying to run gradlew clean test -Dgroups='sanityTests' will not run tests in that specific group but will run all tests. Can you please provide some insight on this.


问:
Unity 3D : Simple model make lag on mobile
I have checked Google or the Unity Community but no answers to my specific question.

Description of the problem

I am creating a simple game for Android in Low Poly Style and I want to optimize it for this platform.  All of my models are made with Blender and there working fine.

I also created a simple house, made of cube with Blender but when the player is near the house, the game lag ! So I decided to make this house with some cube in Unity 3D, to see if it is lagging:

Blue = the player, Red AND yellow = the direction where the player looks

And surprise, the game lag too! And really. I don't know why. As you can see, this is a very simple house. When the player is front of the door and can see the inside house (yellow arrow), the game lag but when the player rotate the camera to see other part of the environment (red arrow), no lag.

Attempt of resolution

I decreased the number of vertices, faces and edges for all of my Blender models including my house but this house is already lagging.

I decrease the side view of the camera player.

I checked the occlusion culling but there is nothing to do.

I recreated a new Blender file for my house but the problem is always here

I also exported my mesh in .obj/.fbx but the lag is always here

My question

What is wrong with Blender/Unity ? What can I do ?

EDIT

Here is a video of my problem. As you can see, when the player see the house, it is lagging but when the house is not visible in the camera player, pfuit, no lag: Link

Profiler

Here is the profile when I play the game on mobile:

Red part -> Player see the environnement, Yellow part -> Player look at the house. I can see in the overview screen the "Graphics.PresentAndSync" increase of 10-15% when the player sees the house. I will check that in detail.

答:
(Posted on behalf of the OP).

I have made the update of Unity 3D to the last version 5.5.2f1 and that solve my problem. I will check if others solutions can be found to this problem and give you a feedback asap but this update make clearly the difference.

Many thanks to all of you :)