From: <bra...@us...> - 2010-04-24 00:20:09
|
Revision: 3056 http://archive-access.svn.sourceforge.net/archive-access/?rev=3056&view=rev Author: bradtofel Date: 2010-04-24 00:20:03 +0000 (Sat, 24 Apr 2010) Log Message: ----------- INITIAL REV: Wayback-specific glue code to map CaptureSearchResults into partitions, and to map partitions into Graph, and HTML, (hopefully) simplifying .JSP pages wanting to use Partitions and Graphs. Added Paths: ----------- trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/ trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/CaptureSearchResultPartitionMap.java trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/PartitionPartitionMap.java trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/PartitionsToGraph.java Added: trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/CaptureSearchResultPartitionMap.java =================================================================== --- trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/CaptureSearchResultPartitionMap.java (rev 0) +++ trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/CaptureSearchResultPartitionMap.java 2010-04-24 00:20:03 UTC (rev 3056) @@ -0,0 +1,54 @@ +/* CaptureSearchResultPartitionMap + * + * $Id$: + * + * Created on Apr 8, 2010. + * + * Copyright (C) 2006 Internet Archive. + * + * This file is part of Wayback. + * + * Wayback is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * any later version. + * + * Wayback is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with Wayback; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package org.archive.wayback.partition; + +import java.util.Date; + +import org.archive.wayback.core.CaptureSearchResult; +import org.archive.wayback.util.partition.ElementPartitionMap; +import org.archive.wayback.util.partition.Partition; + +/** + * @author brad + * + */ +public class CaptureSearchResultPartitionMap + implements ElementPartitionMap<CaptureSearchResult> { + + public void addElementToPartition(CaptureSearchResult element, + Partition<CaptureSearchResult> partition) { + partition.add(element); + partition.addTotal(1); + if(element.isClosest()) { + partition.setContainsClosest(true); + } + } + + public Date elementToDate(CaptureSearchResult element) { + return element.getCaptureDate(); + } + +} Property changes on: trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/CaptureSearchResultPartitionMap.java ___________________________________________________________________ Added: svn:keywords + Author Date Revision Id Added: trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/PartitionPartitionMap.java =================================================================== --- trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/PartitionPartitionMap.java (rev 0) +++ trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/PartitionPartitionMap.java 2010-04-24 00:20:03 UTC (rev 3056) @@ -0,0 +1,60 @@ +/* PartitionPartitionMap + * + * $Id$: + * + * Created on Apr 8, 2010. + * + * Copyright (C) 2006 Internet Archive. + * + * This file is part of Wayback. + * + * Wayback is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * any later version. + * + * Wayback is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with Wayback; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package org.archive.wayback.partition; + +import java.util.Date; + +import org.archive.wayback.core.CaptureSearchResult; +import org.archive.wayback.util.partition.ElementPartitionMap; +import org.archive.wayback.util.partition.Partition; + +/** + * @author brad + * + */ +public class PartitionPartitionMap +implements ElementPartitionMap<Partition<CaptureSearchResult>> { + + /* (non-Javadoc) + * @see org.archive.wayback.util.partition.ElementPartitionMap#addElementToPartition(java.lang.Object, org.archive.wayback.util.partition.Partition) + */ + public void addElementToPartition(Partition<CaptureSearchResult> element, + Partition<Partition<CaptureSearchResult>> partition) { + partition.add(element); + partition.addTotal(element.getTotal()); + if(element.isContainsClosest()) { + partition.setContainsClosest(true); + } + } + + /* (non-Javadoc) + * @see org.archive.wayback.util.partition.ElementPartitionMap#elementToDate(java.lang.Object) + */ + public Date elementToDate(Partition<CaptureSearchResult> element) { + return element.getStart(); + } + +} Property changes on: trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/PartitionPartitionMap.java ___________________________________________________________________ Added: svn:keywords + Author Date Revision Id Added: trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/PartitionsToGraph.java =================================================================== --- trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/PartitionsToGraph.java (rev 0) +++ trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/PartitionsToGraph.java 2010-04-24 00:20:03 UTC (rev 3056) @@ -0,0 +1,567 @@ +/* PartitionsToGraph + * + * $Id$: + * + * Created on Apr 9, 2010. + * + * Copyright (C) 2006 Internet Archive. + * + * This file is part of Wayback. + * + * Wayback is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * any later version. + * + * Wayback is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with Wayback; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package org.archive.wayback.partition; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.TimeZone; + +import org.archive.wayback.ResultURIConverter; +import org.archive.wayback.core.CaptureSearchResult; +import org.archive.wayback.util.StringFormatter; +import org.archive.wayback.util.Timestamp; +import org.archive.wayback.util.graph.Graph; +import org.archive.wayback.util.graph.GraphConfiguration; +import org.archive.wayback.util.graph.RegionData; +import org.archive.wayback.util.partition.Partition; +import org.archive.wayback.util.partition.PartitionSize; +import org.archive.wayback.util.partition.Partitioner; + +/** + * @author brad + * + */ +public class PartitionsToGraph { + + public final static int NAV_COUNT = 9; + + public final static int NAV_PREV_YEAR = 0; + public final static int NAV_PREV_MONTH = 1; + public final static int NAV_PREV_DAY = 2; + public final static int NAV_PREV_CAPTURE = 3; + public final static int NAV_CURRENT = 4; + public final static int NAV_NEXT_CAPTURE = 5; + public final static int NAV_NEXT_DAY = 6; + public final static int NAV_NEXT_MONTH = 7; + public final static int NAV_NEXT_YEAR = 8; + + + private static final TimeZone TZ_UTC = TimeZone.getTimeZone("UTC"); + + private static String joinInts(int[] a) { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for(int i : a) { + if(first) { + sb.append(i); + first = false; + } else { + sb.append(",").append(i); + } + } + return sb.toString(); + } + private static void printAr(String name, int o[], int n[]) { + System.out.format("%s=========\nORIG(%s)\nNORM(%s)\n", + name,joinInts(o),joinInts(n)); + } + + private static int normalizeInt(int input, int localMax, int maxOutput) { + double ln = Math.log(localMax); + if(input == 0) { + return 0; + + } else if(input == 1) { + return 1; + } else { + double iln = Math.log(input); + double pct = iln / ln; + double num = pct * maxOutput; + int idx = (int) num; + System.out.format("%d - %f - %f - %f - %f : %d\n", + input,ln,iln,pct,num,idx); + if(input < idx) { + return input; + } else { + return idx; + } + } + } + + private static int[] normalizeTo(int input[], int max) { + int localMax = -1; + for(int i = 0; i < input.length; i++) { + if(input[i] > localMax) localMax = input[i]; + } + if(localMax < max) { + printAr("No normalization",input,input); + return input; + } + int normalized[] = new int[input.length]; + double ln = Math.log(localMax); + for(int i = 0; i < input.length; i++) { + if(input[i] == 0) { + normalized[i] = 0; + } else if(input[i] == 1) { + normalized[i] = 1; + } else { + double iln = Math.log(input[i]); + double pct = iln / ln; + double num = pct * max; + int idx = (int) num; + System.out.format("%d - %d - %f - %f - %f - %f : %d\n", + i,input[i],ln,iln,pct,num,idx); + if(input[i] < idx) { + normalized[i] = input[i]; + } else { + normalized[i] = idx; + } + } + } + printAr("NORMALIZED",input,normalized); + return normalized; + } + + public static Calendar getUTCCalendar() { + return Calendar.getInstance(TZ_UTC); + } + + public static Graph partsOfPartsToGraph(List<Partition<Partition<CaptureSearchResult>>> ppcs, + StringFormatter formatter, String formatKey, int width, int height) { + + Calendar cal = Calendar.getInstance(TZ_UTC); + // FIRST PASS TO CALCULATE MONTH DOMAIN MAX: + int maxValue = -1; + for(Partition<Partition<CaptureSearchResult>> ppc : ppcs) { + for(Partition<CaptureSearchResult> pc : ppc.list()) { + if(pc.getTotal() > maxValue) { + maxValue = pc.getTotal(); + } + } + } + + RegionData data[] = new RegionData[ppcs.size()]; + for(int y = 0; y < ppcs.size(); y++) { + int activeP = -1; + Partition<Partition<CaptureSearchResult>> ppc = ppcs.get(y); + String label = formatter.format(formatKey, ppc.getStart()); +// cal.setTime(ppc.getStart()); +// String label = String.valueOf(cal.get(Calendar.YEAR)); + List<Partition<CaptureSearchResult>> pcs = ppc.list(); + int count = pcs.size(); + int values[] = new int[count]; + for(int m = 0; m < count; m++) { + Partition<CaptureSearchResult> pc = pcs.get(m); + values[m] = normalizeInt(pc.getTotal(), maxValue, 15); + if(pc.isContainsClosest()) { + activeP = m; + } + } + data[y] = new RegionData(label, activeP, values); + } + GraphConfiguration config = new GraphConfiguration(); + return new Graph(width, height, data, config); + } + + public static List<Partition<Partition<CaptureSearchResult>>> reversePartsOfParts(List<Partition<Partition<CaptureSearchResult>>> parts) { + List<Partition<Partition<CaptureSearchResult>>> reversed = + new ArrayList<Partition<Partition<CaptureSearchResult>>>(); + for(Partition<Partition<CaptureSearchResult>> p : parts) { + reversed.add(0, p); + } + return reversed; + } + public static List<Partition<CaptureSearchResult>> reversePartsOfCaps(List<Partition<CaptureSearchResult>> parts) { + List<Partition<CaptureSearchResult>> reversed = + new ArrayList<Partition<CaptureSearchResult>>(); + for(Partition<CaptureSearchResult> p : parts) { + reversed.add(0, p); + } + return reversed; + } + public static List<CaptureSearchResult> reverseCaps(List<CaptureSearchResult> caps) { + List<CaptureSearchResult> reversed = + new ArrayList<CaptureSearchResult>(); + for(CaptureSearchResult cap : caps) { + reversed.add(0, cap); + } + return reversed; + } + + public static List<Partition<Partition<CaptureSearchResult>>> trimPartsOfParts(List<Partition<Partition<CaptureSearchResult>>> parts) { + int first = -1; + int last = -1; + for(int i = 0; i < parts.size(); i++) { + Partition<Partition<CaptureSearchResult>> p = parts.get(i); + if(p.getTotal() > 0) { + if(first == -1) { + first = i; + } + last = i; + } + } + return parts.subList(first, last+1); + } + public static List<Partition<CaptureSearchResult>> trimPartsOfCaps(List<Partition<CaptureSearchResult>> parts) { + int first = -1; + int last = -1; + for(int i = 0; i < parts.size(); i++) { + Partition<CaptureSearchResult> p = parts.get(i); + if(p.getTotal() > 0) { + if(first == -1) { + first = i; + } + last = i; + } + } + return parts.subList(first, last+1); + } + + public static Graph convertYearMonth(List<Partition<Partition<CaptureSearchResult>>> years, + int width, int height) { + + Calendar cal = Calendar.getInstance(TZ_UTC); + // FIRST PASS TO CALCULATE MONTH DOMAIN MAX: + int maxValue = -1; + for(Partition<Partition<CaptureSearchResult>> year : years) { + for(Partition<CaptureSearchResult> month : year.list()) { + if(month.getTotal() > maxValue) { + maxValue = month.getTotal(); + } + } + } + + RegionData yearRD[] = new RegionData[years.size()]; + for(int y = 0; y < years.size(); y++) { + int activeMonth = -1; + Partition<Partition<CaptureSearchResult>> year = years.get(y); + cal.setTime(year.getStart()); + String label = String.valueOf(cal.get(Calendar.YEAR)); + List<Partition<CaptureSearchResult>> months = year.list(); + if(months.size() != 12) { + throw new RuntimeException("Not 12 months..."); + } + int values[] = new int[12]; + for(int m = 0; m < 12; m++) { + Partition<CaptureSearchResult> month = months.get(m); + values[m] = normalizeInt(month.getTotal(), maxValue, 15); + if(month.isContainsClosest()) { + activeMonth = m; + } + } + yearRD[y] = new RegionData(label, activeMonth, values); + } + GraphConfiguration config = new GraphConfiguration(); + return new Graph(width, height, yearRD, config); + } + + public static String[] getTitles(CaptureSearchResult results[], + StringFormatter formatter, String property) { + int len = results.length; + String urls[] = new String[len]; + for(int i = 0; i < len; i++) { + String url = null; + if(results[i] != null) { + url = formatter.format(property, results[i].getCaptureDate()); + } + urls[i] = url; + } + return urls; + } + public static String[] getUrls(CaptureSearchResult results[], String suffix, + ResultURIConverter c) { + int len = results.length; + String urls[] = new String[len]; + for(int i = 0; i < len; i++) { + String url = null; + if(results[i] != null) { + if(suffix == null) { + url = c.makeReplayURI(results[i].getCaptureTimestamp(), + results[i].getOriginalUrl()); + } else { + url = c.makeReplayURI(results[i].getCaptureTimestamp() + + suffix, results[i].getOriginalUrl()); + } + } + urls[i] = url; + } + return urls; + } + public static String[] getUrls(CaptureSearchResult results[], + ResultURIConverter c) { + return getUrls(results,null,c); + } + + public static CaptureSearchResult[] getResults( + List<Partition<Partition<CaptureSearchResult>>> years) { + + int count = years.size(); + CaptureSearchResult results[] = new CaptureSearchResult[count]; + for(int i = 0; i < count; i++) { + Partition<Partition<CaptureSearchResult>> year = years.get(i); + CaptureSearchResult first = null; + if(year.getTotal() > 0) { + for(Partition<CaptureSearchResult> month : year.list()) { + if(month.getTotal() > 0) { + first = month.list().get(0); + break; + } + } + } + results[i] = first; + } + return results; + } + + + + public static String getFirstUrlMonth(Partition<CaptureSearchResult> month, + ResultURIConverter c) { + if(month.getTotal() > 0) { + CaptureSearchResult first = month.list().get(0); + return c.makeReplayURI(first.getCaptureTimestamp(), + first.getOriginalUrl()); + } + return null; + } + + public static String getLastUrlMonth(Partition<CaptureSearchResult> month, + ResultURIConverter c) { + if(month.getTotal() > 0) { + CaptureSearchResult last = month.list().get(month.list().size()-1); + return c.makeReplayURI(last.getCaptureTimestamp(), + last.getOriginalUrl()); + } + return null; + } + + public static String getFirstUrlYear(Partition<Partition<CaptureSearchResult>> year, + ResultURIConverter c) { + for(Partition<CaptureSearchResult> month : year.list()) { + String firstInMonth = getFirstUrlMonth(month,c); + if(firstInMonth != null) return firstInMonth; + } + return null; + } + public static String getLastUrlYear(Partition<Partition<CaptureSearchResult>> year, + ResultURIConverter c) { + List<Partition<CaptureSearchResult>> months = year.list(); + for(int i = months.size()-1; i >= 0; i--) { + String firstInMonth = getLastUrlMonth(months.get(i),c); + if(firstInMonth != null) return firstInMonth; + } + return null; + } + + + public static String[] getNavigatorLinks( + List<Partition<Partition<CaptureSearchResult>>> years, ResultURIConverter uc) { + String navs[] = new String[NAV_COUNT]; + for(int i = 0; i < NAV_COUNT; i++) { + navs[i] = null; + } + /* + * first traverse the years, grabbing: + * * the one *before* + * * the *current* + * * the one *after* + * + * the "active" year: + */ + + Partition<Partition<CaptureSearchResult>> prevYear = null; + Partition<Partition<CaptureSearchResult>> curYear = null; + Partition<Partition<CaptureSearchResult>> nextYear = null; + + for(Partition<Partition<CaptureSearchResult>> year : years) { + if(year.isContainsClosest()) { + curYear = year; + } else { + // have we seen the current one? + if(curYear == null) { + // no, track this as the "prev", and continue: + if(year.getTotal() > 0) { + prevYear = year; + } + } else { + // yes, this is the "next", remember and break: + if(year.getTotal() > 0) { + nextYear = year; + break; + } + } + } + } + if(prevYear != null) { + navs[NAV_PREV_YEAR] = getLastUrlYear(prevYear, uc); + } + if(nextYear != null) { + navs[NAV_NEXT_YEAR] = getFirstUrlYear(nextYear, uc); + } + // now on to months: + List<Partition<CaptureSearchResult>> months = curYear.list(); + + Partition<CaptureSearchResult> prevMonth = null; + Partition<CaptureSearchResult> curMonth = null; + Partition<CaptureSearchResult> nextMonth = null; + + for(Partition<CaptureSearchResult> month : months) { + if(month.isContainsClosest()) { + curMonth = month; + } else { + // have we seen the current one? + if(curMonth == null) { + // no, track this as the "prev", and continue: + if(month.getTotal() > 0) { + prevMonth = month; + } + } else { + // yes, this is the "next", remember and break: + if(month.getTotal() > 0) { + nextMonth = month; + break; + } + } + } + } + + if(prevMonth != null) { + navs[NAV_PREV_MONTH] = getLastUrlMonth(prevMonth, uc); + } else { + // assume whatever we found for prev Year is OK, even if null: + navs[NAV_PREV_MONTH] = navs[NAV_PREV_YEAR]; + } + if(nextMonth != null) { + navs[NAV_NEXT_MONTH] = getFirstUrlMonth(nextMonth, uc); + } else { + // assume whatever we found for next Year is OK, even if null: + navs[NAV_NEXT_MONTH] = navs[NAV_NEXT_YEAR]; + } + + // OK... now we're down to days... split the current month into days: + List<Partition<CaptureSearchResult>> days = splitToDays(curMonth); + + Partition<CaptureSearchResult> prevDay = null; + Partition<CaptureSearchResult> curDay = null; + Partition<CaptureSearchResult> nextDay = null; + + for(Partition<CaptureSearchResult> day : days) { + if(day.isContainsClosest()) { + curDay = day; + } else { + // have we seen the current one? + if(curDay == null) { + // no, track this as the "prev", and continue: + if(day.getTotal() > 0) { + prevDay = day; + } + } else { + // yes, this is the "next", remember and break: + if(day.getTotal() > 0) { + nextDay = day; + break; + } + } + } + } + + if(prevDay != null) { + navs[NAV_PREV_DAY] = getLastUrlMonth(prevDay, uc); + } else { + // assume whatever we found for prev Month is OK, even if null: + navs[NAV_PREV_DAY] = navs[NAV_PREV_MONTH]; + } + if(nextDay != null) { + navs[NAV_NEXT_DAY] = getFirstUrlMonth(nextDay, uc); + } else { + // assume whatever we found for next Month is OK, even if null: + navs[NAV_NEXT_DAY] = navs[NAV_NEXT_MONTH]; + } + + // FINALLY! We just need the next and prev links: + CaptureSearchResult prevResult = null; + CaptureSearchResult curResult = null; + CaptureSearchResult nextResult = null; + for(CaptureSearchResult result : curDay.list()) { + if(result.isClosest()) { + curResult = result; + } else { + // have we seen the current one? + if(curResult == null) { + // no, track this as the "prev", and continue: + prevResult = result; + } else { + // yes, this is the "next", remember and break: + nextResult = result; + break; + } + } + } + if(prevResult != null) { + navs[NAV_PREV_CAPTURE] = + uc.makeReplayURI(prevResult.getCaptureTimestamp(), + prevResult.getOriginalUrl()); + } else { + // assume whatever we found for prev Day is OK, even if null: + navs[NAV_PREV_CAPTURE] = navs[NAV_PREV_DAY]; + } + if(nextResult != null) { + navs[NAV_NEXT_CAPTURE] = + uc.makeReplayURI(nextResult.getCaptureTimestamp(), + nextResult.getOriginalUrl()); + } else { + // assume whatever we found for prev Day is OK, even if null: + navs[NAV_NEXT_CAPTURE] = navs[NAV_NEXT_DAY]; + } + + return navs; + } + + /** + * @param list + * @return + */ + private static List<Partition<CaptureSearchResult>> splitToDays( + Partition<CaptureSearchResult> month) { + CaptureSearchResultPartitionMap map = + new CaptureSearchResultPartitionMap(); + Partitioner<CaptureSearchResult> partitioner = + new Partitioner<CaptureSearchResult>(map); + PartitionSize daySize = Partitioner.daySize; + List<Partition<CaptureSearchResult>> days = partitioner.getRange(daySize, + month.getStart(), month.getEnd()); + partitioner.populate(days, month.iterator()); + return days; + } + + public static String[] getNavigators(StringFormatter formatter, CaptureSearchResult current) { + String navs[] = new String[NAV_COUNT]; + navs[NAV_PREV_YEAR] = formatter.format("graph.prevYear"); + navs[NAV_PREV_MONTH] = formatter.format("graph.prevMonth"); + navs[NAV_PREV_DAY] = formatter.format("graph.prevDay"); + navs[NAV_PREV_CAPTURE] = formatter.format("graph.prevCapture"); + + navs[NAV_CURRENT] = formatter.format("graph.current", current.getOriginalUrl(), + current.getCaptureDate()); + + navs[NAV_NEXT_CAPTURE] = formatter.format("graph.nextCapture"); + navs[NAV_NEXT_DAY] = formatter.format("graph.nextDay"); + navs[NAV_NEXT_MONTH] = formatter.format("graph.nextMonth"); + navs[NAV_NEXT_YEAR] = formatter.format("graph.nextYear"); + return navs; + } +} Property changes on: trunk/archive-access/projects/wayback/wayback-core/src/main/java/org/archive/wayback/partition/PartitionsToGraph.java ___________________________________________________________________ Added: svn:keywords + Author Date Revision Id This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |