001/* Generate a web page that contains links for the appropriate copyrights
002
003   Copyright (c) 2003-2018 The Regents of the University of California.
004   All rights reserved.
005   Permission is hereby granted, without written agreement and without
006   license or royalty fees, to use, copy, modify, and distribute this
007   software and its documentation for any purpose, provided that the above
008   copyright notice and the following two paragraphs appear in all copies
009   of this software.
010
011   IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012   FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013   ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014   THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015   SUCH DAMAGE.
016
017   THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020   PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021   CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022   ENHANCEMENTS, OR MODIFICATIONS.
023
024   PT_COPYRIGHT_VERSION_2
025   COPYRIGHTENDKEY
026 */
027package ptolemy.actor.gui;
028
029import java.io.File;
030import java.io.IOException;
031import java.net.URL;
032import java.util.Comparator;
033import java.util.HashMap;
034import java.util.HashSet;
035import java.util.Iterator;
036import java.util.Map;
037import java.util.Set;
038import java.util.TreeMap;
039
040import ptolemy.data.ArrayToken;
041import ptolemy.data.RecordToken;
042import ptolemy.data.StringToken;
043import ptolemy.data.expr.Parameter;
044import ptolemy.kernel.attributes.VersionAttribute;
045import ptolemy.kernel.util.StringAttribute;
046import ptolemy.util.ClassUtilities;
047import ptolemy.util.FileUtilities;
048
049///////////////////////////////////////////////////////////////////
050//// GenerateCopyrights
051
052/**
053   Generate an HTML file that contains links to the appropriate
054   copyrights for entities in the configuration.
055   This class looks for particular classes, and if the class is found
056   in the classpath, then a corresponding html file is included
057   in the list of copyrights.
058
059   @author Christopher Hylands
060   @version $Id$
061   @since Ptolemy II 2.0
062   @Pt.ProposedRating Red (cxh)
063   @Pt.AcceptedRating Red (cxh)
064 */
065public class GenerateCopyrights {
066    ///////////////////////////////////////////////////////////////////
067    ////                         public methods                    ////
068
069    /** Generate HTML about the copyrights for classes that might
070     *  be present in the configuration.  This method contains
071     *  a list of classes and corresponding copyrights.  If
072     *  a class in the list is present, then we generate html
073     *  that contains a link to the copyright.  Note that if the
074     *  copyright file need not be present on the local machine,
075     *  we generate a link to the copy on the Ptolemy website.
076     *
077     *  <p>If the configuration contains an _applicationName attribute
078     *  then that attributed is used as the name of the application
079     *  in the generated text.  If _applicationName is not present,
080     *  then the default name is "Ptolemy II".
081     *
082     *  <p>If the configuration contains an _applicationCopyright
083     *  StringAttribute, then the value of that attributed is used
084     *  as the location of the copyright html file.  If
085     *  _applicationCopyright is not present, then
086     *  "ptolemy/configs/doc/copyright.htm" is used.
087     *
088     *  <p>If the configuration has a parameter called
089     *  _applicationCopyrights that is an array of records where
090     *  each element is a record
091     *  <pre>
092     *  {actor="ptolemy.actor.lib.Foo", copyright="foo.htm"}
093     *  </pre>
094     *  then we add that actor/copyright pair to the list of potential
095     *  copyrights.
096     *
097     *  @param configuration The configuration to look for the
098     *  _applicationName and _applicationCopyright attributes in.
099     *  @return A String containing HTML that describes what
100     *  copyrights are used by Entities in the configuration
101     */
102    public static String generateHTML(Configuration configuration) {
103        // A Map of copyrights, where the key is a URL naming
104        // the copyright and the value is a List of entities
105        // that use that as a copyright.
106        HashMap<String, Set<String>> copyrightsMap = new HashMap<String, Set<String>>();
107
108        // Add the classnames and copyrights.
109        // Alphabetical by className.
110        _addIfClassPresent(copyrightsMap, "com.cureos.numerics.Cobyla",
111                "com/cureos/jcobyla-license.htm");
112
113        _addIfClassPresent(copyrightsMap, "com.github.sarxos.webcam.Webcam",
114                "lib/webcam-capture-license.htm");
115
116        _addIfClassPresent(copyrightsMap,
117                "com.github.ojdcheck.OpenJavaDocCheck",
118                "lib/ojdcheck-license.htm");
119
120        _addIfClassPresent(copyrightsMap, "com.kitfox.svg.app.beans.SVGIcon",
121                "lib/svgSalamander-license.htm");
122
123        _addIfClassPresent(copyrightsMap,
124                "com.jhlabs.image.AbstractBufferedImageOp",
125                "com/jhlabs/jhlabs-license.htm");
126
127        _addIfClassPresent(copyrightsMap, "com.microstar.xml.XmlParser",
128                "com/microstar/xml/aelfred-license.htm");
129
130        _addIfClassPresent(copyrightsMap, "com.sun.jna.Pointer",
131                "lib/jna-license.htm");
132
133        _addIfClassPresent(copyrightsMap, "com.sleepycat.db.Environment",
134                "ptdb/lib/db-dbxml-license.htm");
135
136        _addIfClassPresent(copyrightsMap,
137                "com.google.protobuf.MessageOrBuilder",
138                "lib/protobuf-license.htm");
139
140        _addIfFilePresent(copyrightsMap,
141                "$CLASSPATH/bin/Vergil.app/Contents/MacOS/universalJavaApplicationStub",
142                "lib/universalJavaApplicationStub-license.html");
143
144        _addIfFilePresent(copyrightsMap,
145                "$CLASSPATH/bin/CapeCode.app/Contents/MacOS/universalJavaApplicationStub",
146                "lib/universalJavaApplicationStub-license.html");
147
148        _addIfClassPresent(copyrightsMap,
149                "edu.umich.eecs.april.image.AprilTagFilter",
150                "edu/umich/eecs/april/april-license.htm");
151
152        _addIfClassPresent(copyrightsMap,
153                "edu.cmu.sphinx.api.LiveSpeechRecognizer",
154                "ptolemy/actor/lib/jjs/modules/speechRecognition/sphinx-license.htm");
155
156        _addIfClassPresent(copyrightsMap, "g4ltl.SolverUtility",
157                "lib/g4ltl-license.htm");
158
159        _addIfClassPresent(copyrightsMap, "hla.rti.jlc.RtiFactory",
160                "lib/jcerti-license.htm");
161
162        _addIfClassPresent(copyrightsMap, "interfaces.util.ChicUI",
163                "lib/chic-license.htm");
164
165        _addIfClassPresent(copyrightsMap, "io.socket.SocketIO",
166                "lib/socketio-license.htm");
167
168        _addIfClassPresent(copyrightsMap, "javax.servlet.http.HttpServlet",
169                "lib/javax.servlet-api-license.htm");
170
171        _addIfClassPresent(copyrightsMap, "jni.GenericJNIActor",
172                "jni/launcher/launcher-copyright.htm");
173
174        _addIfClassPresent(copyrightsMap,
175                "mescal.domains.mescalPE.kernel.parser",
176                "mescal/configs/doc/cup-copyright.htm");
177
178        _addIfClassPresent(copyrightsMap,
179                "net.jimblackler.Utils.YieldAdapterIterator",
180                "net/jimblackler/Utils/jimblacklerUtils-license.htm");
181
182        _addIfClassPresent(copyrightsMap, "oscP5.OscP5",
183                "lib/oscP5-license.htm");
184
185        // Used by RExpression and RExpression2 actors.
186        _addIfClassPresent(copyrightsMap,
187                "org.apache.commons.lang.StringEscapeUtils",
188                "lib/commons-license.htm");
189        _addIfClassPresent(copyrightsMap, "org.apache.commons.logging.Log",
190                "lib/commons-license.htm");
191
192        _addIfClassPresent(copyrightsMap, "org.apache.oltu.oauth2.common.OAuth",
193                "lib/org.apache.oltu.oauth2-license.htm");
194
195        _addIfClassPresent(copyrightsMap, "org.eclipse.jetty.server.Server",
196                "lib/jetty-all-license.htm");
197
198        _addIfClassPresent(copyrightsMap,
199                "org.eclipse.paho.client.mqttv3.MqttClient",
200                "lib/org.eclipse.paho.client.mqttv3-license.htm");
201
202        _addIfClassPresent(copyrightsMap, "org.json.JSONObject",
203                "org/json/json-license.htm");
204
205        _addIfClassPresent(copyrightsMap, "org.jsoup.parser.Parser",
206                "lib/jsoup-license.htm");
207
208        _addIfClassPresent(copyrightsMap, "org.mozilla.javascript.Context",
209                "lib/js-license.htm");
210
211        _addIfClassPresent(copyrightsMap, "org.junit.runner.JUnitCore",
212                "lib/junit-license.htm");
213
214        _addIfClassPresent(copyrightsMap,
215                "org.netbeans.api.visual.widget.Scene",
216                "lib/netbeans-visual-library-license.htm");
217
218        _addIfClassPresent(copyrightsMap, "org.ptolemy.fmi.driver.OutputRow",
219                "org/ptolemy/fmi/driver/fmusdk-license.htm");
220
221        // Used by RExpression2 actor.
222        _addIfClassPresent(copyrightsMap, "org.rosuda.JRI.REXP",
223                "lib/JRI-license.htm");
224
225        _addIfClassPresent(copyrightsMap,
226                "org.satlive.jsat.objects.ExternalLiteral",
227                "mescal/configs/doc/jsat-copyright.htm");
228
229        // ant is used by JSAccessor, but we can't have a class have
230        // two licenses associated with it, so we look for
231        // AccessorLibrary and include apache-ant-license.htm
232        _addIfClassPresent(copyrightsMap,
233                "org.terraswarm.accessor.AccessorLibrary",
234                "ant/apache-ant-license.htm");
235
236        _addIfClassPresent(copyrightsMap, "org.terraswarm.accessor.JSAccessor",
237                "org/terraswarm/accessor/accessors/web/accessors-license.htm");
238
239        // Vertx
240        _addIfClassPresent(copyrightsMap,
241                "com.fasterxml.jackson.core.base.GeneratorBase",
242                "lib/jackson-license.htm");
243
244        _addIfClassPresent(copyrightsMap,
245                "io.netty.handler.traffic.ChannelTrafficShapingHandler",
246                "lib/netty-license.htm");
247
248        _addIfClassPresent(copyrightsMap,
249                "org.vertx.java.spi.cluster.impl.hazelcast.HazelcastAsyncMap",
250                "lib/hazelcast-license.htm");
251
252        _addIfClassPresent(copyrightsMap, "io.vertx.core.Vertx",
253                "lib/vertx-license.htm");
254
255        _addIfClassPresent(copyrightsMap, "ptolemy.actor.gui.BrowserLauncher",
256                "ptolemy/actor/gui/BrowserLauncher-license.htm");
257        _addIfClassPresent(copyrightsMap,
258                "ptolemy.actor.gui.PortConfigurerDialog",
259                "ptolemy/actor/gui/PortConfigurerDialog-license.htm");
260        _addIfClassPresent(copyrightsMap,
261                "ptolemy.actor.gui.run.PtolemyFormEditor",
262                "com/jgoodies/jgoodies-copyright.htm");
263        _addIfClassPresent(copyrightsMap,
264                "ptolemy.actor.gui.run.RunLayoutFrame",
265                "org/mlc/mlc-copyright.htm");
266        _addIfClassPresent(copyrightsMap,
267                "ptolemy.actor.lib.colt.ColtRandomSource",
268                "ptolemy/actor/lib/colt/colt-copyright.htm");
269        _addIfClassPresent(copyrightsMap,
270                "ptolemy.actor.lib.database.DatabaseManager",
271                "com.mysql.jdbc.Driver",
272                "ptolemy/actor/lib/database/mysql-copyright.htm");
273        _addIfClassPresent(copyrightsMap, "ptolemy.actor.lib.excel.Excel",
274                "ptolemy/actor/lib/excel/jxl-copyright.htm");
275        _addIfClassPresent(copyrightsMap,
276                "ptolemy.actor.lib.fmi.fmipp.FMUModelExchange",
277                "ptolemy/actor/lib/fmi/fmipp/fmipp-license.htm");
278        /* ptolemy.actor.lib.io.comm.SerialComm */
279        _addIfClassPresent(copyrightsMap, "gnu.io.SerialPort",
280                "lib/nrjavaserial-license.htm");
281        _addIfClassPresent(copyrightsMap, "ptolemy.actor.lib.jai.JAIImageToken",
282                "ptolemy/actor/lib/jai/jai-copyright.htm");
283        _addIfClassPresent(copyrightsMap, "ptolemy.actor.lib.jjs.JavaScript",
284                "ptolemy/actor/lib/jjs/jjs-license.htm");
285        _addIfFilePresent(copyrightsMap,
286                "$CLASSPATH/ptolemy/actor/lib/jjs/external/require.js",
287                "ptolemy/actor/lib/jjs/external/require.js-license.htm");
288
289        _addIfClassPresent(copyrightsMap, "ptolemy.actor.lib.jmf.JMFImageToken",
290                "ptolemy/actor/lib/jmf/jmf-copyright.htm");
291        _addIfClassPresent(copyrightsMap, "ptolemy.actor.lib.joystick.Joystick",
292                "ptolemy/actor/lib/joystick/joystick-copyright.htm");
293        _addIfClassPresent(copyrightsMap,
294                "ptolemy.actor.lib.logic.fuzzy.FuzzyLogic",
295                "ptolemy/actor/lib/logic/fuzzy/FuzzyEngine-copyright.htm");
296        _addIfClassPresent(copyrightsMap, "javax.mail.Address",
297                "lib/javamail-license.htm");
298        _addIfClassPresent(copyrightsMap, "org.ptolemy.opencv.FaceRecognizer",
299                "lib/opencv-license.htm");
300        _addIfClassPresent(copyrightsMap,
301                "ptolemy.actor.lib.python.PythonScript",
302                "ptolemy/actor/lib/python/jython-license.htm");
303        _addIfClassPresent(copyrightsMap, "ptolemy.actor.lib.x10.X10Interface",
304                "ptolemy/actor/lib/x10/x10-copyright.htm");
305        _addIfClassPresent(copyrightsMap, "ptolemy.actor.ptalon.PtalonActor",
306                "ptolemy/actor/ptalon/ptalon-copyright.html");
307
308        _addIfClassPresent(copyrightsMap,
309                "ptolemy.backtrack.eclipse.ast.TypeAnalyzer",
310                "ptolemy/backtrack/eclipse/ast/eclipse-copyright.htm");
311
312        _addIfClassPresent(copyrightsMap,
313                "ptolemy.backtrack.util.ClassFileLoader",
314                "ptolemy/backtrack/util/gcj-copyright.html");
315
316        _addIfClassPresent(copyrightsMap,
317                "ptolemy.caltrop.actors.AbstractCalInterpreter",
318                "ptolemy/caltrop/cup-copyright.htm");
319        _addIfClassPresent(copyrightsMap,
320                "ptolemy.caltrop.actors.CalInterpreter",
321                "ptolemy/caltrop/saxon-copyright.htm");
322
323        _addIfClassPresent(copyrightsMap,
324                "ptolemy.ptolemy.cg.kernel.generic.program.procedural.fmima.FMIMACodeGenerator",
325                "ptolemy/actor/lib/fmi/ma2/fmusdk-license.htm");
326
327        _addIfClassPresent(copyrightsMap,
328                "ptolemy.copernicus.kernel.KernelMain",
329                "ptolemy/copernicus/kernel/soot-copyright.html");
330
331        _addIfClassPresent(copyrightsMap, "ptolemy.data.ontologies.Concept",
332                "ptolemy/data/ontologies/doc/udunits2Database/udunits-license.htm");
333
334        _addIfClassPresent(copyrightsMap, "ptolemy.domains.gr.kernel.GRActor",
335                "ptolemy/domains/gr/lib/java3d-copyright.htm");
336        _addIfClassPresent(copyrightsMap,
337                "ptolemy.domains.gr.lib.quicktime.MovieViewScreen2D",
338                "ptolemy/domains/gr/lib/quicktime/quicktime-copyright.htm");
339        _addIfClassPresent(copyrightsMap,
340                "ptolemy.domains.gr.lib.vr.GRTexture2D.java",
341                "ptolemy/domains/gr/lib/vr/vr-copyright.htm");
342
343        _addIfClassPresent(copyrightsMap,
344                "ptolemy.domains.gro.kernel.GRODirector",
345                "ptolemy/domains/gro/JOGL-copyright.htm");
346
347        _addIfClassPresent(copyrightsMap,
348                "ptolemy.domains.psdf.kernel.PSDFScheduler",
349                "ptolemy/domains/psdf/mapss-copyright.htm");
350
351        _addIfClassPresent(copyrightsMap,
352                "ptolemy.domains.ptinyos.util.nc2moml.MoMLLib",
353                "ptolemy/domains/ptinyos/lib/jdom-copyright.htm");
354
355        _addIfClassPresent(copyrightsMap, "ptolemy.graph.Element",
356                "ptolemy/graph/graph-license.htm");
357
358        _addIfClassPresent(copyrightsMap, "ptolemy.gui.ComponentDialog",
359                "ptolemy/gui/ComponentDialog-license.htm");
360
361        _addIfClassPresent(copyrightsMap,
362                "ptolemy.homer.widgets.ResizableImageWidget",
363                "ptolemy/homer/widgets/ResizableImageWidget-license.htm");
364
365        _addIfClassPresent(copyrightsMap, "ptolemy.matlab.Expression",
366                "ptolemy/matlab/matlab-copyright.htm");
367
368        _addIfClassPresent(copyrightsMap, "ptolemy.media.Audio",
369                "ptolemy/media/Audio-license.htm");
370
371        _addIfClassPresent(copyrightsMap, "ptolemy.util.DoubleUtilities",
372                "ptolemy/util/DoubleUtilities-license.htm");
373
374        _addIfClassPresent(copyrightsMap, "ptolemy.util.test.junit.TclTests",
375                "lib/JUnitParams-license.htm");
376
377        _addIfClassPresent(copyrightsMap,
378                "ptolemy.vergil.basic.export.html.ExportHTMLAction",
379                "ptolemy/vergil/basic/export/html/javascript/javascript-license.htm");
380
381        _addIfClassPresent(copyrightsMap,
382                "ptolemy.vergil.basic.export.html.ExportToWeb",
383                "ptolemy/vergil/basic/export/html/javascript/fancybox/fancybox-license.htm");
384
385        _addIfClassPresent(copyrightsMap,
386                "ptolemy.vergil.basic.export.itextpdf.ExportPDFAction",
387                "ptolemy/vergil/basic/export/itextpdf/itextpdf-copyright.htm");
388
389        _addIfClassPresent(copyrightsMap,
390                "ptolemy.vergil.basic.layout.kieler.KielerLayout",
391                "lib/guava-license.htm");
392        _addIfClassPresent(copyrightsMap,
393                "ptolemy.vergil.basic.layout.kieler.KielerGraphUtil",
394                "ptolemy/vergil/basic/layout/kieler/kieler-copyright.htm");
395
396        _addIfClassPresent(copyrightsMap,
397                "ptolemy.vergil.pdfrenderer.PDFAttribute",
398                "ptolemy/vergil/pdfrenderer/PDFRenderer-copyright.htm");
399
400        _addIfClassPresent(copyrightsMap, "tcl.lang.Shell",
401                "lib/ptjacl-license.htm");
402
403        _addIfClassPresent(copyrightsMap,
404                "thales.vergil.SingleWindowApplication",
405                "thales/thalesSingleWindow-license.htm");
406
407        _addIfClassPresent(copyrightsMap,
408                "org.jivesoftware.smack.XMPPConnection",
409                "lib/smack-license.htm");
410
411        // Check for the _applicationCopyrights parameter
412        try {
413            Parameter applicationCopyrights = (Parameter) configuration
414                    .getAttribute("_applicationCopyrights", Parameter.class);
415
416            if (applicationCopyrights != null) {
417                ArrayToken copyrightTokens = (ArrayToken) applicationCopyrights
418                        .getToken();
419
420                for (int i = 0; i < copyrightTokens.length(); i++) {
421                    StringToken actorToken = (StringToken) ((RecordToken) copyrightTokens
422                            .getElement(i)).get("actor");
423                    StringToken copyrightToken = (StringToken) ((RecordToken) copyrightTokens
424                            .getElement(i)).get("copyright");
425                    _addIfClassPresent(copyrightsMap, actorToken.stringValue(),
426                            copyrightToken.stringValue());
427                }
428            }
429        } catch (Exception ex) {
430            // This application has no _applicationCopyrights
431        }
432
433        // We also create a file that contains all the copyrights.
434        StringBuffer masterCopyrightBuffer = new StringBuffer();
435
436        StringBuffer masterCopyrightTable = new StringBuffer();
437
438        // Read in the header
439        String copyrightStartFileName = "$CLASSPATH/ptolemy/actor/gui/masterCopyrightStart.htm.in";
440        try {
441            // Probably wrong to read it as bytes and convert to a
442            // string, but we have a convenient method, so we use it.
443            masterCopyrightBuffer.append(new String(
444                    FileUtilities.binaryReadURLToByteArray(FileUtilities
445                            .nameToURL(copyrightStartFileName, null, null))));
446        } catch (IOException ex) {
447            // Print only a message, we want to print the copyrights
448            System.err.println(
449                    "Could not read " + copyrightStartFileName + ": " + ex);
450        }
451
452        StringBuffer htmlBuffer = new StringBuffer(
453                generatePrimaryCopyrightHTML(configuration));
454
455        // Sort by the copyright file name, which should start with the package name.
456        FileNameComparator fileNameComparator = new FileNameComparator();
457        TreeMap<String, Set<String>> sortedCopyrightsMap = new TreeMap<String, Set<String>>(
458                fileNameComparator);
459
460        sortedCopyrightsMap.putAll(copyrightsMap);
461
462        if (copyrightsMap.size() != sortedCopyrightsMap.size()) {
463            // Print only a message, we want to print the copyrights.
464            System.err.println(
465                    "GenerateCopyrights: the size of the unsorted copyright table "
466                            + "and the sorted copyright table are not the same?  Perhaps there are two "
467                            + "or more copyrights with the same file name? (foo/copyright.htm and "
468                            + "bar/copyright.htm will not work.)");
469
470        }
471        Iterator copyrights = sortedCopyrightsMap.entrySet().iterator();
472        if (copyrights.hasNext()) {
473            // DSP configuration might not include other actors.
474            htmlBuffer.append("<p>Below we list features and the "
475                    + "corresponding copyright "
476                    + " of the package that is used.  If a feature is not "
477                    + "listed below, then the "
478                    + _getApplicationName(configuration) + " copyright is the "
479                    + "only copyright." + "<table>\n" + "  <tr>\n"
480                    + "      <th>Copyright of package used by the feature</th>\n"
481                    + "      <th>Feature</th>\n" + "  </tr>\n");
482
483            while (copyrights.hasNext()) {
484                Map.Entry entry = (Map.Entry) copyrights.next();
485                String copyrightURL = (String) entry.getKey();
486                Set entitiesSet = (Set) entry.getValue();
487
488                StringBuffer entityBuffer = new StringBuffer();
489                Iterator entities = entitiesSet.iterator();
490
491                while (entities.hasNext()) {
492                    if (entityBuffer.length() > 0) {
493                        entityBuffer.append(", ");
494                    }
495
496                    String entityClassName = (String) entities.next();
497
498                    // If we have javadoc, link to it.
499                    // Assuming that entityClassName contains a dot separated
500                    // classpath here.
501                    String docName = "doc.codeDoc." + entityClassName;
502                    String codeDoc = _findURL(
503                            docName.replace('.', '/') + ".html");
504                    entityBuffer.append("<a href=\"" + codeDoc + "\">"
505                            + entityClassName + "</a>");
506                }
507
508                //System.out.println("GenerateCopyrights: url: " + copyrightURL);
509                String foundCopyright = _findURL(copyrightURL);
510
511                if (copyrightURL.contains("backtrack")
512                        && !copyrightURL.contains("http")) {
513                    // If the backtrack copyright is not local, then don't print it.
514                    continue;
515                }
516                htmlBuffer.append("<tr>\n" + "  <td> <a href=\""
517                        + foundCopyright + "\"><code>"
518                        + _canonicalizeURLToPTII(foundCopyright)
519                        + "</code></a></td>\n" + "  <td>" + entityBuffer
520                        + "</td>\n" + "</tr>\n");
521                try {
522                    String copyright = new String(FileUtilities
523                            .binaryReadURLToByteArray(new URL(foundCopyright)));
524
525                    // Append the text between the body tags.
526
527                    // Look for <body> or </head>
528                    int startIndex = 0;
529                    if ((startIndex = copyright.indexOf("<body>")) == -1) {
530                        if ((startIndex = copyright.indexOf("</head>")) != -1) {
531                            startIndex += "</head>".length();
532                        } else {
533                            // Print only a message, we want to print the copyrights.
534                            System.out.println("Could not find body or head in "
535                                    + foundCopyright + " "
536                                    + copyright.substring(0, 200));
537                            startIndex = 0;
538                        }
539                    } else {
540                        startIndex += "<body>".length();
541                    }
542
543                    // Look for </body> or </html>
544                    int endIndex = 0;
545                    if ((endIndex = copyright.indexOf("</body>")) == -1) {
546                        if ((endIndex = copyright.indexOf("</html>")) == -1) {
547                            endIndex = copyright.length();
548                        }
549                    }
550
551                    // Get read of the html head and close body.
552                    copyright = copyright.substring(startIndex, endIndex);
553
554                    // If there is a <h1> tag, make sure that it has <a name=...
555                    int hIndex = 0;
556                    if ((hIndex = copyright.indexOf("<h1>")) == -1) {
557                        if ((hIndex = copyright.indexOf("<h2>")) == -1) {
558                            // Print only a message, we want to print the copyrights.
559                            System.out.println("Warning, no h1 or h2 in "
560                                    + foundCopyright);
561                        } else {
562                        }
563                    }
564                    if (hIndex != -1) {
565                        int hEndIndex = copyright.indexOf("</h");
566                        if (hEndIndex < hIndex) {
567                            throw new RuntimeException("Generating copyrights: "
568                                    + "hEndIndex " + hEndIndex + " < " + hIndex
569                                    + " " + foundCopyright + " copyright:\n"
570                                    + copyright);
571                        }
572                        String header = copyright.substring(hIndex, hEndIndex);
573                        String newHeader = header;
574                        if (header.indexOf("<a name") == -1) {
575                            // Insert a name tag that is the name of the package.
576
577                            // If the copyright file name contains a -,then the name of the package
578                            // is what is before the -.  If the name does not have a -, then
579                            // the package name is the directory.
580                            String packageName = "unknownPackage";
581                            File copyrightFile = new File(copyrightURL);
582                            String copyrightFileName = copyrightFile.getName();
583                            int hyphenIndex = 0;
584                            if ((hyphenIndex = copyrightFileName
585                                    .indexOf("-")) > 0) {
586                                packageName = copyrightFileName.substring(0,
587                                        hyphenIndex);
588                            } else {
589                                packageName = copyrightFile.getParent();
590                            }
591                            newHeader = "<a name=\"" + packageName + "\">"
592                                    + header;
593                            copyright = copyright.replace(header, newHeader);
594                        }
595
596                        int nameIndex = 0;
597                        if ((nameIndex = newHeader
598                                .indexOf("<a name=\"")) != -1) {
599                            int labelIndex = 0;
600                            if ((labelIndex = newHeader.indexOf("\">")) != -1) {
601                                String target = newHeader.substring(
602                                        nameIndex + "<a name=\"".length(),
603                                        labelIndex);
604                                // Skip the <h1> or <h2>
605                                String label = newHeader
606                                        .substring(labelIndex + 6);
607
608                                //_guessCopyright(label, copyright);
609
610                                masterCopyrightTable
611                                        .append(_generateLicenseTableRow(target,
612                                                label));
613                            }
614                        }
615                    }
616                    masterCopyrightBuffer.append(copyright);
617                } catch (IOException ex) {
618                    // Ignore this, we want to print the copyrights no matter what.
619                    System.out.println(
620                            "Could not read " + foundCopyright + ": " + ex);
621                }
622            }
623
624            htmlBuffer.append("</table>\n</p>");
625        }
626
627        String tableTarget = "<!-- Table Contents Goes Here -->";
628        int tableTargetIndex = -1;
629        if ((tableTargetIndex = masterCopyrightBuffer
630                .indexOf(tableTarget)) == -1) {
631            System.err.println("GenerateCopyrights: Could not find \""
632                    + tableTarget + "\" in the generated copyright text, "
633                    + "maybe ptolemy/actor/gui/masterCopyrightStart.htm.in does not have it?");
634        } else {
635            masterCopyrightBuffer.insert(tableTargetIndex,
636                    masterCopyrightTable);
637        }
638        try {
639            URL masterCopyrightURL = HTMLAbout._temporaryHTMLFile(
640                    "mastercopyright", ".htm",
641                    masterCopyrightBuffer.toString());
642            htmlBuffer.append("<p>For the complete copyrights in one file\n"
643                    + "See the <a href=\"" + masterCopyrightURL
644                    + "\">master copyright</a>.</p>\n");
645        } catch (IOException ex) {
646            // Ignore this, we want to print the copyrights.
647            System.err.println(
648                    "Could not write a temporary file with the complete copyrights: "
649                            + ex);
650        }
651
652        htmlBuffer.append("<p>Other information <a href=\"about:\">about</a>\n"
653                + "this configuration.\n" + "</body>\n</html>");
654
655        return htmlBuffer.toString();
656    }
657
658    /** Generate the primary copyright.  Include a link to the other
659     *  copyrights.
660     *  @param configuration The configuration in which to look for the
661     *  _applicationName attribute.
662     *  @return A String containing HTML that describes what
663     *  copyrights are used by Entities in the configuration
664     */
665    public static String generatePrimaryCopyrightHTML(
666            Configuration configuration) {
667
668        String defaultApplicationCopyright = "ptolemy/configs/doc/copyright.htm";
669        String applicationCopyright = defaultApplicationCopyright;
670
671        try {
672            StringAttribute applicationCopyrightAttribute = (StringAttribute) configuration
673                    .getAttribute("_applicationCopyright",
674                            StringAttribute.class);
675
676            if (applicationCopyrightAttribute != null) {
677                applicationCopyright = applicationCopyrightAttribute
678                        .getExpression();
679            }
680        } catch (Exception ex) {
681            // Ignore and use the default applicationCopyright
682            applicationCopyright = defaultApplicationCopyright;
683        }
684
685        String applicationName = _getApplicationName(configuration);
686        String applicationCopyrightURL = _findURL(applicationCopyright);
687
688        String aelfredCopyright = _findURL(
689                "com/microstar/xml/aelfred-license.htm");
690        String graphCopyright = _findURL("ptolemy/graph/graph-license.htm");
691        String doubleUtilitiesCopyright = _findURL(
692                "ptolemy/util/DoubleUtilities-license.htm");
693
694        String defaultCSS = _findURL("doc/default.css");
695        StringBuffer htmlBuffer = new StringBuffer();
696        htmlBuffer.append("<html>\n<head>\n<title>Copyrights</title>\n"
697                + "<link href=\"" + defaultCSS + "\" rel=\"stylesheet\""
698                + "type=\"text/css\">\n" + "</head>\n<body>\n" + "<h1>"
699                + applicationName + "</h1>\n" + "The primary copyright for the "
700                + applicationName + " System can be\n" + "found in <a href=\""
701                + applicationCopyrightURL + "\"><code>"
702                + _canonicalizeURLToPTII(applicationCopyrightURL)
703                + "</code></a>.\n"
704                + "This configuration includes code that uses packages\n"
705                + "with the following copyrights.\n");
706
707        if (!applicationCopyright.equals(defaultApplicationCopyright)) {
708            // If the Ptolemy II copyright is not the main copyright, add it.
709            String ptolemyIICopyright = _findURL(defaultApplicationCopyright);
710            htmlBuffer.append("<p>" + applicationName + " uses Ptolemy II "
711                    + VersionAttribute.CURRENT_VERSION.getExpression() + ".\n"
712                    + "PtolemyII is covered by the copyright in\n "
713                    + "<a href=\"" + ptolemyIICopyright + "\"><code>"
714                    + _canonicalizeURLToPTII(ptolemyIICopyright)
715                    + "</code></a>\n");
716        }
717
718        htmlBuffer.append("<p>" + applicationName
719                + " uses AElfred as an XML Parser.\n"
720                + "AElfred is covered by the copyright in\n " + "<a href=\""
721                + aelfredCopyright + "\"><code>"
722                + _canonicalizeURLToPTII(aelfredCopyright) + "</code></a>\n</p>"
723                + "<p>" + applicationName
724                + " uses the ptolemy.graph package for scheduling and analysis of Ptolemy II models."
725                + "Significant portions of the ptolemy.graph package were developed by "
726                + "<a href=\"http://www.ece.umd.edu/~ssb/#in_browser\">Professor Shuvra S. Bhattacharyya</a> "
727                + "and his group. and are covered by a BSD License in\n "
728                + "<a href=\"" + graphCopyright + "\"><code>"
729                + _canonicalizeURLToPTII(graphCopyright) + "</code></a>\n</p>"
730                + "<p>" + applicationName
731                + " uses DoubleUtilities, which is based on Guava's DoubleUtils.java.  "
732                + "Guava is licensed under the Apache License, Version 2.0, see "
733                + "<a href=\"" + doubleUtilitiesCopyright + "\"><code>"
734                + _canonicalizeURLToPTII(doubleUtilitiesCopyright)
735                + "</code></a>\n</p>");
736
737        return htmlBuffer.toString();
738    }
739
740    ///////////////////////////////////////////////////////////////////
741    ////                         private methods                   ////
742
743    /* If a className is can be found, then add the className
744     * and copyrightPath to copyrightsMap
745     * @param The map of copyrights.
746     * @param applicationClassName The fully qualified, dot separated
747     * class name of an application class, such as a Ptolemy actor
748     * that uses (either by import or by reflection) the libraryClassName.
749     * @param libraryClassName The fully qualified, dot separated
750     * class name of the copyrighted or licensed library.
751     * @param copyrightPath The path or URL to the copyright for
752     * the library
753     */
754    private static void _addIfClassPresent(
755            Map<String, Set<String>> copyrightsMap, String applicationClassName,
756            String libraryClassName, String copyrightPath) {
757        // If actor.lib.database.DatabaseManager is present, then
758        // we look for MySQL JDBC packages.
759        try {
760            Class.forName(applicationClassName);
761            _addIfClassPresent(copyrightsMap, libraryClassName, copyrightPath);
762        } catch (Throwable throwable) {
763            // Ignore, this just means that the applicationClassName
764            // could not be found, so we need not include information
765            // about the copyright.
766        }
767    }
768
769    /* If a className is can be found, then add the className
770     * and copyrightPath to copyrightsMap
771     * @param The map of copyrights.
772     * @param className The fully qualified, dot separated
773     * class name of the copyrighted or licensed library.
774     * @param copyrightPath The path or URL to the copyright for
775     * the library.
776     */
777    private static void _addIfClassPresent(
778            Map<String, Set<String>> copyrightsMap, String className,
779            String copyrightPath) {
780
781        boolean addIt = false;
782
783        try {
784            Class.forName(className);
785            addIt = true;
786        } catch (Throwable throwable) {
787            // Usually, ignore, this just means that the classname could
788            // not be found, so we need not include information
789            // about the copyright.
790
791            // However, under MacOSX, include any backtracking links
792            String osName = System.getProperty("os.name");
793            if (osName.startsWith("Mac OS")
794                    && copyrightPath.contains("backtrack")) {
795                addIt = true;
796            }
797        }
798
799        if (addIt) {
800            try {
801                Set<String> entitiesSet = copyrightsMap.get(copyrightPath);
802
803                if (entitiesSet == null) {
804                    // This is the first time we've seen this copyright,
805                    // add a key/value pair to copyrights, where the key
806                    // is the URL of the copyright and the value is Set
807                    // of entities that correspond with that copyright.
808                    entitiesSet = new HashSet<String>();
809
810                    entitiesSet.add(className);
811                    copyrightsMap.put(copyrightPath, entitiesSet);
812                } else {
813                    // Other classes are using this copyright, so add this
814                    // one to the list.
815                    entitiesSet.add(className);
816                }
817            } catch (Throwable throwable) {
818                // Ignore errors, it must means we
819            }
820        }
821    }
822
823    /* If a file name can be found as a resource, then add
824     * the file name and copyrightPath to copyrightsMap
825     * @param The map of copyrights.
826     * @param fileName The filename that begins with "$CLASSPATH", for example
827     * "$CLASSPATH/bin/Vergil.app/Contents/MacOS/universalJavaApplicationStub"
828     * @param copyrightPath The path or URL to the copyright for
829     * the library, for example
830     * "bin/Vergil.app/Contents/MacOS/universalJavaApplicationStub-license.html"
831     */
832    private static void _addIfFilePresent(
833            Map<String, Set<String>> copyrightsMap, String fileName,
834            String copyrightPath) {
835
836        boolean addIt = false;
837
838        try {
839            File file = FileUtilities.nameToFile(fileName, null);
840            if (file == null) {
841                return;
842            } else if (file.isFile()) {
843                addIt = true;
844            }
845        } catch (Throwable throwable) {
846            // Usually, ignore, this just means that the classname could
847            // not be found, so we need not include information
848            // about the copyright.
849        }
850
851        if (addIt) {
852            try {
853                Set<String> entitiesSet = copyrightsMap.get(copyrightPath);
854
855                if (entitiesSet == null) {
856                    // This is the first time we've seen this copyright,
857                    // add a key/value pair to copyrights, where the key
858                    // is the URL of the copyright and the value is Set
859                    // of entities that correspond with that copyright.
860                    entitiesSet = new HashSet<String>();
861
862                    entitiesSet.add(fileName);
863                    copyrightsMap.put(copyrightPath, entitiesSet);
864                } else {
865                    // Other classes are using this copyright, so add this
866                    // one to the list.
867                    entitiesSet.add(fileName);
868                }
869            } catch (Throwable throwable) {
870                // Ignore errors.
871            }
872        }
873    }
874
875    // Truncate a jarURL so that the very long jar:file:...! is
876    // converted to $PTII.  If the string does not start with jar:file
877    // or if it startes with jar:file but does not contain a !, then
878    // it is returned unchanged.  This method is used to truncate
879    // the very long paths that we might see under Web Start.
880    private static String _canonicalizeURLToPTII(String path) {
881        if (!path.startsWith("jar:file")) {
882            return path;
883        } else {
884            int index = path.lastIndexOf("!");
885
886            if (index == -1) {
887                return path;
888            } else {
889                return "$PTII" + path.substring(index + 1, path.length());
890            }
891        }
892    }
893
894    // Look for the localURL, and if we cannot find it, refer
895    // to the url on the website that corresponds with this version of
896    // Ptolemy II
897    private static String _findURL(String localURL) {
898        try {
899            URL url = ClassUtilities.getResource(localURL);
900            return url.toString();
901        } catch (Exception ex) {
902            // Ignore it and use the copyright from the website
903            // Substitute in the first two tuples of the version
904            // If the version is 3.0-beta-2, we end up with 3.0
905            StringBuffer majorVersionBuffer = new StringBuffer();
906
907            Iterator tuples = VersionAttribute.CURRENT_VERSION.iterator();
908
909            // Get the first two tuples and separate them with a dot.
910            if (tuples.hasNext()) {
911                majorVersionBuffer.append((String) tuples.next());
912
913                if (tuples.hasNext()) {
914                    majorVersionBuffer.append(".");
915                    majorVersionBuffer.append((String) tuples.next());
916                }
917            }
918
919            String majorVersion = majorVersionBuffer.toString();
920            return "http://ptolemy.eecs.berkeley.edu/ptolemyII/" + "ptII"
921                    + majorVersion + "/ptII" + majorVersion + "/" + localURL;
922        }
923    }
924
925    /** Generate a row for the master table.
926     *  @param target The HTML target for the license
927     *  @param label The label for the license.
928     *  @return HTML for the row that represents the table.
929     */
930    private static String _generateLicenseTableRow(String target,
931            String label) {
932        StringBuffer results = new StringBuffer(" <tr>\n" + "  <td>\n"
933                + "     <a href=\"#" + target + "\">"
934                + label.replace("License for", "").replace("Copyright for", "")
935                + "</a>\n" + "  </td>\n");
936        int rowIndex = -1;
937        for (int i = 0; i < _licenses.length; i++) {
938            if (_licenses[i][0].equals(target)) {
939                rowIndex = i;
940                break;
941            }
942        }
943        if (rowIndex == -1) {
944            results.append(
945                    "  <td>?</td> <td>?</td> <td>?</td> <td>Update ptolemy/actor/gui/GenerateCopyrights.java for \""
946                            + target + "\".</td>");
947        } else {
948            results.append("  <td>" + _licenses[rowIndex][1] + "</td>\n"
949                    + "  <td>" + _licenses[rowIndex][2] + "</td>\n" + "  <td>"
950                    + _licenses[rowIndex][3] + "</td>\n" + "  <td>"
951                    + _licenses[rowIndex][4] + "</td>\n" + "  <td>"
952                    + _licenses[rowIndex][5] + "</td>\n");
953        }
954        results.append("</tr>\n");
955        return results.toString();
956    }
957
958    /** Get the application name from the _applicationName parameter.
959     *  If the _applicationName parameter is not set, then return
960     *  "Ptolemy II"
961     */
962    private static String _getApplicationName(Configuration configuration) {
963        // Now generate the HTML
964        String applicationName = "Ptolemy II";
965
966        try {
967            StringAttribute applicationNameAttribute = (StringAttribute) configuration
968                    .getAttribute("_applicationName", StringAttribute.class);
969
970            if (applicationNameAttribute != null) {
971                applicationName = applicationNameAttribute.getExpression();
972            }
973        } catch (Exception ex) {
974            // Ignore and use the default applicationName
975        }
976        return applicationName;
977    }
978
979    //     /** Guess the type of copyright, used for priming the table. */
980    //     protected void _guessCopyright(String label, String copyright) {
981    //         StringBuffer type = new StringBuffer();
982    //         String [] types = {"Apache License", "CDDL", "Eclipse", "GNU Lesser General Public", "Oracle", "Research in Motion", "Sun" };
983    //         for (int i = 0; i < types.length; i++) {
984    //             if (copyright.indexOf(types[i]) != -1) {
985    //                 if (type.length() > 0) {
986    //                     type.append(" + ");
987    //                 }
988    //                 type.append(types[i]);
989    //             }
990    //         }
991    //         System.out.println("{\"" + target + "\", \" \", \" \", \"Y\", \""
992    //                 + type + "\"},");
993    //     }
994
995    /** Compare two filenames.
996     */
997    static class FileNameComparator implements Comparator<String> {
998
999        /** Compare to Strings that should represent files by the
1000         *  lower case name of the file.
1001         *  @param a The first file name.
1002         *  @param b The second file name.
1003         *  @return -1, 0 or 1
1004         */
1005        @Override
1006        public int compare(String a, String b) {
1007            File fileA = new File(a);
1008            File fileB = new File(b);
1009            return fileA.getName().toLowerCase()
1010                    .compareTo(fileB.getName().toLowerCase());
1011        }
1012    }
1013
1014    /** A table of copyright labels, whether it is in Ptiny, the
1015     * Windows JRE, included in sources, included in Kepler and a
1016     * summary of the license(s).
1017     * We use a simple table here for ease of maintenance.
1018     */
1019    private static String[][] _licenses = {
1020            // Name, Ptiny, Windows JRE, Included in Sources, Included in Kepler, Summary
1021            { "accessors", " ", " ", "Y", "Y", "BSD and MIT" },
1022            { "aelfred", "Y", " ", "Y", "Y", "Include Microstar's copyright" },
1023            { "Audio", "Y", " ", "Y", "Y ", "Include credit text" },
1024            { "BrowserLauncher", "Y", " ", "Y", "Y",
1025                    "Include the BrowserLauncher copyright" },
1026            { "ComponentDialog", "Y", " ", "Y", "Y",
1027                    "Oracle BSD Example License" },
1028            { "DoubleUtilities", "Y", " ", "Y", "Y", "Apache License" },
1029            { "JUnitParams", " ", " ", "Y", "Y", "Apache License" },
1030            { "javamail", " ", " ", "Y", " ",
1031                    "CDDL + GPLv2 with Classpath exception" },
1032            { "PortConfigurerDialog", "Y", " ", "Y", "Y",
1033                    "Oracle BSD Example License" },
1034            { "PDFRenderer", " ", " ", "Y", "Y", "GNU Lesser General Public" },
1035            { "ResizableImageWidget", " ", " ", "Y", " ",
1036                    "CDDL + Oracle + Oracle" },
1037            { "april", " ", " ", " ", "Y ", "BSD" },
1038            { "chic", " ", " ", "Y", "Y", "BSD" },
1039            { "colt", "Y", " ", "Y", "Y", "BSD and others" },
1040            { "commons", "N", " ", "Y", "Y", "Apache" },
1041            { "cup", " ", " ", "Y", " ", "Similar to BSD" },
1042            { "db", " ", " ", "Y", " ",
1043                    "Similar to <font color=\"red\">GPL</font>" }, // GPL!!
1044            { "fmipp", " ", " ", "Y", " ", "FMUSDK: Qtronic: Similar to BSD" },
1045            { "fmusdk", " ", " ", "Y", " ", " QTronic: Similar to BSD" },
1046            { "g4ltl", " ", " ", "Y", "Y", "Apache License" },
1047            { "gcj", " ", " ", "Y", " ", "GPL with libgcc Exception" }, // Backtracking.
1048            { "graph", "Y", " ", "Y", "Y", "BSD" },
1049            { "guava", " ", " ", "Y", "Y", "Apache License" },
1050            { "hazelcast", " ", " ", "Y", " ", "Apache License" },
1051            { "itextpdf", " ", " ", "Y", " ",
1052                    "Affero General Public License <font color=\"red\">like GPL</font>" },
1053            { "jackson", " ", " ", "Y", " ", "Apache License" },
1054            { "jai", " ", "Y", " ", " ", "Oracle" },
1055            { "java3d", " ", "Y", "", " ", "Oracle" },
1056            { "javascript", " ", " ", "Y", "Y", "JQuery and Fancybox: MIT" },
1057            { "javax.servlet", " ", " ", "Y", "Y", "Apache License" },
1058            { "jcerti", " ", " ", "Y", "Y", "GNU Lesser General Public" },
1059            { "jcobyla", " ", " ", "Y", "", "MIT" },
1060            { "jdom", " ", " ", "Y", "",
1061                    "Similar to BSD.  No use of sponsor name in advertising" },
1062            { "jetty", " ", " ", "Y", "Y", "Apache License + Eclipse" },
1063            { "jgoodies", " ", " ", "Y", "Y", "3 Clause BSD" },
1064            { "jhlabs", " ", " ", "Y", " ", "Apache License" },
1065            { "jimblacklerUtils", " ", " ", "Y", "Y", "Public Domain" },
1066            { "jjs", " ", " ", "Y", " ", "BSD-like" },
1067            { "jmf", " ", "Y", " ", " ", "Oracle" },
1068            { "jna", " ", " ", "Y", "Y",
1069                    "Apache License + GNU Lesser General Public" },
1070            { "JRI", " ", "Y", " ", " ", "GNU Lesser General Public" },
1071            { "joystick", " ", " ", "Y", " ", "Artistic License" },
1072            { "js", " ", " ", "Y", " ", "Mozilla + Oracle" },
1073            { "json", " ", " ", "Y", "Y", "BSD-like" },
1074            { "jsoup", " ", " ", "Y", "Y", "MIT" },
1075            { "junit", " ", " ", "Y", "Y", "Common Public License - v 1.0" },
1076            { "jxl", " ", " ", "Y", " ", "GNU Lesser General Public" },
1077            { "jython", "Y", " ", "Y", "Y",
1078                    "Apache License + Python V2 + other licenses" },
1079            { "kieler", "Y", " ", "Y", "Y", "Eclipse" },
1080            { "mapss", " ", " ", "Y", "Y", "BSD" },
1081            { "matlab", "Y", " ", "Y", "Y", "Research in Motion BSD" },
1082            { "mlc", " ", " ", "Y", "Y", "GNU Lesser General Public + Oracle" },
1083            { "mysql", " ", " ", "Y", " ", "GPL + exceptions or Commercial" },
1084            { "netbeans", " ", " ", "Y", "Y", "CDDL + Oracle" },
1085            { "netty", " ", " ", " ", "Y ", "Apache + MIT + BSD + PD" },
1086            { "nrjavaserial", " ", " ", "Y", " ", "LGPL 2.1 + Apache" },
1087            { "opencv", " ", " ", "Y", " ", "BSD" },
1088            { "org.apache.oltu.oauth2", " ", " ", " ", "Y ", "Apache" },
1089            { "org.eclipse.paho.client.mqttv3", " ", " ", " ", "Y", "Eclipse" },
1090            { "oscP5", " ", " ", " ", "Y ",
1091                    "GNU Lesser General Public License 3.0" },
1092            { "protobuf", " ", " ", "Y", "Y", "BSD 3-Clause" },
1093            { "ptalon", "Y", " ", "Y", " ", "Antler: Public Domain" },
1094            { "ptjacl", " ", " ", "Y", "Y", "Apache License + BSD + Oracle" },
1095            { "quicktime", " ", " ", " ", " ", "Apple" }, // License prohibits distribution
1096            { "require.js", " ", " ", "Y", " ", "MIT" },
1097            { "rxtx", " ", "Y", " ", " ",
1098                    "GNU Lesser General Public 2.1 + Oracle" },
1099            { "saxon", " ", " ", "Y", " ", "Mozilla Public License" },
1100            { "smack", " ", " ", "Y", "Y", "Apache License" },
1101            { "socketio", " ", " ", "Y", "Y", "BSD" },
1102            { "soot", " ", " ", "Y", "Y", "BSD + LGPL 2" },
1103            { "sphinx", " ", " ", "N", "N", "BSD-like" },
1104            { "svgSalamander", " ", " ", "Y", " ", "BSD" },
1105            { "thalesSingleWindow", " ", " ", "Y", " ", "BSD" },
1106            { "udunits", " ", " ", "Y", " ",
1107                    "Similar to BSD.  No use of sponsor name in advertising" },
1108            { "universalJavaApplicationStub", " ", " ", " ", " ", "MIT" },
1109            { "vertx", " ", " ", "Y", " ", "Apache License" },
1110            { "webcam", " ", " ", "Y", " ", "BSD and Apache Licenses" } };
1111}