initial commit
This commit is contained in:
commit
f362426ec1
326 changed files with 243745 additions and 0 deletions
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/data
|
||||||
|
/work
|
||||||
|
/logs
|
||||||
|
/.idea
|
||||||
|
/target
|
||||||
|
.DS_Store
|
||||||
|
*.iml
|
||||||
|
/.settings
|
||||||
|
/.classpath
|
||||||
|
/.project
|
||||||
|
/.gradle
|
||||||
|
/build
|
||||||
|
/plugins
|
||||||
|
/sessions
|
||||||
|
*~
|
||||||
|
*.MARC
|
14
.travis.yml
Normal file
14
.travis.yml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
language: java
|
||||||
|
|
||||||
|
sudo: required
|
||||||
|
|
||||||
|
# there is no openjdk8
|
||||||
|
jdk:
|
||||||
|
- oraclejdk8
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.m2
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- ./gradlew sonarqube -Dsonar.host.url=https://sonarqube.com -Dsonar.login=$SONAR_TOKEN -Dsonar.verbose=true --debug
|
48
CREDITS.txt
Normal file
48
CREDITS.txt
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
Thanks to Bas Peters, who created
|
||||||
|
|
||||||
|
- JAMES Java MARC events http://xml.coverpages.org/MARC-Events-James.html
|
||||||
|
- Marc4j
|
||||||
|
- the book "Crosswalking: Processing MARC in XML Environments with MARC4J"
|
||||||
|
|
||||||
|
http://www.lulu.com/shop/bas-peters/crosswalking-processing-marc-in-xml-environments-with-marc4j/paperback/product-689445.html
|
||||||
|
|
||||||
|
and inspired this project.
|
||||||
|
|
||||||
|
----------------
|
||||||
|
|
||||||
|
These four classes in org.xbib.marc.io
|
||||||
|
|
||||||
|
FixedTokenReplacementInputStream
|
||||||
|
ReplaceStringInputStream
|
||||||
|
ScanBuffer
|
||||||
|
StreamTokenHandler
|
||||||
|
|
||||||
|
are derived versions from the classes in Swizzle (September 2016)
|
||||||
|
|
||||||
|
https://github.com/codehaus/swizzle/tree/master/swizzle-stream/
|
||||||
|
|
||||||
|
Swizzle License: The Apache Software License, Version 2.0
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
These classes
|
||||||
|
|
||||||
|
BytesArray
|
||||||
|
BytesReference
|
||||||
|
BytesStreamOutput
|
||||||
|
|
||||||
|
are derived versions from classes in Elasticsearch 1.0
|
||||||
|
|
||||||
|
https://github.com/elastic/elasticsearch/tree/1.0/src/main/java/org/elasticsearch/common/bytes
|
||||||
|
|
||||||
|
Elasticsearch License: The Apache Software License, Version 2.0
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
MARC test data has been acquired from
|
||||||
|
|
||||||
|
https://github.com/marc4j/marc4j/tree/master/test/resources
|
||||||
|
|
||||||
|
and were donated y libraries for testing purpose.
|
||||||
|
|
202
LICENSE.txt
Normal file
202
LICENSE.txt
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
209
README.adoc
Normal file
209
README.adoc
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
# MARC bibliographic data processing library for Java
|
||||||
|
|
||||||
|
image::https://api.travis-ci.org/xbib/marc.svg[Build status]
|
||||||
|
|
||||||
|
image::https://maven-badges.herokuapp.com/maven-central/org.xbib/marc/badge.svg[Maven Central]
|
||||||
|
|
||||||
|
This is a Java library for processing bibliographic data in the following formats:
|
||||||
|
|
||||||
|
- ISO 2709/Z39.2
|
||||||
|
- MARC (USMARC, MARC 21, MARC XML)
|
||||||
|
- MarcXchange (ISO 25577:2013)
|
||||||
|
- UNIMARC
|
||||||
|
- MAB (MAB2, MAB XML)
|
||||||
|
- dialects of MARC (Aleph Sequential, Pica, SISIS format)
|
||||||
|
|
||||||
|
The motivation of this library is to transport bibliographic data into XML or JSON based formats,
|
||||||
|
with the focus on european/german application environment.
|
||||||
|
|
||||||
|
The most known and widespread bibliographic data format is MARC, which stands for "machine readable cataloging"
|
||||||
|
and was developed by the Library of Congress 1968. Inspired by the success of MARC, several other formats, mostly based
|
||||||
|
on MARC, were developed in the 1970s, some very similar, some with significant differences. Most notable
|
||||||
|
is the UNICODE format, developed by IFLA.
|
||||||
|
|
||||||
|
MARC does not offer the features of XML or JSON, it is not a document format
|
||||||
|
or a format for the Web. MARC is stream-based and was targeted to write records on magnetic tape.
|
||||||
|
Today, magnetic tape distributions are history. Also, file distribution via FTP, common in the 1990s, does not fit
|
||||||
|
well into a highly linked information infrastructure like the Seamntic Web.
|
||||||
|
|
||||||
|
This library offers the first step to transport MARC data into systems in use today,
|
||||||
|
by writing MARC fields to XML or JSON formats. More steps would include the generation of
|
||||||
|
graph structures (RDF triples) by processing records in context, but that is not part of this package.
|
||||||
|
|
||||||
|
The library provides a fluent interface and a rich set of input streams, content handlers and listeners.
|
||||||
|
Provided are writers for XML, stylesheet transformations (MODS), and a JSON writer for
|
||||||
|
key/value-oriented JSON, suitable for indexing into Elasticsearch.
|
||||||
|
|
||||||
|
Here is a code example for reading from an ISO 2709 stream and writing into a MarcXchange collection.
|
||||||
|
|
||||||
|
```
|
||||||
|
try (MarcXchangeWriter writer = new MarcXchangeWriter(out)) {
|
||||||
|
Marc.builder()
|
||||||
|
.setInputStream(in)
|
||||||
|
.setCharset(Charset.forName("ANSEL"))
|
||||||
|
.setMarcListener(writer)
|
||||||
|
.build()
|
||||||
|
.writeCollection();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is an example to create MODS from an ISO 2709 stream
|
||||||
|
|
||||||
|
```
|
||||||
|
Marc marc = Marc.builder()
|
||||||
|
.setInputStream(marcInputStream)
|
||||||
|
.setCharset(Charset.forName("ANSEL"))
|
||||||
|
.setSchema(MARC21_FORMAT)
|
||||||
|
.build();
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
Result result = new StreamResult(sw);
|
||||||
|
System.setProperty("http.agent", "Java Agent");
|
||||||
|
marc.transform(new URL("http://www.loc.gov/standards/mods/v3/MARC21slim2MODS3.xsl"), result);
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
And here is an example shwoing how records in "Aleph Sequential") can be parsed
|
||||||
|
and written into a MarcXchange collection:
|
||||||
|
|
||||||
|
```
|
||||||
|
try (MarcXchangeWriter writer = new MarcXchangeWriter(out, true)
|
||||||
|
.setFormat(MarcXchangeConstants.MARCXCHANGE_FORMAT)) {
|
||||||
|
Marc marc = Marc.builder()
|
||||||
|
.setInputStream(in)
|
||||||
|
.setCharset(StandardCharsets.UTF_8)
|
||||||
|
.setMarcListener(writer)
|
||||||
|
.build();
|
||||||
|
marc.wrapIntoCollection(marc.aleph());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bibliographic character sets
|
||||||
|
|
||||||
|
Bibliographic character sets predate the era of Unicode. Before Unicode, characters sets were
|
||||||
|
scattered into several standards. Bibliographic standards were defined on several
|
||||||
|
bibliographic characters sets. Since Unicode, UTF-8 encoding has been accepted as
|
||||||
|
the de-facto standard, which fit into XML and JSON, but processing input data that was
|
||||||
|
created by using bibliographic standards still requires handling of ancient and exotic
|
||||||
|
encodings.
|
||||||
|
|
||||||
|
Because Java JDK does not provide bibliographic character sets from before the Unicode era,
|
||||||
|
it must be extended by a a bibliographic character set library.
|
||||||
|
it is recommended to use http://github.com/xbib/bibliographic-character-sets if the input data is encoded in ANSEL/Z39.47 or ISO 5426.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
You can use the library with Gradle
|
||||||
|
|
||||||
|
```
|
||||||
|
"org.xbib:marc:1.0.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
or with Maven
|
||||||
|
|
||||||
|
```
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xbib</groupId>
|
||||||
|
<artifactId>marc</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
## MARC4J
|
||||||
|
|
||||||
|
This project was inspired by MARC4J, but is not related to MARC4J or makes reuse of the
|
||||||
|
source code. It is a completeley new implementation. For the curious, I tried to
|
||||||
|
compile a feature comparison table to highlight some differences.
|
||||||
|
|
||||||
|
There is a MARC4J fork at https://github.com/ksclarke/freelib-marc4j where Kevin S. Clarke
|
||||||
|
implements modern Java features into the MARC4J code base.
|
||||||
|
|
||||||
|
I am not experienced with MARC4J, so I appreciate any hints, commments, or corrections.
|
||||||
|
|
||||||
|
.Feature comparison to MARC4J
|
||||||
|
|===
|
||||||
|
| |MARC4J |MARC
|
||||||
|
|
||||||
|
|started by
|
||||||
|
|Bas Peters
|
||||||
|
|Jörg Prante
|
||||||
|
|
||||||
|
|Project start
|
||||||
|
|2001
|
||||||
|
|2016
|
||||||
|
|
||||||
|
|Java
|
||||||
|
|Java 5
|
||||||
|
|Java 8
|
||||||
|
|
||||||
|
|Build
|
||||||
|
|Ant
|
||||||
|
|Gradle
|
||||||
|
|
||||||
|
|Supported formats
|
||||||
|
| ISO 2709/Z39.2,
|
||||||
|
MARC (USMARC, MARC 21, MARC XML),
|
||||||
|
tries to parse MARC-like formats with a "permissive" parser
|
||||||
|
| ISO 2709/Z39.2,
|
||||||
|
MARC (USMARC, MARC 21, MARC XML),
|
||||||
|
MarcXchange (ISO 25577:2013),
|
||||||
|
UNIMARC,
|
||||||
|
MAB (MAB2, MAB XML),
|
||||||
|
dialects of MARC (Aleph Sequential, Pica, SISIS format)
|
||||||
|
|
||||||
|
| Bibliographic character set support
|
||||||
|
| builtin, auto-detectable
|
||||||
|
| dynamically, via Java `Charset` API, no autodetection
|
||||||
|
|
||||||
|
| Processing
|
||||||
|
| iterator-based
|
||||||
|
| iterator-based, iterable-based, Java 8 streams for fields, records
|
||||||
|
|
||||||
|
| Transformations
|
||||||
|
|
|
||||||
|
| on-the-fly, pattern-based filtering for tags/values, field key mapping, field value transformations
|
||||||
|
|
||||||
|
| Cleaning
|
||||||
|
|
|
||||||
|
| substitute invalid characters with a pattern replacement input stream
|
||||||
|
|
||||||
|
| Statistics
|
||||||
|
|
|
||||||
|
| can count tag/indicator/subfield combination occurences
|
||||||
|
|
||||||
|
| Concurrency support
|
||||||
|
|
|
||||||
|
| can write to handlers record by record, provides a `MarcRecordAdapter` to turn MARC field events into record events
|
||||||
|
|
||||||
|
| JUnit test coverage
|
||||||
|
|
|
||||||
|
| extensive testing over all MARC dialects, >80% code coverage
|
||||||
|
|
||||||
|
| Source Quality Profile
|
||||||
|
|
|
||||||
|
| https://sonarqube.com/overview?id=1109967[Sonarqube]
|
||||||
|
|
||||||
|
| Jar size
|
||||||
|
| 447 KB (2.7.0)
|
||||||
|
| 142 KB (1.0.0)
|
||||||
|
|
||||||
|
|License
|
||||||
|
|LGPL
|
||||||
|
|Apache
|
||||||
|
|
||||||
|
|===
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
Copyright (C) 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
you may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
105
build.gradle
Normal file
105
build.gradle
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
plugins {
|
||||||
|
id "org.sonarqube" version "2.1-rc1"
|
||||||
|
id "org.ajoberstar.github-pages" version "1.5.1"
|
||||||
|
id "org.xbib.gradle.plugin.jbake" version "1.1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
println "Host: " + java.net.InetAddress.getLocalHost()
|
||||||
|
println "Gradle: " + gradle.gradleVersion + " JVM: " + org.gradle.internal.jvm.Jvm.current() + " Groovy: " + GroovySystem.getVersion()
|
||||||
|
println "Build: group: '${project.group}', name: '${project.name}', version: '${project.version}'"
|
||||||
|
|
||||||
|
apply plugin: 'java'
|
||||||
|
apply plugin: 'maven'
|
||||||
|
apply plugin: 'signing'
|
||||||
|
apply plugin: 'findbugs'
|
||||||
|
apply plugin: 'pmd'
|
||||||
|
apply plugin: 'checkstyle'
|
||||||
|
apply plugin: "jacoco"
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
wagon
|
||||||
|
provided
|
||||||
|
testCompile.extendsFrom(provided)
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testCompile 'junit:junit:4.12'
|
||||||
|
testCompile 'org.xmlunit:xmlunit-matchers:2.2.1'
|
||||||
|
testCompile 'com.github.stefanbirkner:system-rules:1.16.0'
|
||||||
|
provided "org.xbib:bibliographic-character-sets:1.0.0"
|
||||||
|
wagon 'org.apache.maven.wagon:wagon-ssh-external:2.10'
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
|
||||||
|
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
|
||||||
|
tasks.withType(JavaCompile) {
|
||||||
|
options.compilerArgs << "-Xlint:all"
|
||||||
|
}
|
||||||
|
test {
|
||||||
|
classpath += configurations.provided
|
||||||
|
testLogging {
|
||||||
|
showStandardStreams = true
|
||||||
|
exceptionFormat = 'full'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.withType(FindBugs) {
|
||||||
|
ignoreFailures = true
|
||||||
|
reports {
|
||||||
|
xml.enabled = true
|
||||||
|
html.enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.withType(Pmd) {
|
||||||
|
ignoreFailures = true
|
||||||
|
reports {
|
||||||
|
xml.enabled = true
|
||||||
|
html.enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.withType(Checkstyle) {
|
||||||
|
ignoreFailures = true
|
||||||
|
reports {
|
||||||
|
xml.enabled = true
|
||||||
|
html.enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jacocoTestReport {
|
||||||
|
reports {
|
||||||
|
xml.enabled true
|
||||||
|
csv.enabled false
|
||||||
|
xml.destination "${buildDir}/reports/jacoco-xml"
|
||||||
|
html.destination "${buildDir}/reports/jacoco-html"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sonarqube {
|
||||||
|
properties {
|
||||||
|
property "sonar.projectName", "xbib MARC"
|
||||||
|
property "sonar.sourceEncoding", "UTF-8"
|
||||||
|
property "sonar.tests", "src/test/java"
|
||||||
|
property "sonar.scm.provider", "git"
|
||||||
|
property "sonar.java.coveragePlugin", "jacoco"
|
||||||
|
property "sonar.junit.reportsPath", "build/test-results/test/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||||
|
classifier 'sources'
|
||||||
|
from sourceSets.main.allSource
|
||||||
|
}
|
||||||
|
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||||
|
classifier 'javadoc'
|
||||||
|
}
|
||||||
|
artifacts {
|
||||||
|
archives sourcesJar, javadocJar
|
||||||
|
}
|
||||||
|
if (project.hasProperty('signing.keyId')) {
|
||||||
|
signing {
|
||||||
|
sign configurations.archives
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: 'gradle/ext.gradle'
|
||||||
|
apply from: 'gradle/publish.gradle'
|
323
config/checkstyle/checkstyle.xml
Normal file
323
config/checkstyle/checkstyle.xml
Normal file
|
@ -0,0 +1,323 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE module PUBLIC
|
||||||
|
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||||
|
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||||
|
|
||||||
|
<!-- This is a checkstyle configuration file. For descriptions of
|
||||||
|
what the following rules do, please see the checkstyle configuration
|
||||||
|
page at http://checkstyle.sourceforge.net/config.html -->
|
||||||
|
|
||||||
|
<module name="Checker">
|
||||||
|
|
||||||
|
<module name="FileTabCharacter">
|
||||||
|
<!-- Checks that there are no tab characters in the file.
|
||||||
|
-->
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="NewlineAtEndOfFile">
|
||||||
|
<property name="lineSeparator" value="lf"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="RegexpSingleline">
|
||||||
|
<!-- Checks that FIXME is not used in comments. TODO is preferred.
|
||||||
|
-->
|
||||||
|
<property name="format" value="((//.*)|(\*.*))FIXME" />
|
||||||
|
<property name="message" value='TODO is preferred to FIXME. e.g. "TODO(johndoe): Refactor when v2 is released."' />
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="RegexpSingleline">
|
||||||
|
<!-- Checks that TODOs are named. (Actually, just that they are followed
|
||||||
|
by an open paren.)
|
||||||
|
-->
|
||||||
|
<property name="format" value="((//.*)|(\*.*))TODO[^(]" />
|
||||||
|
<property name="message" value='All TODOs should be named. e.g. "TODO(johndoe): Refactor when v2 is released."' />
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="JavadocPackage">
|
||||||
|
<!-- Checks that each Java package has a Javadoc file used for commenting.
|
||||||
|
Only allows a package-info.java, not package.html. -->
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!-- All Java AST specific tests live under TreeWalker module. -->
|
||||||
|
<module name="TreeWalker">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
IMPORT CHECKS
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<module name="RedundantImport">
|
||||||
|
<!-- Checks for redundant import statements. -->
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="ImportOrder">
|
||||||
|
<!-- Checks for out of order import statements. -->
|
||||||
|
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
<property name="groups" value="com.google,android,junit,net,org,java,javax"/>
|
||||||
|
<!-- This ensures that static imports go first. -->
|
||||||
|
<property name="option" value="top"/>
|
||||||
|
<property name="tokens" value="STATIC_IMPORT, IMPORT"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
JAVADOC CHECKS
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Checks for Javadoc comments. -->
|
||||||
|
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
|
||||||
|
<module name="JavadocMethod">
|
||||||
|
<property name="scope" value="protected"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
<property name="allowMissingJavadoc" value="true"/>
|
||||||
|
<property name="allowMissingParamTags" value="true"/>
|
||||||
|
<property name="allowMissingReturnTag" value="true"/>
|
||||||
|
<property name="allowMissingThrowsTags" value="true"/>
|
||||||
|
<property name="allowThrowsTagsForSubclasses" value="true"/>
|
||||||
|
<property name="allowUndeclaredRTE" value="true"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="JavadocType">
|
||||||
|
<property name="scope" value="protected"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="JavadocStyle">
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
NAMING CHECKS
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Item 38 - Adhere to generally accepted naming conventions -->
|
||||||
|
|
||||||
|
<module name="PackageName">
|
||||||
|
<!-- Validates identifiers for package names against the
|
||||||
|
supplied expression. -->
|
||||||
|
<!-- Here the default checkstyle rule restricts package name parts to
|
||||||
|
seven characters, this is not in line with common practice at Google.
|
||||||
|
-->
|
||||||
|
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]{1,})*$"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="TypeNameCheck">
|
||||||
|
<!-- Validates static, final fields against the
|
||||||
|
expression "^[A-Z][a-zA-Z0-9]*$". -->
|
||||||
|
<metadata name="altname" value="TypeName"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="ConstantNameCheck">
|
||||||
|
<!-- Validates non-private, static, final fields against the supplied
|
||||||
|
public/package final fields "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$". -->
|
||||||
|
<metadata name="altname" value="ConstantName"/>
|
||||||
|
<property name="applyToPublic" value="true"/>
|
||||||
|
<property name="applyToProtected" value="true"/>
|
||||||
|
<property name="applyToPackage" value="true"/>
|
||||||
|
<property name="applyToPrivate" value="false"/>
|
||||||
|
<property name="format" value="^([A-Z][A-Z0-9]*(_[A-Z0-9]+)*|FLAG_.*)$"/>
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Variable ''{0}'' should be in ALL_CAPS (if it is a constant) or be private (otherwise)."/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="StaticVariableNameCheck">
|
||||||
|
<!-- Validates static, non-final fields against the supplied
|
||||||
|
expression "^[a-z][a-zA-Z0-9]*_?$". -->
|
||||||
|
<metadata name="altname" value="StaticVariableName"/>
|
||||||
|
<property name="applyToPublic" value="true"/>
|
||||||
|
<property name="applyToProtected" value="true"/>
|
||||||
|
<property name="applyToPackage" value="true"/>
|
||||||
|
<property name="applyToPrivate" value="true"/>
|
||||||
|
<property name="format" value="^[a-z][a-zA-Z0-9]*_?$"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="MemberNameCheck">
|
||||||
|
<!-- Validates non-static members against the supplied expression. -->
|
||||||
|
<metadata name="altname" value="MemberName"/>
|
||||||
|
<property name="applyToPublic" value="true"/>
|
||||||
|
<property name="applyToProtected" value="true"/>
|
||||||
|
<property name="applyToPackage" value="true"/>
|
||||||
|
<property name="applyToPrivate" value="true"/>
|
||||||
|
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="MethodNameCheck">
|
||||||
|
<!-- Validates identifiers for method names. -->
|
||||||
|
<metadata name="altname" value="MethodName"/>
|
||||||
|
<property name="format" value="^[a-z][a-zA-Z0-9]*(_[a-zA-Z0-9]+)*$"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="ParameterName">
|
||||||
|
<!-- Validates identifiers for method parameters against the
|
||||||
|
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="LocalFinalVariableName">
|
||||||
|
<!-- Validates identifiers for local final variables against the
|
||||||
|
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="LocalVariableName">
|
||||||
|
<!-- Validates identifiers for local variables against the
|
||||||
|
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
LENGTH and CODING CHECKS
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<module name="LineLength">
|
||||||
|
<!-- Checks if a line is too long. -->
|
||||||
|
<property name="max" value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.max}" default="128"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
The default ignore pattern exempts the following elements:
|
||||||
|
- import statements
|
||||||
|
- long URLs inside comments
|
||||||
|
-->
|
||||||
|
|
||||||
|
<property name="ignorePattern"
|
||||||
|
value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
|
||||||
|
default="^(package .*;\s*)|(import .*;\s*)|( *(\*|//).*https?://.*)$"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="LeftCurly">
|
||||||
|
<!-- Checks for placement of the left curly brace ('{'). -->
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="RightCurly">
|
||||||
|
<!-- Checks right curlies on CATCH, ELSE, and TRY blocks are on
|
||||||
|
the same line. e.g., the following example is fine:
|
||||||
|
<pre>
|
||||||
|
if {
|
||||||
|
...
|
||||||
|
} else
|
||||||
|
</pre>
|
||||||
|
-->
|
||||||
|
<!-- This next example is not fine:
|
||||||
|
<pre>
|
||||||
|
if {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
else
|
||||||
|
</pre>
|
||||||
|
-->
|
||||||
|
<property name="option" value="same"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!-- Checks for braces around if and else blocks -->
|
||||||
|
<module name="NeedBraces">
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
<property name="tokens" value="LITERAL_IF, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="UpperEll">
|
||||||
|
<!-- Checks that long constants are defined with an upper ell.-->
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="FallThrough">
|
||||||
|
<!-- Warn about falling through to the next case statement. Similar to
|
||||||
|
javac -Xlint:fallthrough, but the check is suppressed if a single-line comment
|
||||||
|
on the last non-blank line preceding the fallen-into case contains 'fall through' (or
|
||||||
|
some other variants which we don't publicized to promote consistency).
|
||||||
|
-->
|
||||||
|
<property name="reliefPattern"
|
||||||
|
value="fall through|Fall through|fallthru|Fallthru|falls through|Falls through|fallthrough|Fallthrough|No break|NO break|no break|continue on"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
MODIFIERS CHECKS
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<module name="ModifierOrder">
|
||||||
|
<!-- Warn if modifier order is inconsistent with JLS3 8.1.1, 8.3.1, and
|
||||||
|
8.4.3. The prescribed order is:
|
||||||
|
public, protected, private, abstract, static, final, transient, volatile,
|
||||||
|
synchronized, native, strictfp
|
||||||
|
-->
|
||||||
|
</module>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
WHITESPACE CHECKS
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<module name="WhitespaceAround">
|
||||||
|
<!-- Checks that various tokens are surrounded by whitespace.
|
||||||
|
This includes most binary operators and keywords followed
|
||||||
|
by regular or curly braces.
|
||||||
|
-->
|
||||||
|
<property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR,
|
||||||
|
BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN,
|
||||||
|
EQUAL, GE, GT, LAND, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
|
||||||
|
LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
|
||||||
|
LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS,
|
||||||
|
MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION,
|
||||||
|
SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="WhitespaceAfter">
|
||||||
|
<!-- Checks that commas, semicolons and typecasts are followed by
|
||||||
|
whitespace.
|
||||||
|
-->
|
||||||
|
<property name="tokens" value="COMMA, SEMI, TYPECAST"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="NoWhitespaceAfter">
|
||||||
|
<!-- Checks that there is no whitespace after various unary operators.
|
||||||
|
Linebreaks are allowed.
|
||||||
|
-->
|
||||||
|
<property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS,
|
||||||
|
UNARY_PLUS"/>
|
||||||
|
<property name="allowLineBreaks" value="true"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="NoWhitespaceBefore">
|
||||||
|
<!-- Checks that there is no whitespace before various unary operators.
|
||||||
|
Linebreaks are allowed.
|
||||||
|
-->
|
||||||
|
<property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/>
|
||||||
|
<property name="allowLineBreaks" value="true"/>
|
||||||
|
<property name="severity" value="error"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="ParenPad">
|
||||||
|
<!-- Checks that there is no whitespace before close parens or after
|
||||||
|
open parens.
|
||||||
|
-->
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
</module>
|
||||||
|
</module>
|
||||||
|
|
3
gradle.properties
Normal file
3
gradle.properties
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
group = org.xbib
|
||||||
|
version = 1.0.0
|
||||||
|
org.gradle.daemon = true
|
8
gradle/ext.gradle
Normal file
8
gradle/ext.gradle
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
ext {
|
||||||
|
user = 'xbib'
|
||||||
|
projectName = 'marc'
|
||||||
|
projectDescription = 'MARC bibliographic data processing library for Java'
|
||||||
|
scmUrl = 'https://github.com/xbib/marc'
|
||||||
|
scmConnection = 'scm:git:git://github.com/xbib/marc.git'
|
||||||
|
scmDeveloperConnection = 'scm:git:git://github.com/xbib/marc.git'
|
||||||
|
}
|
73
gradle/publish.gradle
Normal file
73
gradle/publish.gradle
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
|
||||||
|
task xbibUpload(type: Upload) {
|
||||||
|
configuration = configurations.archives
|
||||||
|
uploadDescriptor = true
|
||||||
|
repositories {
|
||||||
|
if (project.hasProperty('xbibUsername')) {
|
||||||
|
mavenDeployer {
|
||||||
|
configuration = configurations.wagon
|
||||||
|
repository(url: uri('scpexe://xbib.org/repository')) {
|
||||||
|
authentication(userName: xbibUsername, privateKey: xbibPrivateKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task sonatypeUpload(type: Upload) {
|
||||||
|
configuration = configurations.archives
|
||||||
|
uploadDescriptor = true
|
||||||
|
repositories {
|
||||||
|
if (project.hasProperty('ossrhUsername')) {
|
||||||
|
mavenDeployer {
|
||||||
|
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||||
|
repository(url: uri(ossrhReleaseUrl)) {
|
||||||
|
authentication(userName: ossrhUsername, password: ossrhPassword)
|
||||||
|
}
|
||||||
|
snapshotRepository(url: uri(ossrhSnapshotUrl)) {
|
||||||
|
authentication(userName: ossrhUsername, password: ossrhPassword)
|
||||||
|
}
|
||||||
|
pom.project {
|
||||||
|
name projectName
|
||||||
|
description projectDescription
|
||||||
|
packaging 'jar'
|
||||||
|
inceptionYear '2016'
|
||||||
|
url scmUrl
|
||||||
|
organization {
|
||||||
|
name 'xbib'
|
||||||
|
url 'http://xbib.org'
|
||||||
|
}
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id user
|
||||||
|
name 'Jörg Prante'
|
||||||
|
email 'joergprante@gmail.com'
|
||||||
|
url 'https://github.com/jprante'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scm {
|
||||||
|
url scmUrl
|
||||||
|
connection scmConnection
|
||||||
|
developerConnection scmDeveloperConnection
|
||||||
|
}
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name 'The Apache License, Version 2.0'
|
||||||
|
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
githubPages {
|
||||||
|
repoUri = 'git@github.com:xbib/marc.git'
|
||||||
|
targetBranch = "gh-pages"
|
||||||
|
pages {
|
||||||
|
from(file('build/jbake')) {
|
||||||
|
into '.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#Fri Sep 02 12:18:26 CEST 2016
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-3.0-bin.zip
|
169
gradlew
vendored
Executable file
169
gradlew
vendored
Executable file
|
@ -0,0 +1,169 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn ( ) {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die ( ) {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||||
|
function splitJvmOpts() {
|
||||||
|
JVM_OPTS=("$@")
|
||||||
|
}
|
||||||
|
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||||
|
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||||
|
|
||||||
|
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||||
|
if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
84
gradlew.bat
vendored
Normal file
84
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS=
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
1
settings.gradle
Normal file
1
settings.gradle
Normal file
|
@ -0,0 +1 @@
|
||||||
|
rootProject.name = 'marc'
|
512
src/jbake/assets/css/asciidoctor.css
Normal file
512
src/jbake/assets/css/asciidoctor.css
Normal file
|
@ -0,0 +1,512 @@
|
||||||
|
@import url(http://cdnjs.cloudflare.com/ajax/libs/font-awesome/3.2.0/css/font-awesome.css);
|
||||||
|
/* ========================================================================== Embedded content ========================================================================== */
|
||||||
|
/** Remove border when inside `a` element in IE 8/9. */
|
||||||
|
img { border: 0; }
|
||||||
|
|
||||||
|
/** Correct overflow displayed oddly in IE 9. */
|
||||||
|
svg:not(:root) { overflow: hidden; }
|
||||||
|
|
||||||
|
/* ========================================================================== Figures ========================================================================== */
|
||||||
|
/** Address margin not present in IE 8/9 and Safari 5. */
|
||||||
|
figure { margin: 0; }
|
||||||
|
|
||||||
|
/* ========================================================================== Forms ========================================================================== */
|
||||||
|
/** Define consistent border, margin, and padding. */
|
||||||
|
fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; }
|
||||||
|
|
||||||
|
/** 1. Correct `color` not being inherited in IE 8/9. 2. Remove padding so people aren't caught out if they zero out fieldsets. */
|
||||||
|
legend { border: 0; /* 1 */ padding: 0; /* 2 */ }
|
||||||
|
|
||||||
|
/** 1. Correct font family not being inherited in all browsers. 2. Correct font size not being inherited in all browsers. 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. */
|
||||||
|
button, input, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 2 */ margin: 0; /* 3 */ }
|
||||||
|
|
||||||
|
/** Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet. */
|
||||||
|
button, input { line-height: normal; }
|
||||||
|
|
||||||
|
/** Address inconsistent `text-transform` inheritance for `button` and `select`. All other form control elements do not inherit `text-transform` values. Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. Correct `select` style inheritance in Firefox 4+ and Opera. */
|
||||||
|
button, select { text-transform: none; }
|
||||||
|
|
||||||
|
/** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 2. Correct inability to style clickable `input` types in iOS. 3. Improve usability and consistency of cursor style between image-type `input` and others. */
|
||||||
|
button, html input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ }
|
||||||
|
|
||||||
|
/** Re-set default cursor for disabled elements. */
|
||||||
|
button[disabled], html input[disabled] { cursor: default; }
|
||||||
|
|
||||||
|
/** 1. Address box sizing set to `content-box` in IE 8/9. 2. Remove excess padding in IE 8/9. */
|
||||||
|
input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ }
|
||||||
|
|
||||||
|
/** 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome (include `-moz` to future-proof). */
|
||||||
|
input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; }
|
||||||
|
|
||||||
|
/** Remove inner padding and search cancel button in Safari 5 and Chrome on OS X. */
|
||||||
|
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; }
|
||||||
|
|
||||||
|
/** Remove inner padding and border in Firefox 4+. */
|
||||||
|
button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; }
|
||||||
|
|
||||||
|
/** 1. Remove default vertical scrollbar in IE 8/9. 2. Improve readability and alignment in all browsers. */
|
||||||
|
textarea { overflow: auto; /* 1 */ vertical-align: top; /* 2 */ }
|
||||||
|
|
||||||
|
/* ========================================================================== Tables ========================================================================== */
|
||||||
|
/** Remove most spacing between table cells. */
|
||||||
|
table { border-collapse: collapse; border-spacing: 0; }
|
||||||
|
|
||||||
|
*, *:before, *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; }
|
||||||
|
|
||||||
|
img, object, embed { max-width: 100%; height: auto; }
|
||||||
|
|
||||||
|
object, embed { height: 100%; }
|
||||||
|
|
||||||
|
img { -ms-interpolation-mode: bicubic; }
|
||||||
|
|
||||||
|
#map_canvas img, #map_canvas embed, #map_canvas object, .map_canvas img, .map_canvas embed, .map_canvas object { max-width: none !important; }
|
||||||
|
|
||||||
|
.left { float: left !important; }
|
||||||
|
|
||||||
|
.right { float: right !important; }
|
||||||
|
|
||||||
|
.text-left { text-align: left !important; }
|
||||||
|
|
||||||
|
.text-right { text-align: right !important; }
|
||||||
|
|
||||||
|
.text-center { text-align: center !important; }
|
||||||
|
|
||||||
|
.text-justify { text-align: justify !important; }
|
||||||
|
|
||||||
|
.hide { display: none; }
|
||||||
|
|
||||||
|
.antialiased, body { -webkit-font-smoothing: antialiased; }
|
||||||
|
|
||||||
|
img { display: inline-block; vertical-align: middle; }
|
||||||
|
|
||||||
|
textarea { height: auto; min-height: 50px; }
|
||||||
|
|
||||||
|
select { width: 100%; }
|
||||||
|
|
||||||
|
p.lead, .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { font-size: 1.21875em; line-height: 1.6; }
|
||||||
|
|
||||||
|
.subheader, #content #toctitle, .admonitionblock td.content > .title, .exampleblock > .title, .imageblock > .title, .videoblock > .title, .listingblock > .title, .literalblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, .sidebarblock > .title, .tableblock > .title, .verseblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title, .tableblock > caption { line-height: 1.4; color: #7a2518; font-weight: 300; margin-top: 0.2em; margin-bottom: 0.5em; }
|
||||||
|
|
||||||
|
/* Lists */
|
||||||
|
ul, ol, dl { font-size: 1em; line-height: 1.6; margin-bottom: 1.25em; list-style-position: outside; font-family: inherit; }
|
||||||
|
|
||||||
|
ul, ol { margin-left: 1.5em; }
|
||||||
|
|
||||||
|
/* Unordered Lists */
|
||||||
|
ul li ul, ul li ol { margin-left: 1.25em; margin-bottom: 0; font-size: 1em; /* Override nested font-size change */ }
|
||||||
|
ul.square li ul, ul.circle li ul, ul.disc li ul { list-style: inherit; }
|
||||||
|
ul.square { list-style-type: square; }
|
||||||
|
ul.circle { list-style-type: circle; }
|
||||||
|
ul.disc { list-style-type: disc; }
|
||||||
|
ul.no-bullet { list-style: none; }
|
||||||
|
|
||||||
|
/* Ordered Lists */
|
||||||
|
ol li ul, ol li ol { margin-left: 1.25em; margin-bottom: 0; }
|
||||||
|
|
||||||
|
/* Definition Lists */
|
||||||
|
dl dt { margin-bottom: 0.3125em; font-weight: bold; }
|
||||||
|
dl dd { margin-bottom: 1.25em; }
|
||||||
|
|
||||||
|
/* Abbreviations */
|
||||||
|
abbr, acronym { text-transform: uppercase; font-size: 90%; color: #222222; border-bottom: 1px dotted #dddddd; cursor: help; }
|
||||||
|
|
||||||
|
abbr { text-transform: none; }
|
||||||
|
|
||||||
|
/* Blockquotes */
|
||||||
|
blockquote { margin: 0 0 1.25em; padding: 0.5625em 1.25em 0 1.1875em; border-left: 1px solid #dddddd; }
|
||||||
|
blockquote cite { display: block; font-size: inherit; color: #555555; }
|
||||||
|
blockquote cite:before { content: "\2014 \0020"; }
|
||||||
|
blockquote cite a, blockquote cite a:visited { color: #555555; }
|
||||||
|
|
||||||
|
blockquote, blockquote p { line-height: 1.6; color: #6f6f6f; }
|
||||||
|
|
||||||
|
/* Microformats */
|
||||||
|
.vcard { display: inline-block; margin: 0 0 1.25em 0; border: 1px solid #dddddd; padding: 0.625em 0.75em; }
|
||||||
|
.vcard li { margin: 0; display: block; }
|
||||||
|
.vcard .fn { font-weight: bold; font-size: 0.9375em; }
|
||||||
|
|
||||||
|
.vevent .summary { font-weight: bold; }
|
||||||
|
.vevent abbr { cursor: auto; text-decoration: none; font-weight: bold; border: none; padding: 0 0.0625em; }
|
||||||
|
|
||||||
|
@media only screen and (min-width: 768px) { h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.4; }
|
||||||
|
h1 { font-size: 2.75em; }
|
||||||
|
h2 { font-size: 2.3125em; }
|
||||||
|
h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.6875em; }
|
||||||
|
h4 { font-size: 1.4375em; } }
|
||||||
|
/* Print styles. Inlined to avoid required HTTP connection: www.phpied.com/delay-loading-your-print-css/ Credit to Paul Irish and HTML5 Boilerplate (html5boilerplate.com)
|
||||||
|
*/
|
||||||
|
.print-only { display: none !important; }
|
||||||
|
|
||||||
|
@media print { * { background: transparent !important; color: #000 !important; /* Black prints faster: h5bp.com/s */ box-shadow: none !important; text-shadow: none !important; }
|
||||||
|
a, a:visited { text-decoration: underline; }
|
||||||
|
a[href]:after { content: " (" attr(href) ")"; }
|
||||||
|
abbr[title]:after { content: " (" attr(title) ")"; }
|
||||||
|
.ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; }
|
||||||
|
pre, blockquote { border: 1px solid #999; page-break-inside: avoid; }
|
||||||
|
thead { display: table-header-group; /* h5bp.com/t */ }
|
||||||
|
tr, img { page-break-inside: avoid; }
|
||||||
|
img { max-width: 100% !important; }
|
||||||
|
@page { margin: 0.5cm; }
|
||||||
|
p, h2, h3, #toctitle, .sidebarblock > .content > .title { orphans: 3; widows: 3; }
|
||||||
|
h2, h3, #toctitle, .sidebarblock > .content > .title { page-break-after: avoid; }
|
||||||
|
.hide-on-print { display: none !important; }
|
||||||
|
.print-only { display: block !important; }
|
||||||
|
.hide-for-print { display: none !important; }
|
||||||
|
.show-for-print { display: inherit !important; } }
|
||||||
|
/* Tables */
|
||||||
|
table { background: white; margin-bottom: 1.25em; border: solid 1px #dddddd; }
|
||||||
|
table thead, table tfoot { background: whitesmoke; font-weight: bold; }
|
||||||
|
table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td { padding: 0.5em 0.625em 0.625em; font-size: inherit; color: #222222; text-align: left; }
|
||||||
|
table tr th, table tr td { padding: 0.5625em 0.625em; font-size: inherit; color: #222222; }
|
||||||
|
table tr.even, table tr.alt, table tr:nth-of-type(even) { background: #f9f9f9; }
|
||||||
|
table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoot tr td { display: table-cell; line-height: 1.6; }
|
||||||
|
|
||||||
|
.clearfix:before, .clearfix:after, .float-group:before, .float-group:after { content: " "; display: table; }
|
||||||
|
.clearfix:after, .float-group:after { clear: both; }
|
||||||
|
|
||||||
|
*:not(pre) > code { font-size: 0.9375em; padding: 1px 3px 0; white-space: nowrap; background-color: #f2f2f2; border: 1px solid #cccccc; -webkit-border-radius: 4px; border-radius: 4px; text-shadow: none; }
|
||||||
|
|
||||||
|
/*pre, pre > code { line-height: 1.4; color: inherit; font-family: Consolas, "Liberation Mono", Courier, monospace; font-weight: normal; }*/
|
||||||
|
|
||||||
|
kbd.keyseq { color: #555555; }
|
||||||
|
|
||||||
|
kbd:not(.keyseq) { display: inline-block; color: #222222; font-size: 0.75em; line-height: 1.4; background-color: #F7F7F7; border: 1px solid #ccc; -webkit-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px white inset; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px white inset; margin: -0.15em 0.15em 0 0.15em; padding: 0.2em 0.6em 0.2em 0.5em; vertical-align: middle; white-space: nowrap; }
|
||||||
|
|
||||||
|
kbd kbd:first-child { margin-left: 0; }
|
||||||
|
|
||||||
|
kbd kbd:last-child { margin-right: 0; }
|
||||||
|
|
||||||
|
.menuseq, .menu { color: #090909; }
|
||||||
|
|
||||||
|
p a > code:hover { color: #561309; }
|
||||||
|
|
||||||
|
#header, #content, #footnotes, #footer { width: 100%; margin-left: auto; margin-right: auto; margin-top: 0; margin-bottom: 0; max-width: 62.5em; *zoom: 1; position: relative; padding-left: 0.9375em; padding-right: 0.9375em; }
|
||||||
|
#header:before, #header:after, #content:before, #content:after, #footnotes:before, #footnotes:after, #footer:before, #footer:after { content: " "; display: table; }
|
||||||
|
#header:after, #content:after, #footnotes:after, #footer:after { clear: both; }
|
||||||
|
|
||||||
|
#header { margin-bottom: 2.5em; }
|
||||||
|
#header > h1 { color: black; font-weight: normal; border-bottom: 1px solid #dddddd; margin-bottom: -28px; padding-bottom: 32px; }
|
||||||
|
#header span { color: #6f6f6f; }
|
||||||
|
#header #revnumber { text-transform: capitalize; }
|
||||||
|
#header br { display: none; }
|
||||||
|
#header br + span { padding-left: 3px; }
|
||||||
|
#header br + span:before { content: "\2013 \0020"; }
|
||||||
|
#header br + span.author { padding-left: 0; }
|
||||||
|
#header br + span.author:before { content: ", "; }
|
||||||
|
|
||||||
|
#toc { border-bottom: 3px double #ebebeb; padding-bottom: 1.25em; }
|
||||||
|
#toc > ul { margin-left: 0.25em; }
|
||||||
|
#toc ul.sectlevel0 > li > a { font-style: italic; }
|
||||||
|
#toc ul.sectlevel0 ul.sectlevel1 { margin-left: 0; margin-top: 0.5em; margin-bottom: 0.5em; }
|
||||||
|
#toc ul { list-style-type: none; }
|
||||||
|
|
||||||
|
#toctitle { color: #7a2518; }
|
||||||
|
|
||||||
|
@media only screen and (min-width: 1280px) { body.toc2 { padding-left: 20em; }
|
||||||
|
#toc.toc2 { position: fixed; width: 20em; left: 0; top: 0; border-right: 1px solid #ebebeb; border-bottom: 0; z-index: 1000; padding: 1em; height: 100%; overflow: auto; }
|
||||||
|
#toc.toc2 #toctitle { margin-top: 0; }
|
||||||
|
#toc.toc2 > ul { font-size: .95em; }
|
||||||
|
#toc.toc2 ul ul { margin-left: 0; padding-left: 1.25em; }
|
||||||
|
#toc.toc2 ul.sectlevel0 ul.sectlevel1 { padding-left: 0; margin-top: 0.5em; margin-bottom: 0.5em; }
|
||||||
|
body.toc2.toc-right { padding-left: 0; padding-right: 20em; }
|
||||||
|
body.toc2.toc-right #toc.toc2 { border-right: 0; border-left: 1px solid #ebebeb; left: auto; right: 0; } }
|
||||||
|
#content #toc { border-style: solid; border-width: 1px; border-color: #d9d9d9; margin-bottom: 1.25em; padding: 1.25em; background: #f2f2f2; border-width: 0; -webkit-border-radius: 4px; border-radius: 4px; }
|
||||||
|
#content #toc > :first-child { margin-top: 0; }
|
||||||
|
#content #toc > :last-child { margin-bottom: 0; }
|
||||||
|
#content #toc a { text-decoration: none; }
|
||||||
|
|
||||||
|
#content #toctitle { font-weight: bold; font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; font-size: 1em; padding-left: 0.125em; }
|
||||||
|
|
||||||
|
#footer { max-width: 100%; background-color: #222222; padding: 1.25em; }
|
||||||
|
|
||||||
|
#footer-text { color: #dddddd; line-height: 1.44; }
|
||||||
|
|
||||||
|
.sect1 { padding-bottom: 1.25em; }
|
||||||
|
|
||||||
|
.sect1 + .sect1 { border-top: 3px double #ebebeb; }
|
||||||
|
|
||||||
|
#content h1 > a.anchor, h2 > a.anchor, h3 > a.anchor, #toctitle > a.anchor, .sidebarblock > .content > .title > a.anchor, h4 > a.anchor, h5 > a.anchor, h6 > a.anchor { position: absolute; width: 1em; margin-left: -1em; display: block; text-decoration: none; visibility: hidden; text-align: center; font-weight: normal; }
|
||||||
|
#content h1 > a.anchor:before, h2 > a.anchor:before, h3 > a.anchor:before, #toctitle > a.anchor:before, .sidebarblock > .content > .title > a.anchor:before, h4 > a.anchor:before, h5 > a.anchor:before, h6 > a.anchor:before { content: '\00A7'; font-size: .85em; vertical-align: text-top; display: block; margin-top: 0.05em; }
|
||||||
|
#content h1:hover > a.anchor, #content h1 > a.anchor:hover, h2:hover > a.anchor, h2 > a.anchor:hover, h3:hover > a.anchor, #toctitle:hover > a.anchor, .sidebarblock > .content > .title:hover > a.anchor, h3 > a.anchor:hover, #toctitle > a.anchor:hover, .sidebarblock > .content > .title > a.anchor:hover, h4:hover > a.anchor, h4 > a.anchor:hover, h5:hover > a.anchor, h5 > a.anchor:hover, h6:hover > a.anchor, h6 > a.anchor:hover { visibility: visible; }
|
||||||
|
#content h1 > a.link, h2 > a.link, h3 > a.link, #toctitle > a.link, .sidebarblock > .content > .title > a.link, h4 > a.link, h5 > a.link, h6 > a.link { color: #ba3925; text-decoration: none; }
|
||||||
|
#content h1 > a.link:hover, h2 > a.link:hover, h3 > a.link:hover, #toctitle > a.link:hover, .sidebarblock > .content > .title > a.link:hover, h4 > a.link:hover, h5 > a.link:hover, h6 > a.link:hover { color: #a53221; }
|
||||||
|
|
||||||
|
.imageblock, .literalblock, .listingblock, .verseblock, .videoblock { margin-bottom: 1.25em; }
|
||||||
|
|
||||||
|
.admonitionblock td.content > .title, .exampleblock > .title, .imageblock > .title, .videoblock > .title, .listingblock > .title, .literalblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, .sidebarblock > .title, .tableblock > .title, .verseblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { text-align: left; font-weight: bold; }
|
||||||
|
|
||||||
|
.tableblock > caption { text-align: left; font-weight: bold; white-space: nowrap; overflow: visible; max-width: 0; }
|
||||||
|
|
||||||
|
table.tableblock #preamble > .sectionbody > .paragraph:first-of-type p { font-size: inherit; }
|
||||||
|
|
||||||
|
.admonitionblock > table { border: 0; background: none; width: 100%; }
|
||||||
|
.admonitionblock > table td.icon { text-align: center; width: 80px; }
|
||||||
|
.admonitionblock > table td.icon img { max-width: none; }
|
||||||
|
.admonitionblock > table td.icon .title { font-weight: bold; text-transform: uppercase; }
|
||||||
|
.admonitionblock > table td.content { padding-left: 1.125em; padding-right: 1.25em; border-left: 1px solid #dddddd; color: #6f6f6f; }
|
||||||
|
.admonitionblock > table td.content > :last-child > :last-child { margin-bottom: 0; }
|
||||||
|
|
||||||
|
.exampleblock > .content { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background: white; -webkit-border-radius: 4px; border-radius: 4px; }
|
||||||
|
.exampleblock > .content > :first-child { margin-top: 0; }
|
||||||
|
.exampleblock > .content > :last-child { margin-bottom: 0; }
|
||||||
|
.exampleblock > .content h1, .exampleblock > .content h2, .exampleblock > .content h3, .exampleblock > .content #toctitle, .sidebarblock.exampleblock > .content > .title, .exampleblock > .content h4, .exampleblock > .content h5, .exampleblock > .content h6, .exampleblock > .content p { color: #333333; }
|
||||||
|
.exampleblock > .content h1, .exampleblock > .content h2, .exampleblock > .content h3, .exampleblock > .content #toctitle, .sidebarblock.exampleblock > .content > .title, .exampleblock > .content h4, .exampleblock > .content h5, .exampleblock > .content h6 { line-height: 1; margin-bottom: 0.625em; }
|
||||||
|
.exampleblock > .content h1.subheader, .exampleblock > .content h2.subheader, .exampleblock > .content h3.subheader, .exampleblock > .content .subheader#toctitle, .sidebarblock.exampleblock > .content > .subheader.title, .exampleblock > .content h4.subheader, .exampleblock > .content h5.subheader, .exampleblock > .content h6.subheader { line-height: 1.4; }
|
||||||
|
|
||||||
|
.exampleblock.result > .content { -webkit-box-shadow: 0 1px 8px #d9d9d9; box-shadow: 0 1px 8px #d9d9d9; }
|
||||||
|
|
||||||
|
.sidebarblock { border-style: solid; border-width: 1px; border-color: #d9d9d9; margin-bottom: 1.25em; padding: 1.25em; background: #f2f2f2; -webkit-border-radius: 4px; border-radius: 4px; }
|
||||||
|
.sidebarblock > :first-child { margin-top: 0; }
|
||||||
|
.sidebarblock > :last-child { margin-bottom: 0; }
|
||||||
|
.sidebarblock h1, .sidebarblock h2, .sidebarblock h3, .sidebarblock #toctitle, .sidebarblock > .content > .title, .sidebarblock h4, .sidebarblock h5, .sidebarblock h6, .sidebarblock p { color: #333333; }
|
||||||
|
.sidebarblock h1, .sidebarblock h2, .sidebarblock h3, .sidebarblock #toctitle, .sidebarblock > .content > .title, .sidebarblock h4, .sidebarblock h5, .sidebarblock h6 { line-height: 1; margin-bottom: 0.625em; }
|
||||||
|
.sidebarblock h1.subheader, .sidebarblock h2.subheader, .sidebarblock h3.subheader, .sidebarblock .subheader#toctitle, .sidebarblock > .content > .subheader.title, .sidebarblock h4.subheader, .sidebarblock h5.subheader, .sidebarblock h6.subheader { line-height: 1.4; }
|
||||||
|
.sidebarblock > .content > .title { color: #7a2518; margin-top: 0; line-height: 1.6; }
|
||||||
|
|
||||||
|
.exampleblock > .content > :last-child > :last-child, .exampleblock > .content .olist > ol > li:last-child > :last-child, .exampleblock > .content .ulist > ul > li:last-child > :last-child, .exampleblock > .content .qlist > ol > li:last-child > :last-child, .sidebarblock > .content > :last-child > :last-child, .sidebarblock > .content .olist > ol > li:last-child > :last-child, .sidebarblock > .content .ulist > ul > li:last-child > :last-child, .sidebarblock > .content .qlist > ol > li:last-child > :last-child { margin-bottom: 0; }
|
||||||
|
|
||||||
|
/*.literalblock > .content pre, .listingblock > .content pre { background: none; border-width: 1px 0; border-style: dotted; border-color: #bfbfbf; -webkit-border-radius: 4px; border-radius: 4px; padding: 0.75em 0.75em 0.5em 0.75em; word-wrap: break-word; }*/
|
||||||
|
.literalblock > .content pre.nowrap, .listingblock > .content pre.nowrap { overflow-x: auto; white-space: pre; word-wrap: normal; }
|
||||||
|
.literalblock > .content pre > code, .listingblock > .content pre > code { display: block; }
|
||||||
|
@media only screen { .literalblock > .content pre, .listingblock > .content pre { font-size: 0.8em; } }
|
||||||
|
@media only screen and (min-width: 768px) { .literalblock > .content pre, .listingblock > .content pre { font-size: 0.9em; } }
|
||||||
|
@media only screen and (min-width: 1280px) { .literalblock > .content pre, .listingblock > .content pre { font-size: 1em; } }
|
||||||
|
|
||||||
|
.listingblock > .content { position: relative; }
|
||||||
|
|
||||||
|
.listingblock:hover code[class*=" language-"]:before { text-transform: uppercase; font-size: 0.9em; color: #999; position: absolute; top: 0.375em; right: 0.375em; }
|
||||||
|
|
||||||
|
.listingblock:hover code.asciidoc:before { content: "asciidoc"; }
|
||||||
|
.listingblock:hover code.clojure:before { content: "clojure"; }
|
||||||
|
.listingblock:hover code.css:before { content: "css"; }
|
||||||
|
.listingblock:hover code.groovy:before { content: "groovy"; }
|
||||||
|
.listingblock:hover code.html:before { content: "html"; }
|
||||||
|
.listingblock:hover code.java:before { content: "java"; }
|
||||||
|
.listingblock:hover code.javascript:before { content: "javascript"; }
|
||||||
|
.listingblock:hover code.python:before { content: "python"; }
|
||||||
|
.listingblock:hover code.ruby:before { content: "ruby"; }
|
||||||
|
.listingblock:hover code.scss:before { content: "scss"; }
|
||||||
|
.listingblock:hover code.xml:before { content: "xml"; }
|
||||||
|
.listingblock:hover code.yaml:before { content: "yaml"; }
|
||||||
|
|
||||||
|
.listingblock.terminal pre .command:before { content: attr(data-prompt); padding-right: 0.5em; color: #999; }
|
||||||
|
|
||||||
|
.listingblock.terminal pre .command:not([data-prompt]):before { content: '$'; }
|
||||||
|
|
||||||
|
table.pyhltable { border: 0; margin-bottom: 0; }
|
||||||
|
|
||||||
|
table.pyhltable td { vertical-align: top; padding-top: 0; padding-bottom: 0; }
|
||||||
|
|
||||||
|
table.pyhltable td.code { padding-left: .75em; padding-right: 0; }
|
||||||
|
|
||||||
|
.highlight.pygments .lineno, table.pyhltable td:not(.code) { color: #999; padding-left: 0; padding-right: .5em; border-right: 1px solid #dddddd; }
|
||||||
|
|
||||||
|
.highlight.pygments .lineno { display: inline-block; margin-right: .25em; }
|
||||||
|
|
||||||
|
table.pyhltable .linenodiv { background-color: transparent !important; padding-right: 0 !important; }
|
||||||
|
|
||||||
|
.quoteblock { margin: 0 0 1.25em; padding: 0.5625em 1.25em 0 1.1875em; border-left: 1px solid #dddddd; }
|
||||||
|
.quoteblock blockquote { margin: 0 0 1.25em 0; padding: 0 0 0.5625em 0; border: 0; }
|
||||||
|
.quoteblock blockquote > .paragraph:last-child p { margin-bottom: 0; }
|
||||||
|
.quoteblock .attribution { margin-top: -.25em; padding-bottom: 0.5625em; font-size: inherit; color: #555555; }
|
||||||
|
.quoteblock .attribution br { display: none; }
|
||||||
|
.quoteblock .attribution cite { display: block; margin-bottom: 0.625em; }
|
||||||
|
|
||||||
|
table thead th, table tfoot th { font-weight: bold; }
|
||||||
|
|
||||||
|
table.tableblock.grid-all { border-collapse: separate; border-spacing: 1px; -webkit-border-radius: 4px; border-radius: 4px; border-top: 1px solid #dddddd; border-bottom: 1px solid #dddddd; }
|
||||||
|
|
||||||
|
table.tableblock.frame-topbot, table.tableblock.frame-none { border-left: 0; border-right: 0; }
|
||||||
|
|
||||||
|
table.tableblock.frame-sides, table.tableblock.frame-none { border-top: 0; border-bottom: 0; }
|
||||||
|
|
||||||
|
table.tableblock td .paragraph:last-child p, table.tableblock td > p:last-child { margin-bottom: 0; }
|
||||||
|
|
||||||
|
th.tableblock.halign-left, td.tableblock.halign-left { text-align: left; }
|
||||||
|
|
||||||
|
th.tableblock.halign-right, td.tableblock.halign-right { text-align: right; }
|
||||||
|
|
||||||
|
th.tableblock.halign-center, td.tableblock.halign-center { text-align: center; }
|
||||||
|
|
||||||
|
th.tableblock.valign-top, td.tableblock.valign-top { vertical-align: top; }
|
||||||
|
|
||||||
|
th.tableblock.valign-bottom, td.tableblock.valign-bottom { vertical-align: bottom; }
|
||||||
|
|
||||||
|
th.tableblock.valign-middle, td.tableblock.valign-middle { vertical-align: middle; }
|
||||||
|
|
||||||
|
p.tableblock.header { color: #222222; font-weight: bold; }
|
||||||
|
|
||||||
|
td > div.verse { white-space: pre; }
|
||||||
|
|
||||||
|
ol { margin-left: 1.75em; }
|
||||||
|
|
||||||
|
ul li ol { margin-left: 1.5em; }
|
||||||
|
|
||||||
|
dl dd { margin-left: 1.125em; }
|
||||||
|
|
||||||
|
dl dd:last-child, dl dd:last-child > :last-child { margin-bottom: 0; }
|
||||||
|
|
||||||
|
ol > li p, ul > li p, ul dd, ol dd, .olist .olist, .ulist .ulist, .ulist .olist, .olist .ulist { margin-bottom: 0.625em; }
|
||||||
|
|
||||||
|
ul.unstyled, ol.unnumbered, ul.checklist, ul.none { list-style-type: none; }
|
||||||
|
|
||||||
|
ul.unstyled, ol.unnumbered, ul.checklist { margin-left: 0.625em; }
|
||||||
|
|
||||||
|
ul.checklist li > p:first-child > i[class^="icon-check"]:first-child, ul.checklist li > p:first-child > input[type="checkbox"]:first-child { margin-right: 0.25em; }
|
||||||
|
|
||||||
|
ul.checklist li > p:first-child > input[type="checkbox"]:first-child { position: relative; top: 1px; }
|
||||||
|
|
||||||
|
ul.inline { margin: 0 auto 0.625em auto; margin-left: -1.375em; margin-right: 0; padding: 0; list-style: none; overflow: hidden; }
|
||||||
|
ul.inline > li { list-style: none; float: left; margin-left: 1.375em; display: block; }
|
||||||
|
ul.inline > li > * { display: block; }
|
||||||
|
|
||||||
|
.unstyled dl dt { font-weight: normal; font-style: normal; }
|
||||||
|
|
||||||
|
ol.arabic { list-style-type: decimal; }
|
||||||
|
|
||||||
|
ol.decimal { list-style-type: decimal-leading-zero; }
|
||||||
|
|
||||||
|
ol.loweralpha { list-style-type: lower-alpha; }
|
||||||
|
|
||||||
|
ol.upperalpha { list-style-type: upper-alpha; }
|
||||||
|
|
||||||
|
ol.lowerroman { list-style-type: lower-roman; }
|
||||||
|
|
||||||
|
ol.upperroman { list-style-type: upper-roman; }
|
||||||
|
|
||||||
|
ol.lowergreek { list-style-type: lower-greek; }
|
||||||
|
|
||||||
|
.hdlist > table, .colist > table { border: 0; background: none; }
|
||||||
|
.hdlist > table > tbody > tr, .colist > table > tbody > tr { background: none; }
|
||||||
|
|
||||||
|
td.hdlist1 { padding-right: .8em; font-weight: bold; }
|
||||||
|
|
||||||
|
td.hdlist1, td.hdlist2 { vertical-align: top; }
|
||||||
|
|
||||||
|
.literalblock + .colist, .listingblock + .colist { margin-top: -0.5em; }
|
||||||
|
|
||||||
|
.colist > table tr > td:first-of-type { padding: 0 .8em; line-height: 1; }
|
||||||
|
.colist > table tr > td:last-of-type { padding: 0.25em 0; }
|
||||||
|
|
||||||
|
.qanda > ol > li > p > em:only-child { color: #00467f; }
|
||||||
|
|
||||||
|
.thumb, .th { line-height: 0; display: inline-block; border: solid 4px white; -webkit-box-shadow: 0 0 0 1px #dddddd; box-shadow: 0 0 0 1px #dddddd; }
|
||||||
|
|
||||||
|
.imageblock.left, .imageblock[style*="float: left"] { margin: 0.25em 0.625em 1.25em 0; }
|
||||||
|
.imageblock.right, .imageblock[style*="float: right"] { margin: 0.25em 0 1.25em 0.625em; }
|
||||||
|
.imageblock > .title { margin-bottom: 0; }
|
||||||
|
.imageblock.thumb, .imageblock.th { border-width: 6px; }
|
||||||
|
.imageblock.thumb > .title, .imageblock.th > .title { padding: 0 0.125em; }
|
||||||
|
|
||||||
|
.image.left, .image.right { margin-top: 0.25em; margin-bottom: 0.25em; display: inline-block; line-height: 0; }
|
||||||
|
.image.left { margin-right: 0.625em; }
|
||||||
|
.image.right { margin-left: 0.625em; }
|
||||||
|
|
||||||
|
a.image { text-decoration: none; }
|
||||||
|
|
||||||
|
span.footnote, span.footnoteref { vertical-align: super; font-size: 0.875em; }
|
||||||
|
span.footnote a, span.footnoteref a { text-decoration: none; }
|
||||||
|
|
||||||
|
#footnotes { padding-top: 0.75em; padding-bottom: 0.75em; margin-bottom: 0.625em; }
|
||||||
|
#footnotes hr { width: 20%; min-width: 6.25em; margin: -.25em 0 .75em 0; border-width: 1px 0 0 0; }
|
||||||
|
#footnotes .footnote { padding: 0 0.375em; line-height: 1.3; font-size: 0.875em; margin-left: 1.2em; text-indent: -1.2em; margin-bottom: .2em; }
|
||||||
|
#footnotes .footnote a:first-of-type { font-weight: bold; text-decoration: none; }
|
||||||
|
#footnotes .footnote:last-of-type { margin-bottom: 0; }
|
||||||
|
|
||||||
|
#content #footnotes { margin-top: -0.625em; margin-bottom: 0; padding: 0.75em 0; }
|
||||||
|
|
||||||
|
.gist .file-data > table { border: none; background: #fff; width: 100%; margin-bottom: 0; }
|
||||||
|
.gist .file-data > table td.line-data { width: 99%; }
|
||||||
|
|
||||||
|
div.unbreakable { page-break-inside: avoid; }
|
||||||
|
|
||||||
|
.big { font-size: larger; }
|
||||||
|
|
||||||
|
.small { font-size: smaller; }
|
||||||
|
|
||||||
|
.underline { text-decoration: underline; }
|
||||||
|
|
||||||
|
.overline { text-decoration: overline; }
|
||||||
|
|
||||||
|
.line-through { text-decoration: line-through; }
|
||||||
|
|
||||||
|
.aqua { color: #00bfbf; }
|
||||||
|
|
||||||
|
.aqua-background { background-color: #00fafa; }
|
||||||
|
|
||||||
|
.black { color: black; }
|
||||||
|
|
||||||
|
.black-background { background-color: black; }
|
||||||
|
|
||||||
|
.blue { color: #0000bf; }
|
||||||
|
|
||||||
|
.blue-background { background-color: #0000fa; }
|
||||||
|
|
||||||
|
.fuchsia { color: #bf00bf; }
|
||||||
|
|
||||||
|
.fuchsia-background { background-color: #fa00fa; }
|
||||||
|
|
||||||
|
.gray { color: #606060; }
|
||||||
|
|
||||||
|
.gray-background { background-color: #7d7d7d; }
|
||||||
|
|
||||||
|
.green { color: #006000; }
|
||||||
|
|
||||||
|
.green-background { background-color: #007d00; }
|
||||||
|
|
||||||
|
.lime { color: #00bf00; }
|
||||||
|
|
||||||
|
.lime-background { background-color: #00fa00; }
|
||||||
|
|
||||||
|
.maroon { color: #600000; }
|
||||||
|
|
||||||
|
.maroon-background { background-color: #7d0000; }
|
||||||
|
|
||||||
|
.navy { color: #000060; }
|
||||||
|
|
||||||
|
.navy-background { background-color: #00007d; }
|
||||||
|
|
||||||
|
.olive { color: #606000; }
|
||||||
|
|
||||||
|
.olive-background { background-color: #7d7d00; }
|
||||||
|
|
||||||
|
.purple { color: #600060; }
|
||||||
|
|
||||||
|
.purple-background { background-color: #7d007d; }
|
||||||
|
|
||||||
|
.red { color: #bf0000; }
|
||||||
|
|
||||||
|
.red-background { background-color: #fa0000; }
|
||||||
|
|
||||||
|
.silver { color: #909090; }
|
||||||
|
|
||||||
|
.silver-background { background-color: #bcbcbc; }
|
||||||
|
|
||||||
|
.teal { color: #006060; }
|
||||||
|
|
||||||
|
.teal-background { background-color: #007d7d; }
|
||||||
|
|
||||||
|
.white { color: #bfbfbf; }
|
||||||
|
|
||||||
|
.white-background { background-color: #fafafa; }
|
||||||
|
|
||||||
|
.yellow { color: #bfbf00; }
|
||||||
|
|
||||||
|
.yellow-background { background-color: #fafa00; }
|
||||||
|
|
||||||
|
span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
||||||
|
|
||||||
|
.admonitionblock td.icon [class^="icon-"]:before { font-size: 2.5em; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); cursor: default; }
|
||||||
|
.admonitionblock td.icon .icon-note:before { content: "\f05a"; color: #005498; color: #003f72; }
|
||||||
|
.admonitionblock td.icon .icon-tip:before { content: "\f0eb"; text-shadow: 1px 1px 2px rgba(155, 155, 0, 0.8); color: #111; }
|
||||||
|
.admonitionblock td.icon .icon-warning:before { content: "\f071"; color: #bf6900; }
|
||||||
|
.admonitionblock td.icon .icon-caution:before { content: "\f06d"; color: #bf3400; }
|
||||||
|
.admonitionblock td.icon .icon-important:before { content: "\f06a"; color: #bf0000; }
|
||||||
|
|
||||||
|
.conum { display: inline-block; color: white !important; background-color: #222222; -webkit-border-radius: 100px; border-radius: 100px; text-align: center; width: 20px; height: 20px; font-size: 12px; font-weight: bold; line-height: 20px; font-family: Arial, sans-serif; font-style: normal; position: relative; top: -2px; letter-spacing: -1px; }
|
||||||
|
.conum * { color: white !important; }
|
||||||
|
.conum + b { display: none; }
|
||||||
|
.conum:after { content: attr(data-value); }
|
||||||
|
.conum:not([data-value]):empty { display: none; }
|
||||||
|
|
||||||
|
.literalblock > .content > pre, .listingblock > .content > pre { -webkit-border-radius: 0; border-radius: 0; }
|
52
src/jbake/assets/css/base.css
Normal file
52
src/jbake/assets/css/base.css
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/* Sticky footer styles
|
||||||
|
-------------------------------------------------- */
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
/* The html and body elements cannot have any padding or margin. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper for page content to push down footer */
|
||||||
|
#wrap {
|
||||||
|
min-height: 100%;
|
||||||
|
height: auto !important;
|
||||||
|
height: 100%;
|
||||||
|
/* Negative indent footer by it's height */
|
||||||
|
margin: 0 auto -60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the fixed height of the footer here */
|
||||||
|
#push,
|
||||||
|
#footer {
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
#footer {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lastly, apply responsive CSS fixes as necessary */
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
#footer {
|
||||||
|
margin-left: -20px;
|
||||||
|
margin-right: -20px;
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom page CSS
|
||||||
|
-------------------------------------------------- */
|
||||||
|
/* Not required for template or sticky footer method. */
|
||||||
|
|
||||||
|
#wrap > .container {
|
||||||
|
padding-top: 60px;
|
||||||
|
}
|
||||||
|
.container .credit {
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*code {
|
||||||
|
font-size: 80%;
|
||||||
|
}*/
|
5
src/jbake/assets/css/bootstrap-theme.min.css
vendored
Normal file
5
src/jbake/assets/css/bootstrap-theme.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
5
src/jbake/assets/css/bootstrap.min.css
vendored
Normal file
5
src/jbake/assets/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
src/jbake/assets/css/prettify.css
Normal file
1
src/jbake/assets/css/prettify.css
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
|
BIN
src/jbake/assets/favicon.ico
Normal file
BIN
src/jbake/assets/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
src/jbake/assets/fonts/glyphicons-halflings-regular.eot
Normal file
BIN
src/jbake/assets/fonts/glyphicons-halflings-regular.eot
Normal file
Binary file not shown.
229
src/jbake/assets/fonts/glyphicons-halflings-regular.svg
Normal file
229
src/jbake/assets/fonts/glyphicons-halflings-regular.svg
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<metadata></metadata>
|
||||||
|
<defs>
|
||||||
|
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
|
||||||
|
<font-face units-per-em="1200" ascent="960" descent="-240" />
|
||||||
|
<missing-glyph horiz-adv-x="500" />
|
||||||
|
<glyph />
|
||||||
|
<glyph />
|
||||||
|
<glyph unicode="
" />
|
||||||
|
<glyph unicode=" " />
|
||||||
|
<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
|
||||||
|
<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
|
||||||
|
<glyph unicode=" " />
|
||||||
|
<glyph unicode=" " horiz-adv-x="652" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="1304" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="652" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="1304" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="434" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="326" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="217" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="217" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="163" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="260" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="72" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="260" />
|
||||||
|
<glyph unicode=" " horiz-adv-x="326" />
|
||||||
|
<glyph unicode="€" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
|
||||||
|
<glyph unicode="−" d="M200 400h900v300h-900v-300z" />
|
||||||
|
<glyph unicode="◼" horiz-adv-x="500" d="M0 0z" />
|
||||||
|
<glyph unicode="☁" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
|
||||||
|
<glyph unicode="✉" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
|
||||||
|
<glyph unicode="✏" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
|
||||||
|
<glyph unicode="" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
|
||||||
|
<glyph unicode="" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
|
||||||
|
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
|
||||||
|
<glyph unicode="" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
|
||||||
|
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
|
||||||
|
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
|
||||||
|
<glyph unicode="" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
|
||||||
|
<glyph unicode="" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
|
||||||
|
<glyph unicode="" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||||
|
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||||
|
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||||
|
<glyph unicode="" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
|
||||||
|
<glyph unicode="" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
|
||||||
|
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
|
||||||
|
<glyph unicode="" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
|
||||||
|
<glyph unicode="" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
|
||||||
|
<glyph unicode="" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
|
||||||
|
<glyph unicode="" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
|
||||||
|
<glyph unicode="" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
|
||||||
|
<glyph unicode="" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
|
||||||
|
<glyph unicode="" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
|
||||||
|
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
|
||||||
|
<glyph unicode="" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
|
||||||
|
<glyph unicode="" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
|
||||||
|
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
|
||||||
|
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
|
||||||
|
<glyph unicode="" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
|
||||||
|
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
|
||||||
|
<glyph unicode="" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
|
||||||
|
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
|
||||||
|
<glyph unicode="" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
|
||||||
|
<glyph unicode="" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
|
||||||
|
<glyph unicode="" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
|
||||||
|
<glyph unicode="" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
|
||||||
|
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
|
||||||
|
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
|
||||||
|
<glyph unicode="" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
|
||||||
|
<glyph unicode="" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
|
||||||
|
<glyph unicode="" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
|
||||||
|
<glyph unicode="" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
|
||||||
|
<glyph unicode="" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
|
||||||
|
<glyph unicode="" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
|
||||||
|
<glyph unicode="" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
|
||||||
|
<glyph unicode="" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
|
||||||
|
<glyph unicode="" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
|
||||||
|
<glyph unicode="" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
|
||||||
|
<glyph unicode="" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
|
||||||
|
<glyph unicode="" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
|
||||||
|
<glyph unicode="" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
|
||||||
|
<glyph unicode="" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
|
||||||
|
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||||
|
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||||
|
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
|
||||||
|
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
|
||||||
|
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
|
||||||
|
<glyph unicode="" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
|
||||||
|
<glyph unicode="" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
|
||||||
|
<glyph unicode="" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
|
||||||
|
<glyph unicode="" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
|
||||||
|
<glyph unicode="" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
|
||||||
|
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
|
||||||
|
<glyph unicode="" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
|
||||||
|
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
|
||||||
|
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
|
||||||
|
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
|
||||||
|
<glyph unicode="" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
|
||||||
|
<glyph unicode="" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||||
|
<glyph unicode="" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||||
|
<glyph unicode="" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
|
||||||
|
<glyph unicode="" d="M200 0l900 550l-900 550v-1100z" />
|
||||||
|
<glyph unicode="" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||||
|
<glyph unicode="" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||||
|
<glyph unicode="" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
|
||||||
|
<glyph unicode="" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
|
||||||
|
<glyph unicode="" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
|
||||||
|
<glyph unicode="" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
|
||||||
|
<glyph unicode="" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
|
||||||
|
<glyph unicode="" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
|
||||||
|
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
|
||||||
|
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
|
||||||
|
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
|
||||||
|
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
|
||||||
|
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
|
||||||
|
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
|
||||||
|
<glyph unicode="" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
|
||||||
|
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
|
||||||
|
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
|
||||||
|
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
|
||||||
|
<glyph unicode="" d="M0 547l600 453v-300h600v-300h-600v-301z" />
|
||||||
|
<glyph unicode="" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
|
||||||
|
<glyph unicode="" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
|
||||||
|
<glyph unicode="" d="M104 600h296v600h300v-600h298l-449 -600z" />
|
||||||
|
<glyph unicode="" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
|
||||||
|
<glyph unicode="" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
|
||||||
|
<glyph unicode="" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
|
||||||
|
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
|
||||||
|
<glyph unicode="" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
|
||||||
|
<glyph unicode="" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
|
||||||
|
<glyph unicode="" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
|
||||||
|
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
|
||||||
|
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
|
||||||
|
<glyph unicode="" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
|
||||||
|
<glyph unicode="" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
|
||||||
|
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
|
||||||
|
<glyph unicode="" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
|
||||||
|
<glyph unicode="" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
|
||||||
|
<glyph unicode="" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
|
||||||
|
<glyph unicode="" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
|
||||||
|
<glyph unicode="" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
|
||||||
|
<glyph unicode="" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
|
||||||
|
<glyph unicode="" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
|
||||||
|
<glyph unicode="" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
|
||||||
|
<glyph unicode="" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
|
||||||
|
<glyph unicode="" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
|
||||||
|
<glyph unicode="" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
|
||||||
|
<glyph unicode="" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
|
||||||
|
<glyph unicode="" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
|
||||||
|
<glyph unicode="" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
|
||||||
|
<glyph unicode="" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
|
||||||
|
<glyph unicode="" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
|
||||||
|
<glyph unicode="" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
|
||||||
|
<glyph unicode="" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
|
||||||
|
<glyph unicode="" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
|
||||||
|
<glyph unicode="" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
|
||||||
|
<glyph unicode="" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
|
||||||
|
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
|
||||||
|
<glyph unicode="" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
|
||||||
|
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
|
||||||
|
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
|
||||||
|
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
|
||||||
|
<glyph unicode="" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
|
||||||
|
<glyph unicode="" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
|
||||||
|
<glyph unicode="" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
|
||||||
|
<glyph unicode="" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
|
||||||
|
<glyph unicode="" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
|
||||||
|
<glyph unicode="" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
|
||||||
|
<glyph unicode="" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
|
||||||
|
<glyph unicode="" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
|
||||||
|
<glyph unicode="" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
|
||||||
|
<glyph unicode="" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
|
||||||
|
<glyph unicode="" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
|
||||||
|
<glyph unicode="" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
|
||||||
|
<glyph unicode="" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
|
||||||
|
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
|
||||||
|
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
|
||||||
|
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
|
||||||
|
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
|
||||||
|
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
|
||||||
|
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
|
||||||
|
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
|
||||||
|
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
|
||||||
|
<glyph unicode="" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
|
||||||
|
<glyph unicode="" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
|
||||||
|
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
|
||||||
|
<glyph unicode="" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
|
||||||
|
<glyph unicode="" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
|
||||||
|
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
|
||||||
|
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
|
||||||
|
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
|
||||||
|
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
|
||||||
|
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
|
||||||
|
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
|
||||||
|
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
|
||||||
|
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
|
||||||
|
<glyph unicode="" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
|
||||||
|
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
|
||||||
|
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
|
||||||
|
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
|
||||||
|
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
|
||||||
|
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
|
||||||
|
<glyph unicode="" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
|
||||||
|
<glyph unicode="" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
|
||||||
|
<glyph unicode="" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
|
||||||
|
<glyph unicode="" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
|
||||||
|
<glyph unicode="" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
|
||||||
|
<glyph unicode="" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
|
||||||
|
<glyph unicode="" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
|
||||||
|
<glyph unicode="" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
|
||||||
|
<glyph unicode="" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
|
||||||
|
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||||
|
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||||
|
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
|
||||||
|
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
|
||||||
|
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
|
||||||
|
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||||
|
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||||
|
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
|
||||||
|
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
|
||||||
|
<glyph unicode="" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
|
||||||
|
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
|
||||||
|
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
|
||||||
|
<glyph unicode="" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
|
||||||
|
<glyph unicode="" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
|
||||||
|
</font>
|
||||||
|
</defs></svg>
|
After Width: | Height: | Size: 62 KiB |
BIN
src/jbake/assets/fonts/glyphicons-halflings-regular.ttf
Normal file
BIN
src/jbake/assets/fonts/glyphicons-halflings-regular.ttf
Normal file
Binary file not shown.
BIN
src/jbake/assets/fonts/glyphicons-halflings-regular.woff
Normal file
BIN
src/jbake/assets/fonts/glyphicons-halflings-regular.woff
Normal file
Binary file not shown.
BIN
src/jbake/assets/images/CC-BY_icon.svg.png
Normal file
BIN
src/jbake/assets/images/CC-BY_icon.svg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
7
src/jbake/assets/js/bootstrap.min.js
vendored
Normal file
7
src/jbake/assets/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
src/jbake/assets/js/jquery-2.1.3.min.js
vendored
Normal file
4
src/jbake/assets/js/jquery-2.1.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
30
src/jbake/assets/js/prettify.js
Normal file
30
src/jbake/assets/js/prettify.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
!function(){var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
|
||||||
|
(function(){function S(a){function d(e){var b=e.charCodeAt(0);if(b!==92)return b;var a=e.charAt(1);return(b=r[a])?b:"0"<=a&&a<="7"?parseInt(e.substring(1),8):a==="u"||a==="x"?parseInt(e.substring(2),16):e.charCodeAt(1)}function g(e){if(e<32)return(e<16?"\\x0":"\\x")+e.toString(16);e=String.fromCharCode(e);return e==="\\"||e==="-"||e==="]"||e==="^"?"\\"+e:e}function b(e){var b=e.substring(1,e.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),e=[],a=
|
||||||
|
b[0]==="^",c=["["];a&&c.push("^");for(var a=a?1:0,f=b.length;a<f;++a){var h=b[a];if(/\\[bdsw]/i.test(h))c.push(h);else{var h=d(h),l;a+2<f&&"-"===b[a+1]?(l=d(b[a+2]),a+=2):l=h;e.push([h,l]);l<65||h>122||(l<65||h>90||e.push([Math.max(65,h)|32,Math.min(l,90)|32]),l<97||h>122||e.push([Math.max(97,h)&-33,Math.min(l,122)&-33]))}}e.sort(function(e,a){return e[0]-a[0]||a[1]-e[1]});b=[];f=[];for(a=0;a<e.length;++a)h=e[a],h[0]<=f[1]+1?f[1]=Math.max(f[1],h[1]):b.push(f=h);for(a=0;a<b.length;++a)h=b[a],c.push(g(h[0])),
|
||||||
|
h[1]>h[0]&&(h[1]+1>h[0]&&c.push("-"),c.push(g(h[1])));c.push("]");return c.join("")}function s(e){for(var a=e.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),c=a.length,d=[],f=0,h=0;f<c;++f){var l=a[f];l==="("?++h:"\\"===l.charAt(0)&&(l=+l.substring(1))&&(l<=h?d[l]=-1:a[f]=g(l))}for(f=1;f<d.length;++f)-1===d[f]&&(d[f]=++x);for(h=f=0;f<c;++f)l=a[f],l==="("?(++h,d[h]||(a[f]="(?:")):"\\"===l.charAt(0)&&(l=+l.substring(1))&&l<=h&&
|
||||||
|
(a[f]="\\"+d[l]);for(f=0;f<c;++f)"^"===a[f]&&"^"!==a[f+1]&&(a[f]="");if(e.ignoreCase&&m)for(f=0;f<c;++f)l=a[f],e=l.charAt(0),l.length>=2&&e==="["?a[f]=b(l):e!=="\\"&&(a[f]=l.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var x=0,m=!1,j=!1,k=0,c=a.length;k<c;++k){var i=a[k];if(i.ignoreCase)j=!0;else if(/[a-z]/i.test(i.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){m=!0;j=!1;break}}for(var r={b:8,t:9,n:10,v:11,
|
||||||
|
f:12,r:13},n=[],k=0,c=a.length;k<c;++k){i=a[k];if(i.global||i.multiline)throw Error(""+i);n.push("(?:"+s(i)+")")}return RegExp(n.join("|"),j?"gi":"g")}function T(a,d){function g(a){var c=a.nodeType;if(c==1){if(!b.test(a.className)){for(c=a.firstChild;c;c=c.nextSibling)g(c);c=a.nodeName.toLowerCase();if("br"===c||"li"===c)s[j]="\n",m[j<<1]=x++,m[j++<<1|1]=a}}else if(c==3||c==4)c=a.nodeValue,c.length&&(c=d?c.replace(/\r\n?/g,"\n"):c.replace(/[\t\n\r ]+/g," "),s[j]=c,m[j<<1]=x,x+=c.length,m[j++<<1|1]=
|
||||||
|
a)}var b=/(?:^|\s)nocode(?:\s|$)/,s=[],x=0,m=[],j=0;g(a);return{a:s.join("").replace(/\n$/,""),d:m}}function H(a,d,g,b){d&&(a={a:d,e:a},g(a),b.push.apply(b,a.g))}function U(a){for(var d=void 0,g=a.firstChild;g;g=g.nextSibling)var b=g.nodeType,d=b===1?d?a:g:b===3?V.test(g.nodeValue)?a:d:d;return d===a?void 0:d}function C(a,d){function g(a){for(var j=a.e,k=[j,"pln"],c=0,i=a.a.match(s)||[],r={},n=0,e=i.length;n<e;++n){var z=i[n],w=r[z],t=void 0,f;if(typeof w==="string")f=!1;else{var h=b[z.charAt(0)];
|
||||||
|
if(h)t=z.match(h[1]),w=h[0];else{for(f=0;f<x;++f)if(h=d[f],t=z.match(h[1])){w=h[0];break}t||(w="pln")}if((f=w.length>=5&&"lang-"===w.substring(0,5))&&!(t&&typeof t[1]==="string"))f=!1,w="src";f||(r[z]=w)}h=c;c+=z.length;if(f){f=t[1];var l=z.indexOf(f),B=l+f.length;t[2]&&(B=z.length-t[2].length,l=B-f.length);w=w.substring(5);H(j+h,z.substring(0,l),g,k);H(j+h+l,f,I(w,f),k);H(j+h+B,z.substring(B),g,k)}else k.push(j+h,w)}a.g=k}var b={},s;(function(){for(var g=a.concat(d),j=[],k={},c=0,i=g.length;c<i;++c){var r=
|
||||||
|
g[c],n=r[3];if(n)for(var e=n.length;--e>=0;)b[n.charAt(e)]=r;r=r[1];n=""+r;k.hasOwnProperty(n)||(j.push(r),k[n]=q)}j.push(/[\S\s]/);s=S(j)})();var x=d.length;return g}function v(a){var d=[],g=[];a.tripleQuotedStrings?d.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?d.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
|
||||||
|
q,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&g.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var b=a.hashComments;b&&(a.cStyleComments?(b>1?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),g.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,q])):d.push(["com",
|
||||||
|
/^#[^\n\r]*/,q,"#"]));a.cStyleComments&&(g.push(["com",/^\/\/[^\n\r]*/,q]),g.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));if(b=a.regexLiterals){var s=(b=b>1?"":"\n\r")?".":"[\\S\\s]";g.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+("/(?=[^/*"+b+"])(?:[^/\\x5B\\x5C"+b+"]|\\x5C"+s+"|\\x5B(?:[^\\x5C\\x5D"+b+"]|\\x5C"+
|
||||||
|
s+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&g.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&g.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),q]);d.push(["pln",/^\s+/,q," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");g.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,
|
||||||
|
q],["pun",RegExp(b),q]);return C(d,g)}function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.className))if("br"===a.nodeName)s(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&g){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(j.createTextNode(d),a.nextSibling),s(a),c||a.parentNode.removeChild(a)}}function s(a){function b(a,c){var d=
|
||||||
|
c?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=b(e,1),g=a.nextSibling;e.appendChild(d);for(var i=g;i;i=g)g=i.nextSibling,e.appendChild(i)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var x=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,j=a.ownerDocument,k=j.createElement("li");a.firstChild;)k.appendChild(a.firstChild);for(var c=[k],i=0;i<c.length;++i)b(c[i]);d===(d|0)&&c[0].setAttribute("value",d);var r=j.createElement("ol");
|
||||||
|
r.className="linenums";for(var d=Math.max(0,d-1|0)||0,i=0,n=c.length;i<n;++i)k=c[i],k.className="L"+(i+d)%10,k.firstChild||k.appendChild(j.createTextNode("\u00a0")),r.appendChild(k);a.appendChild(r)}function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return F[a]}function K(a){var d=a.h;try{var g=T(a.c,a.i),b=g.a;
|
||||||
|
a.a=b;a.d=g.d;a.e=0;I(d,b)(a);var s=/\bMSIE\s(\d+)/.exec(navigator.userAgent),s=s&&+s[1]<=8,d=/\n/g,x=a.a,m=x.length,g=0,j=a.d,k=j.length,b=0,c=a.g,i=c.length,r=0;c[i]=m;var n,e;for(e=n=0;e<i;)c[e]!==c[e+2]?(c[n++]=c[e++],c[n++]=c[e++]):e+=2;i=n;for(e=n=0;e<i;){for(var p=c[e],w=c[e+1],t=e+2;t+2<=i&&c[t+1]===w;)t+=2;c[n++]=p;c[n++]=w;e=t}c.length=n;var f=a.c,h;if(f)h=f.style.display,f.style.display="none";try{for(;b<k;){var l=j[b+2]||m,B=c[r+2]||m,t=Math.min(l,B),A=j[b+1],G;if(A.nodeType!==1&&(G=x.substring(g,
|
||||||
|
t))){s&&(G=G.replace(d,"\r"));A.nodeValue=G;var L=A.ownerDocument,o=L.createElement("span");o.className=c[r+1];var v=A.parentNode;v.replaceChild(o,A);o.appendChild(A);g<l&&(j[b+1]=A=L.createTextNode(x.substring(t,l)),v.insertBefore(A,o.nextSibling))}g=t;g>=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){D.console&&console.log(u&&u.stack||u)}}var D=window,y=["break,continue,do,else,for,if,return,while"],E=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
|
||||||
|
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[E,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],N=[E,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],
|
||||||
|
O=[N,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],E=[E,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],P=[y,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
|
||||||
|
Q=[y,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],W=[y,"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"],y=[y,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],R=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
|
||||||
|
V=/\S/,X=v({keywords:[M,O,E,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",P,Q,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),F={};p(X,["default-code"]);p(C([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",
|
||||||
|
/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);p(C([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],
|
||||||
|
["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);p(C([],[["atv",/^[\S\s]+/]]),["uq.val"]);p(v({keywords:M,hashComments:!0,cStyleComments:!0,types:R}),["c","cc","cpp","cxx","cyc","m"]);p(v({keywords:"null,true,false"}),["json"]);p(v({keywords:O,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:R}),
|
||||||
|
["cs"]);p(v({keywords:N,cStyleComments:!0}),["java"]);p(v({keywords:y,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);p(v({keywords:P,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);p(v({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),["perl","pl","pm"]);p(v({keywords:Q,
|
||||||
|
hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);p(v({keywords:E,cStyleComments:!0,regexLiterals:!0}),["javascript","js"]);p(v({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);p(v({keywords:W,cStyleComments:!0,multilineStrings:!0}),["rc","rs","rust"]);
|
||||||
|
p(C([],[["str",/^[\S\s]+/]]),["regex"]);var Y=D.PR={createSimpleLexer:C,registerLangHandler:p,sourceDecorator:v,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:D.prettyPrintOne=function(a,d,g){var b=document.createElement("div");b.innerHTML="<pre>"+a+"</pre>";b=b.firstChild;g&&J(b,g,!0);K({h:d,j:g,c:b,i:1});
|
||||||
|
return b.innerHTML},prettyPrint:D.prettyPrint=function(a,d){function g(){for(var b=D.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;i<p.length&&c.now()<b;i++){for(var d=p[i],j=h,k=d;k=k.previousSibling;){var m=k.nodeType,o=(m===7||m===8)&&k.nodeValue;if(o?!/^\??prettify\b/.test(o):m!==3||/\S/.test(k.nodeValue))break;if(o){j={};o.replace(/\b(\w+)=([\w%+\-.:]+)/g,function(a,b,c){j[b]=c});break}}k=d.className;if((j!==h||e.test(k))&&!v.test(k)){m=!1;for(o=d.parentNode;o;o=o.parentNode)if(f.test(o.tagName)&&
|
||||||
|
o.className&&e.test(o.className)){m=!0;break}if(!m){d.className+=" prettyprinted";m=j.lang;if(!m){var m=k.match(n),y;if(!m&&(y=U(d))&&t.test(y.tagName))m=y.className.match(n);m&&(m=m[1])}if(w.test(d.tagName))o=1;else var o=d.currentStyle,u=s.defaultView,o=(o=o?o.whiteSpace:u&&u.getComputedStyle?u.getComputedStyle(d,q).getPropertyValue("white-space"):0)&&"pre"===o.substring(0,3);u=j.linenums;if(!(u=u==="true"||+u))u=(u=k.match(/\blinenums\b(?::(\d+))?/))?u[1]&&u[1].length?+u[1]:!0:!1;u&&J(d,u,o);r=
|
||||||
|
{h:m,c:d,j:u,i:o};K(r)}}}i<p.length?setTimeout(g,250):"function"===typeof a&&a()}for(var b=d||document.body,s=b.ownerDocument||document,b=[b.getElementsByTagName("pre"),b.getElementsByTagName("code"),b.getElementsByTagName("xmp")],p=[],m=0;m<b.length;++m)for(var j=0,k=b[m].length;j<k;++j)p.push(b[m][j]);var b=q,c=Date;c.now||(c={now:function(){return+new Date}});var i=0,r,n=/\blang(?:uage)?-([\w.]+)(?!\S)/,e=/\bprettyprint\b/,v=/\bprettyprinted\b/,w=/pre|xmp/i,t=/^code$/i,f=/^(?:pre|code|xmp)$/i,
|
||||||
|
h={};g()}};typeof define==="function"&&define.amd&&define("google-code-prettify",[],function(){return Y})})();}()
|
11
src/jbake/content/manual.asciidoc
Normal file
11
src/jbake/content/manual.asciidoc
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
= Documentation
|
||||||
|
Jörg Prante
|
||||||
|
2016-09-15
|
||||||
|
:jbake-type: page
|
||||||
|
:jbake-tags: documentation
|
||||||
|
:jbake-status: published
|
||||||
|
:idprefix:
|
||||||
|
:toc:
|
||||||
|
:toc-placement!:
|
||||||
|
|
||||||
|
toc::[]
|
31
src/jbake/jbake.properties
Normal file
31
src/jbake/jbake.properties
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
site.host=http://xbib.github.io/marc
|
||||||
|
site.title=MARC bibliographic processing
|
||||||
|
site.subtitle=including MARC, MarcXchange, MAB, PICA, SISIS
|
||||||
|
site.copyright=2016
|
||||||
|
site.context=/
|
||||||
|
site.theme=lumen
|
||||||
|
site.nav.inverse=false
|
||||||
|
meta.author=Jörg Prante
|
||||||
|
meta.keywords=Java,Marc
|
||||||
|
meta.description=Generated by JBake
|
||||||
|
template.folder=templates
|
||||||
|
content.folder=content
|
||||||
|
asset.folder=assets
|
||||||
|
render.index=true
|
||||||
|
index.file=index.html
|
||||||
|
index.posts.limit=100
|
||||||
|
index.posts.title.limit=200
|
||||||
|
render.tags=true
|
||||||
|
render.sitemap=true
|
||||||
|
template.index.file=index.gsp
|
||||||
|
template.archive.file=archive.gsp
|
||||||
|
template.tag.file=tags.gsp
|
||||||
|
template.sitemap.file=sitemap.gsp
|
||||||
|
template.post.file=post.gsp
|
||||||
|
template.page.file=page.gsp
|
||||||
|
template.feed.file=feed.gsp
|
||||||
|
share.twitter=true
|
||||||
|
prettify.enabled=true
|
||||||
|
prettify.theme=default
|
||||||
|
prettify.linenums=false
|
||||||
|
site.embed.gists=true
|
28
src/jbake/templates/archive.gsp
Normal file
28
src/jbake/templates/archive.gsp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<%include 'header.gsp'%>
|
||||||
|
|
||||||
|
<%include 'menu.gsp'%>
|
||||||
|
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>Blog Archive</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<%def last_month=null;%>
|
||||||
|
<%published_posts.each {post ->%>
|
||||||
|
<%if (last_month) {%>
|
||||||
|
<%if (post.date.format("MMMM yyyy") != last_month) {%>
|
||||||
|
</ul>
|
||||||
|
<h4>${post.date.format("MMMM yyyy")}</h4>
|
||||||
|
<ul>
|
||||||
|
<%}%>
|
||||||
|
<% } else { %>
|
||||||
|
<h4>${post.date.format("MMMM yyyy")}</h4>
|
||||||
|
<ul>
|
||||||
|
<% }%>
|
||||||
|
|
||||||
|
<li>${post.date.format("dd")} - <a href="${post.uri}">${post.title}</a></li>
|
||||||
|
<%last_month = post.date.format("MMMM yyyy")%>
|
||||||
|
<%}%>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<%include "footer.gsp"%>
|
25
src/jbake/templates/feed.gsp
Normal file
25
src/jbake/templates/feed.gsp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<% import static groovy.xml.XmlUtil.escapeXml %><?xml version="1.0"?>
|
||||||
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||||
|
<channel>
|
||||||
|
<title>JBake</title>
|
||||||
|
<link>${config.site_host}</link>
|
||||||
|
<atom:link href="${config.site_host}/${config.feed_file}" rel="self" type="application/rss+xml" />
|
||||||
|
<description>JBake Bootstrap Template</description>
|
||||||
|
<language>en-gb</language>
|
||||||
|
<pubDate>${published_date.format("EEE, d MMM yyyy HH:mm:ss Z")}</pubDate>
|
||||||
|
<lastBuildDate>${published_date.format("EEE, d MMM yyyy HH:mm:ss Z")}</lastBuildDate>
|
||||||
|
|
||||||
|
<%published_posts.each {post -> %>
|
||||||
|
<item>
|
||||||
|
<title>${post.title}</title>
|
||||||
|
<link>${config.site_host}/${post.uri}</link>
|
||||||
|
<pubDate>${post.date.format("EEE, d MMM yyyy HH:mm:ss Z")}</pubDate>
|
||||||
|
<guid isPermaLink="false">${post.uri}</guid>
|
||||||
|
<description>
|
||||||
|
${escapeXml(post.body)}
|
||||||
|
</description>
|
||||||
|
</item>
|
||||||
|
<%}%>
|
||||||
|
|
||||||
|
</channel>
|
||||||
|
</rss>
|
19
src/jbake/templates/footer.gsp
Normal file
19
src/jbake/templates/footer.gsp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
</div>
|
||||||
|
<div id="push"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="footer">
|
||||||
|
<div class="container">
|
||||||
|
<p class="muted credit">© 2015 Jörg Prante <a href="http://creativecommons.org/licenses/by/4.0/"><img src="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>images/CC-BY_icon.svg.png" width="88" height="31"></a>
|
||||||
|
| Mixed with <a href="http://getbootstrap.com/">Bootstrap v3.3.1</a>
|
||||||
|
| Baked with <a href="http://jbake.org">JBake ${version}</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- javascript -->
|
||||||
|
<script src="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>js/jquery-2.1.3.min.js"></script>
|
||||||
|
<script src="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>js/bootstrap.min.js"></script>
|
||||||
|
<script src="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>js/prettify.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
24
src/jbake/templates/header.gsp
Normal file
24
src/jbake/templates/header.gsp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title><%if (content.title) {%>${content.title}<% } else { %>JBake<% }%></title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="author" content="">
|
||||||
|
<meta name="keywords" content="">
|
||||||
|
<meta name="generator" content="JBake">
|
||||||
|
|
||||||
|
<!-- styles -->
|
||||||
|
<link href="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>css/bootstrap-theme.min.css" rel="stylesheet">
|
||||||
|
<link href="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>css/asciidoctor.css" rel="stylesheet">
|
||||||
|
<link href="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>css/base.css" rel="stylesheet">
|
||||||
|
<link href="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>css/prettify.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Fav and touch icons -->
|
||||||
|
<link rel="shortcut icon" href="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>favicon.ico">
|
||||||
|
</head>
|
||||||
|
<body onload="prettyPrint()">
|
||||||
|
<div id="wrap">
|
||||||
|
|
19
src/jbake/templates/index.gsp
Normal file
19
src/jbake/templates/index.gsp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<%include "header.gsp"%>
|
||||||
|
|
||||||
|
<%include "menu.gsp"%>
|
||||||
|
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>Index</h1>
|
||||||
|
</div>
|
||||||
|
<%published_posts.each {post ->%>
|
||||||
|
<div class="post">
|
||||||
|
<a href="${post.uri}">${post.title}</a>
|
||||||
|
<p class="post-info"><i class="glyphicon glyphicon-calendar"></i> ${post.date.format("dd MMMM yyyy")}</p>
|
||||||
|
</div>
|
||||||
|
<%}%>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<p>Older posts are available in the <a href="/${config.archive_file}">archive</a>.</p>
|
||||||
|
|
||||||
|
<%include "footer.gsp"%>
|
22
src/jbake/templates/menu.gsp
Normal file
22
src/jbake/templates/menu.gsp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<!-- Fixed navbar -->
|
||||||
|
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||||
|
<span class="sr-only">Toggle navigation</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
<a class="navbar-brand" href="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>">Jörg Prante</a>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-collapse collapse">
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li><a href="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>index.html">Home</a></li>
|
||||||
|
<li><a href="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>about.html">About</a></li>
|
||||||
|
<li><a href="<%if (content.rootpath) {%>${content.rootpath}<% } else { %><% }%>${config.feed_file}">Subscribe</a></li>
|
||||||
|
</ul>
|
||||||
|
</div><!--/.nav-collapse -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
15
src/jbake/templates/page.gsp
Normal file
15
src/jbake/templates/page.gsp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<%include "header.gsp"%>
|
||||||
|
|
||||||
|
<%include "menu.gsp"%>
|
||||||
|
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>${content.title}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p><em>${content.date.format("dd MMMM yyyy")}</em></p>
|
||||||
|
|
||||||
|
<p>${content.body}</p>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<%include "footer.gsp"%>
|
20
src/jbake/templates/post.gsp
Normal file
20
src/jbake/templates/post.gsp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<%include "header.gsp"%>
|
||||||
|
|
||||||
|
<%include "menu.gsp"%>
|
||||||
|
|
||||||
|
<div class="post">
|
||||||
|
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>${content.title}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="post-info">
|
||||||
|
<i class="fa fa-calendar-o"></i>
|
||||||
|
${content.date.format("dd MMMM yyyy")}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>${content.body}</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%include "footer.gsp"%>
|
9
src/jbake/templates/sitemap.gsp
Normal file
9
src/jbake/templates/sitemap.gsp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
|
||||||
|
<%published_content.each {content -> %>
|
||||||
|
<url>
|
||||||
|
<loc>${config.site_host}${content.uri}</loc>
|
||||||
|
<lastmod>${content.date.format("yyyy-MM-dd")}</lastmod>
|
||||||
|
</url>
|
||||||
|
<%}%>
|
||||||
|
</urlset>
|
28
src/jbake/templates/tags.gsp
Normal file
28
src/jbake/templates/tags.gsp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<%include "header.gsp"%>
|
||||||
|
|
||||||
|
<%include "menu.gsp"%>
|
||||||
|
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>Tag: ${tag}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--<ul>-->
|
||||||
|
<%def last_month=null;%>
|
||||||
|
<%tag_posts.each {post ->%>
|
||||||
|
<%if (last_month) {%>
|
||||||
|
<%if (post.date.format("MMMM yyyy") != last_month) {%>
|
||||||
|
</ul>
|
||||||
|
<h4>${post.date.format("MMMM yyyy")}</h4>
|
||||||
|
<ul>
|
||||||
|
<%}%>
|
||||||
|
<%} else {%>
|
||||||
|
<h4>${post.date.format("MMMM yyyy")}</h4>
|
||||||
|
<ul>
|
||||||
|
<%}%>
|
||||||
|
|
||||||
|
<li>${post.date.format("dd")} - <a href="${post.uri}">${post.title}</a></li>
|
||||||
|
<% last_month = post.date.format("MMMM yyyy")%>
|
||||||
|
<%}%>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<%include "footer.gsp"%>
|
1161
src/main/java/org/xbib/marc/Marc.java
Normal file
1161
src/main/java/org/xbib/marc/Marc.java
Normal file
File diff suppressed because it is too large
Load diff
594
src/main/java/org/xbib/marc/MarcField.java
Normal file
594
src/main/java/org/xbib/marc/MarcField.java
Normal file
|
@ -0,0 +1,594 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc;
|
||||||
|
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MARC field.
|
||||||
|
*/
|
||||||
|
public class MarcField implements Comparable<MarcField> {
|
||||||
|
|
||||||
|
public static final MarcField EMPTY = builder().build();
|
||||||
|
|
||||||
|
public static final String KEY_DELIMITER = "$";
|
||||||
|
|
||||||
|
private static final String EMPTY_STRING = "";
|
||||||
|
|
||||||
|
private final String tag;
|
||||||
|
|
||||||
|
private final String indicator;
|
||||||
|
|
||||||
|
private final int position;
|
||||||
|
|
||||||
|
private final int length;
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
private final String subfieldIds;
|
||||||
|
|
||||||
|
private final LinkedList<Subfield> subfields;
|
||||||
|
|
||||||
|
private final boolean iscontrol;
|
||||||
|
|
||||||
|
private MarcField(String tag, String indicator, int position, int length,
|
||||||
|
String value, LinkedList<Subfield> subfields, String subfieldIds,
|
||||||
|
boolean iscontrol) {
|
||||||
|
this.tag = tag;
|
||||||
|
this.indicator = indicator;
|
||||||
|
this.position = position;
|
||||||
|
this.length = length;
|
||||||
|
this.value = value;
|
||||||
|
this.subfields = subfields;
|
||||||
|
this.subfieldIds = subfieldIds;
|
||||||
|
this.iscontrol = iscontrol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a build for a MARC field.
|
||||||
|
* @return a builder
|
||||||
|
*/
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the MARC field tag.
|
||||||
|
* @return the tag
|
||||||
|
*/
|
||||||
|
public String getTag() {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the MARC field indicator, one or more chaarcters.
|
||||||
|
* @return the indicator
|
||||||
|
*/
|
||||||
|
public String getIndicator() {
|
||||||
|
return indicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the MARC field position. The position is recorded in the MARC directory.
|
||||||
|
* @return position
|
||||||
|
*/
|
||||||
|
public int getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the MARC field length. The length is recorded in the MARC directory.
|
||||||
|
* @return the MARC field length
|
||||||
|
*/
|
||||||
|
public int getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the subfields associated with this MARC field.
|
||||||
|
* @return a list of MARC subfields
|
||||||
|
*/
|
||||||
|
public LinkedList<Subfield> getSubfields() {
|
||||||
|
return subfields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the field value of this MAR field. Mostly used for control fields,
|
||||||
|
* but also on formats that do not use subfields.
|
||||||
|
* @return the field value
|
||||||
|
*/
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this MARC field is a control field.
|
||||||
|
* @return true if control field, false if not
|
||||||
|
*/
|
||||||
|
public boolean isControl() {
|
||||||
|
return iscontrol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this MARC field is empty.
|
||||||
|
* @return true if MARC field is empty, false if not
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return tag == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTagValid() {
|
||||||
|
return tag.length() == 3
|
||||||
|
&& ((tag.charAt(0) >= '0' && tag.charAt(0) <= '9')
|
||||||
|
|| (tag.charAt(0) >= 'A' && tag.charAt(0) <= 'Z'))
|
||||||
|
&& ((tag.charAt(1) >= '0' && tag.charAt(1) <= '9')
|
||||||
|
|| (tag.charAt(1) >= 'A' && tag.charAt(1) <= 'Z'))
|
||||||
|
&& ((tag.charAt(2) >= '0' && tag.charAt(2) <= '9')
|
||||||
|
|| (tag.charAt(2) >= 'A' && tag.charAt(2) <= 'Z'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIndicatorValid() {
|
||||||
|
if (isControl()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
boolean b = indicator.length() <= 9;
|
||||||
|
for (int i = 0; i < indicator.length(); i++) {
|
||||||
|
b = indicator.charAt(i) == ' '
|
||||||
|
|| (indicator.charAt(i) >= '0' && indicator.charAt(i) <= '9')
|
||||||
|
|| (indicator.charAt(i) >= 'a' && indicator.charAt(i) <= 'z')
|
||||||
|
|| (indicator.charAt(i) >= 'A' && indicator.charAt(i) <= 'Z')
|
||||||
|
|| indicator.charAt(i) == '@'; // for our PICA hack
|
||||||
|
if (!b) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSubfieldValid() {
|
||||||
|
if (isControl()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
boolean b = true;
|
||||||
|
for (int i = 0; i < subfieldIds.length(); i++) {
|
||||||
|
b = subfieldIds.charAt(i) == ' '
|
||||||
|
|| (subfieldIds.charAt(i) >= '0' && subfieldIds.charAt(i) <= '9')
|
||||||
|
|| (subfieldIds.charAt(i) >= 'a' && subfieldIds.charAt(i) <= 'z')
|
||||||
|
|| (subfieldIds.charAt(i) >= 'A' && subfieldIds.charAt(i) <= 'Z') // can appear in german MARC
|
||||||
|
|| subfieldIds.charAt(i) == '$' // can appear in german MARC
|
||||||
|
|| subfieldIds.charAt(i) == '=' // can appear in german MARC
|
||||||
|
;
|
||||||
|
if (!b) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return isTagValid() && isIndicatorValid() && isSubfieldValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if pattern matches the tag/indicator key {@code tag '$' indicator}.
|
||||||
|
* @param pattern the pattern
|
||||||
|
* @return this MARC field if pattern macthes, otherwise null
|
||||||
|
*/
|
||||||
|
public MarcField matchKey(Pattern pattern) {
|
||||||
|
return pattern.matcher(toTagIndicatorKey()).matches() ? this : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for fields that match a pattern.
|
||||||
|
* @param pattern the pattern to match
|
||||||
|
* @return thhis MARC field if pattern matches, or null if not
|
||||||
|
*/
|
||||||
|
public MarcField matchValue(Pattern pattern) {
|
||||||
|
if (value != null && pattern.matcher(value).matches()) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
for (Subfield subfield : subfields) {
|
||||||
|
if (pattern.matcher(subfield.getValue()).matches()) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MARC field can be denoted by a key, independent of values.
|
||||||
|
* This key is a string, consisting of tag, indicator, subfield IDs, delimited by a dollar sign.
|
||||||
|
*
|
||||||
|
* @return the key of this MARC field
|
||||||
|
*/
|
||||||
|
public String toKey() {
|
||||||
|
return (tag == null ? EMPTY_STRING : tag) + KEY_DELIMITER + (indicator == null ? EMPTY_STRING : indicator) +
|
||||||
|
KEY_DELIMITER + subfieldIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MARC field can be denoted by a key, independent of values.
|
||||||
|
* This key is a string, consisting of tag and indicator delimited by a dollar sign.
|
||||||
|
*
|
||||||
|
* @return the tag/indicator-based key of this MARC field
|
||||||
|
*/
|
||||||
|
public String toTagIndicatorKey() {
|
||||||
|
return (tag == null ? EMPTY_STRING : tag) + KEY_DELIMITER + (indicator == null ? EMPTY_STRING : indicator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MARC field can be denoted by a key, independent of values.
|
||||||
|
* This key is a string, consisting of the tag.
|
||||||
|
*
|
||||||
|
* @return the tag-based key of this MARC field
|
||||||
|
*/
|
||||||
|
public String toTagKey() {
|
||||||
|
return tag == null ? EMPTY_STRING : tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(MarcField o) {
|
||||||
|
return toKey().compareTo(o.toKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
return object == this || object instanceof MarcField && toKey().equals(((MarcField) object).toKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return toKey().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return toKey() + (getValue() != null && !getValue().isEmpty() ? getValue() : "")
|
||||||
|
+ (!getSubfields().isEmpty() ? getSubfields() : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MARC field builder. The builder accepts all information required for building
|
||||||
|
* a new MARC field.
|
||||||
|
*/
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
private String tag;
|
||||||
|
|
||||||
|
private String indicator;
|
||||||
|
|
||||||
|
private int position;
|
||||||
|
|
||||||
|
private int length;
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
private LinkedList<Subfield> subfields;
|
||||||
|
|
||||||
|
private LinkedList<String> subfieldIds;
|
||||||
|
|
||||||
|
Builder() {
|
||||||
|
this.subfields = new LinkedList<>();
|
||||||
|
this.subfieldIds = new SubfieldIds();
|
||||||
|
this.position = -1;
|
||||||
|
this.length = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the tag.
|
||||||
|
* @param tag the tag
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder tag(String tag) {
|
||||||
|
this.tag = tag;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tag.
|
||||||
|
* @return the tag
|
||||||
|
*/
|
||||||
|
public String tag() {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set indicator.
|
||||||
|
* @param indicator the indicator string
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder indicator(String indicator) {
|
||||||
|
// check if indicators are "-" (like Aleph does). Replace with blank.
|
||||||
|
this.indicator = indicator != null ? indicator.replace('-', ' ') : null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the indicator.
|
||||||
|
* @return the indicator
|
||||||
|
*/
|
||||||
|
public String indicator() {
|
||||||
|
return indicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set position.
|
||||||
|
* @param position the position
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder position(int position) {
|
||||||
|
this.position = position;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return position.
|
||||||
|
* @return the position
|
||||||
|
*/
|
||||||
|
public int position() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return length.
|
||||||
|
* @return the length
|
||||||
|
*/
|
||||||
|
public int length() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set length.
|
||||||
|
* @param length the length
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder length(int length) {
|
||||||
|
this.length = length;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set (non-subfield) value.
|
||||||
|
* @param value the value
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder value(String value) {
|
||||||
|
this.value = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set subfield with ID and value.
|
||||||
|
* @param subfieldId the subfield ID
|
||||||
|
* @param value the subfield value
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder subfield(String subfieldId, String value) {
|
||||||
|
this.subfields.add(new Subfield(subfieldId, value));
|
||||||
|
subfieldIds.add(subfieldId);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set subfield ID.
|
||||||
|
* @param subfieldId the subfield ID
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder subfield(String subfieldId) {
|
||||||
|
this.subfields.add(new Subfield(subfieldId, null));
|
||||||
|
subfieldIds.add(subfieldId);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set subfield ID.
|
||||||
|
* @param subfieldId the subfield ID
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder subfield(char subfieldId) {
|
||||||
|
subfield(Character.toString(subfieldId));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a list of subfield IDs.
|
||||||
|
* @param subfieldIds the subfield IDs
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder subfields(String subfieldIds) {
|
||||||
|
for (char ch : subfieldIds.toCharArray()) {
|
||||||
|
subfield(ch);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set subfield value to the last subfield which was denoted by a subfield ID.
|
||||||
|
* @param value the subfield value
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder subfieldValue(String value) {
|
||||||
|
Subfield subfield = this.subfields.removeLast();
|
||||||
|
this.subfields.add(new Subfield(subfield.getId(), value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set subfield with help of record label information from raw data.
|
||||||
|
* @param label the record label
|
||||||
|
* @param raw the raw data
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder subfield(RecordLabel label, String raw) {
|
||||||
|
// subtract 1 because subfield identifier length includes US separator character
|
||||||
|
int subfieldidlen = label.getSubfieldIdentifierLength() - 1;
|
||||||
|
if (subfieldidlen > 0 && raw.length() >= subfieldidlen) {
|
||||||
|
String subfieldId = raw.substring(0, subfieldidlen);
|
||||||
|
subfields.add(new Subfield(subfieldId, raw.substring(subfieldidlen)));
|
||||||
|
subfieldIds.add(subfieldId);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a new data field with help of a record label from raw data.
|
||||||
|
* @param label the record label
|
||||||
|
* @param raw raw data
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder field(RecordLabel label, String raw) {
|
||||||
|
this.tag = raw.length() > 2 ? raw.substring(0, 3) : null;
|
||||||
|
if (isControl()) {
|
||||||
|
if (raw.length() > 3) {
|
||||||
|
value(raw.substring(3));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int pos = 3 + label.getIndicatorLength();
|
||||||
|
this.indicator = raw.length() >= pos ? raw.substring(3, pos) : null;
|
||||||
|
int subfieldidlen = label.getSubfieldIdentifierLength();
|
||||||
|
if (raw.length() >= pos + subfieldidlen) {
|
||||||
|
String subfieldId = raw.substring(pos, pos + subfieldidlen);
|
||||||
|
this.subfields.add(new Subfield(subfieldId, raw.substring(pos + subfieldidlen)));
|
||||||
|
subfieldIds.add(subfieldId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy a MARC field.
|
||||||
|
* @param field the MARC field to copy
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder marcField(MarcField field) {
|
||||||
|
this.tag = field.getTag();
|
||||||
|
this.indicator = field.getIndicator();
|
||||||
|
this.position = field.getPosition();
|
||||||
|
this.length = field.getLength();
|
||||||
|
this.value = field.getValue();
|
||||||
|
this.subfields = new LinkedList<>(field.getSubfields());
|
||||||
|
for (Subfield subfield : subfields) {
|
||||||
|
subfieldIds.add(subfield.getId());
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the MARC field a control field?
|
||||||
|
* @return true if control field, false if not
|
||||||
|
*/
|
||||||
|
public boolean isControl() {
|
||||||
|
return tag != null && tag.charAt(0) == '0' && tag.charAt(1) == '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the MARC field empty?
|
||||||
|
* @return true if empty, false if not
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return tag == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a MARC field.
|
||||||
|
* @return the built MARC field.
|
||||||
|
*/
|
||||||
|
public MarcField build() {
|
||||||
|
return new MarcField(tag, indicator, position, length,
|
||||||
|
value, subfields, subfieldIds.toString(), isControl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MARC subfield. A subfield consists of an ID and a value.
|
||||||
|
*/
|
||||||
|
public static class Subfield {
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
private Subfield(String id, String value) {
|
||||||
|
this.id = id;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get ID of subfield.
|
||||||
|
* @return the subfield ID
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get value fo subfield.
|
||||||
|
* @return the subfield value
|
||||||
|
*/
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return id + "=" + value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SubfieldIds extends LinkedList<String> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 7016733919690084153L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insertion sort. This is considered faster than sorting afterwards,
|
||||||
|
* especially for short lists (we have << 10 subfields at average in a field).
|
||||||
|
* @param string the string to insert
|
||||||
|
* @return true if collection changed
|
||||||
|
*/
|
||||||
|
public boolean add(String string) {
|
||||||
|
ListIterator<String> it = listIterator();
|
||||||
|
boolean added = false;
|
||||||
|
while (it.hasNext()) {
|
||||||
|
if (it.next().compareTo(string) > 0) {
|
||||||
|
it.previous();
|
||||||
|
it.add(string);
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!added) {
|
||||||
|
it.add(string);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
// comma-less appearance
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (String s : this) {
|
||||||
|
sb.append(s);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
75
src/main/java/org/xbib/marc/MarcFieldDirectory.java
Normal file
75
src/main/java/org/xbib/marc/MarcFieldDirectory.java
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc;
|
||||||
|
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MarcFieldDirectory extends TreeMap<Integer, MarcField.Builder> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 4339262603982720001L;
|
||||||
|
|
||||||
|
public MarcFieldDirectory(RecordLabel label, String encodedDirectory) throws IOException {
|
||||||
|
super();
|
||||||
|
if (label == null) {
|
||||||
|
throw new IllegalArgumentException("label must not be null");
|
||||||
|
}
|
||||||
|
int directoryLength = label.getBaseAddressOfData() - (RecordLabel.LENGTH + 1);
|
||||||
|
// assume that negative values means prohibiting directory access
|
||||||
|
int taglength = 3;
|
||||||
|
if (directoryLength > 0
|
||||||
|
&& encodedDirectory.length() >= directoryLength
|
||||||
|
&& label.getDataFieldLength() > 0
|
||||||
|
&& label.getStartingCharacterPositionLength() > 0
|
||||||
|
&& label.getSegmentIdentifierLength() >= 0) {
|
||||||
|
// directory entry size = key length (fixed at 3)
|
||||||
|
// plus data field length
|
||||||
|
// plus starting character position length
|
||||||
|
// plus segment identifier length
|
||||||
|
int entrysize = taglength
|
||||||
|
+ label.getDataFieldLength()
|
||||||
|
+ label.getStartingCharacterPositionLength()
|
||||||
|
+ label.getSegmentIdentifierLength();
|
||||||
|
if (directoryLength % entrysize != 0) {
|
||||||
|
throw new IOException("invalid ISO 2709 directory length: "
|
||||||
|
+ directoryLength + ", definitions in record label: "
|
||||||
|
+ " data field length = " + label.getDataFieldLength()
|
||||||
|
+ " starting character position length = " + label.getStartingCharacterPositionLength()
|
||||||
|
+ " segment identifier length = " + label.getSegmentIdentifierLength());
|
||||||
|
}
|
||||||
|
for (int i = RecordLabel.LENGTH; i < RecordLabel.LENGTH + directoryLength; i += entrysize) {
|
||||||
|
String tag = null;
|
||||||
|
try {
|
||||||
|
tag = encodedDirectory.substring(i, i + taglength);
|
||||||
|
int l = i + taglength + label.getDataFieldLength();
|
||||||
|
int length = Integer.parseInt(encodedDirectory.substring(i + taglength, l));
|
||||||
|
int position = label.getBaseAddressOfData() +
|
||||||
|
Integer.parseInt(encodedDirectory.substring(l, l + label.getStartingCharacterPositionLength()));
|
||||||
|
put(position, MarcField.builder().tag(tag).position(position).length(length));
|
||||||
|
} catch (StringIndexOutOfBoundsException | NumberFormatException e) {
|
||||||
|
throw new IOException("directory entry corrupt for tag = " + tag + " at position " + i +
|
||||||
|
" directory length = " + directoryLength, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
299
src/main/java/org/xbib/marc/MarcGenerator.java
Normal file
299
src/main/java/org/xbib/marc/MarcGenerator.java
Normal file
|
@ -0,0 +1,299 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc;
|
||||||
|
|
||||||
|
import static org.xbib.marc.io.InformationSeparator.FS;
|
||||||
|
import static org.xbib.marc.io.InformationSeparator.GS;
|
||||||
|
import static org.xbib.marc.io.InformationSeparator.RS;
|
||||||
|
import static org.xbib.marc.io.InformationSeparator.US;
|
||||||
|
|
||||||
|
import org.xbib.marc.io.BytesReference;
|
||||||
|
import org.xbib.marc.io.Chunk;
|
||||||
|
import org.xbib.marc.io.ChunkListener;
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
import org.xbib.marc.label.RecordLabelFixer;
|
||||||
|
import org.xbib.marc.transformer.MarcTransformer;
|
||||||
|
import org.xbib.marc.transformer.field.MarcFieldTransformers;
|
||||||
|
import org.xbib.marc.transformer.value.MarcValueTransformers;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This chunk listener interprets the chunks from a stream and generates MARC events to a given MARC listener.
|
||||||
|
*/
|
||||||
|
public class MarcGenerator implements ChunkListener<byte[], BytesReference> {
|
||||||
|
|
||||||
|
private String format;
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
private Charset charset;
|
||||||
|
|
||||||
|
private MarcListener marcListener;
|
||||||
|
|
||||||
|
private RecordLabelFixer recordLabelFixer;
|
||||||
|
|
||||||
|
private MarcFieldTransformers marcFieldTransformers;
|
||||||
|
|
||||||
|
private MarcValueTransformers marcValueTransformers;
|
||||||
|
|
||||||
|
private MarcTransformer marcTransformer;
|
||||||
|
|
||||||
|
private boolean fatalerrors;
|
||||||
|
|
||||||
|
private String data;
|
||||||
|
|
||||||
|
private int position;
|
||||||
|
|
||||||
|
private RecordLabel recordLabel;
|
||||||
|
|
||||||
|
private MarcFieldDirectory directory;
|
||||||
|
|
||||||
|
private MarcField.Builder builder;
|
||||||
|
|
||||||
|
private List<MarcField> marcFieldList;
|
||||||
|
|
||||||
|
public MarcGenerator() {
|
||||||
|
this.builder = MarcField.builder();
|
||||||
|
this.position = 0;
|
||||||
|
this.marcFieldList = new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcGenerator setFormat(String format) {
|
||||||
|
if (format != null) {
|
||||||
|
this.format = format;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcGenerator setType(String type) {
|
||||||
|
if (type != null) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcGenerator setCharset(Charset charset) {
|
||||||
|
this.charset = charset;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcGenerator setMarcListener(MarcListener marcListener) {
|
||||||
|
this.marcListener = marcListener;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcGenerator setRecordLabelFixer(RecordLabelFixer recordLabelFixer) {
|
||||||
|
this.recordLabelFixer = recordLabelFixer;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcGenerator setMarcFieldTransformers(MarcFieldTransformers marcFieldTransformers) {
|
||||||
|
this.marcFieldTransformers = marcFieldTransformers;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcGenerator setMarcValueTransformers(MarcValueTransformers marcValueTransformers) {
|
||||||
|
this.marcValueTransformers = marcValueTransformers;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcGenerator setMarcTransformer(MarcTransformer marcTransformer) {
|
||||||
|
this.marcTransformer = marcTransformer;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcGenerator setFatalErrors(boolean fatalerrors) {
|
||||||
|
this.fatalerrors = fatalerrors;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void chunk(Chunk<byte[], BytesReference> chunk) throws IOException {
|
||||||
|
char separator = (char) chunk.separator()[0];
|
||||||
|
BytesReference bytesReference = chunk.data();
|
||||||
|
if (bytesReference == null || bytesReference.length() == 0) {
|
||||||
|
emitMarcField();
|
||||||
|
emitMarcRecord();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.data = new String(bytesReference.toBytes(), charset);
|
||||||
|
if (position == 0) {
|
||||||
|
newRecord();
|
||||||
|
position += bytesReference.length() + 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (separator) {
|
||||||
|
case FS: {
|
||||||
|
emitMarcField();
|
||||||
|
emitMarcRecord();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GS: {
|
||||||
|
emitMarcField();
|
||||||
|
emitMarcRecord();
|
||||||
|
newRecord();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RS: {
|
||||||
|
emitMarcField();
|
||||||
|
if (directory == null || directory.isEmpty()) {
|
||||||
|
if (marcTransformer != null) {
|
||||||
|
marcTransformer.transform(builder, recordLabel, this.data);
|
||||||
|
} else {
|
||||||
|
builder.field(recordLabel, this.data);
|
||||||
|
}
|
||||||
|
} else if (directory.containsKey(position)) {
|
||||||
|
builder = directory.get(position);
|
||||||
|
if (builder.isControl()) {
|
||||||
|
builder.value(this.data);
|
||||||
|
} else {
|
||||||
|
// we may have fields which are broken when data is longer
|
||||||
|
// than indicator length. Then, a subfield delimiter/ID
|
||||||
|
// is missing, and we insert a blank subfield ID plus the data here.
|
||||||
|
int pos = recordLabel.getIndicatorLength();
|
||||||
|
builder.indicator(this.data.substring(0, pos));
|
||||||
|
if (pos < this.data.length()) {
|
||||||
|
builder.subfield(" ", this.data.substring(pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
boolean found = false;
|
||||||
|
for (int offset = 1; offset < 5; offset++) {
|
||||||
|
if (directory.containsKey(position + offset)) {
|
||||||
|
position = position + offset;
|
||||||
|
builder = directory.get(position);
|
||||||
|
if (builder.isControl()) {
|
||||||
|
builder.value(this.data);
|
||||||
|
} else {
|
||||||
|
builder.indicator(this.data);
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
} else if (directory.containsKey(position - offset)) {
|
||||||
|
position = position - offset;
|
||||||
|
builder = directory.get(position);
|
||||||
|
if (builder.isControl()) {
|
||||||
|
builder.value(this.data);
|
||||||
|
} else {
|
||||||
|
builder.indicator(this.data);
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found && fatalerrors) {
|
||||||
|
throw new IOException("byte position not found in MARC directory: "
|
||||||
|
+ position + " - broken directory or bad encoding?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case US: {
|
||||||
|
builder.subfield(recordLabel, this.data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
position += bytesReference.length() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void emitMarcField() {
|
||||||
|
MarcField marcField = builder.build();
|
||||||
|
if (marcValueTransformers != null) {
|
||||||
|
marcField = marcValueTransformers.transformValue(marcField);
|
||||||
|
}
|
||||||
|
if (marcFieldTransformers != null) {
|
||||||
|
marcFieldList.add(marcField);
|
||||||
|
} else {
|
||||||
|
if (!marcField.isEmpty() && marcListener != null) {
|
||||||
|
marcListener.field(marcField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder = MarcField.builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void emitMarcRecord() {
|
||||||
|
if (marcFieldTransformers != null) {
|
||||||
|
for (MarcField marcField : marcFieldTransformers.transform(marcFieldList)) {
|
||||||
|
if (!marcField.isEmpty() && marcListener != null) {
|
||||||
|
marcListener.field(marcField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
marcFieldTransformers.reset();
|
||||||
|
marcFieldList.clear();
|
||||||
|
}
|
||||||
|
if (marcListener != null) {
|
||||||
|
marcListener.endRecord();
|
||||||
|
}
|
||||||
|
position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newRecord() throws IOException {
|
||||||
|
// checkguard
|
||||||
|
if (this.data == null || this.data.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// skip line-feed (OCLC PICA quirk)
|
||||||
|
if (this.data.charAt(0) == '\n') {
|
||||||
|
this.data = data.substring(1);
|
||||||
|
}
|
||||||
|
if (this.data.length() > RecordLabel.LENGTH) {
|
||||||
|
// record label + record content = old directory-based format
|
||||||
|
this.recordLabel = RecordLabel.builder().from(this.data.substring(0, RecordLabel.LENGTH).toCharArray()).build();
|
||||||
|
if (recordLabelFixer != null) {
|
||||||
|
this.recordLabel = recordLabelFixer.fix(recordLabel);
|
||||||
|
}
|
||||||
|
if (marcListener != null) {
|
||||||
|
marcListener.beginRecord(format, type);
|
||||||
|
marcListener.leader(recordLabel.toString());
|
||||||
|
}
|
||||||
|
// create directory
|
||||||
|
this.directory = new MarcFieldDirectory(recordLabel, this.data);
|
||||||
|
if (directory.isEmpty()) {
|
||||||
|
builder.field(recordLabel, this.data.substring(RecordLabel.LENGTH));
|
||||||
|
}
|
||||||
|
} else if (this.data.length() == RecordLabel.LENGTH) {
|
||||||
|
this.recordLabel = RecordLabel.builder().from(this.data.substring(0, RecordLabel.LENGTH).toCharArray()).build();
|
||||||
|
if (recordLabelFixer != null) {
|
||||||
|
this.recordLabel = recordLabelFixer.fix(recordLabel);
|
||||||
|
}
|
||||||
|
// record label only = new format without directory
|
||||||
|
this.directory = new MarcFieldDirectory(recordLabel, this.data);
|
||||||
|
if (directory.isEmpty()) {
|
||||||
|
if (marcListener != null) {
|
||||||
|
marcListener.beginRecord(format, type);
|
||||||
|
marcListener.leader(recordLabel.toString());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
builder = MarcField.builder();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// leader too short, ignore. Use a default record label
|
||||||
|
this.recordLabel = RecordLabel.builder().build();
|
||||||
|
if (recordLabelFixer != null) {
|
||||||
|
this.recordLabel = recordLabelFixer.fix(recordLabel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
76
src/main/java/org/xbib/marc/MarcListener.java
Normal file
76
src/main/java/org/xbib/marc/MarcListener.java
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MarcListener is an interface for catching events while
|
||||||
|
* reading from ISO 2709 / MARC format family streams.
|
||||||
|
*
|
||||||
|
* Each record is framed by a leader and a trailer event. The leader
|
||||||
|
* event fires directly after the begin of a record when a leader element
|
||||||
|
* is found, the trailer (which is not defined in ISO 2709/MarcXchange) is fired
|
||||||
|
* just before the record ends. The trailer event is useful for post-processing
|
||||||
|
* fields before the record end event is fired.
|
||||||
|
*
|
||||||
|
* Data field events are fired in the sequence they are found in a record.
|
||||||
|
* Sub fields can be nested in data fields, but at most for one nesting level.
|
||||||
|
*
|
||||||
|
* Control fields are defined as data fields in the tag range from 000 to 009.
|
||||||
|
* They do not have any indicators or sub fields.
|
||||||
|
*
|
||||||
|
* Field data is carried only in the end events, where begin events carry
|
||||||
|
* information about field indicators and subfield identifiers.
|
||||||
|
*/
|
||||||
|
public interface MarcListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin of a record collection.
|
||||||
|
*/
|
||||||
|
void beginCollection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin of a record.
|
||||||
|
*
|
||||||
|
* @param format the record format
|
||||||
|
* @param type the record type
|
||||||
|
*/
|
||||||
|
void beginRecord(String format, String type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The leader (or label) of a record.
|
||||||
|
*
|
||||||
|
* @param label the label
|
||||||
|
*/
|
||||||
|
void leader(String label);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A field.
|
||||||
|
*
|
||||||
|
* @param field the field.
|
||||||
|
*/
|
||||||
|
void field(MarcField field);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End of a record.
|
||||||
|
*/
|
||||||
|
void endRecord();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End of a collection.
|
||||||
|
*/
|
||||||
|
void endCollection();
|
||||||
|
}
|
173
src/main/java/org/xbib/marc/MarcRecord.java
Normal file
173
src/main/java/org/xbib/marc/MarcRecord.java
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc;
|
||||||
|
|
||||||
|
import static org.xbib.marc.json.MarcJsonWriter.FORMAT_TAG;
|
||||||
|
import static org.xbib.marc.json.MarcJsonWriter.LEADER_TAG;
|
||||||
|
import static org.xbib.marc.json.MarcJsonWriter.TYPE_TAG;
|
||||||
|
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MARC record. This is an extended MARC record augmented with MarcXchange information.
|
||||||
|
*/
|
||||||
|
public class MarcRecord extends HashMap<String, Object> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 5305809148724342653L;
|
||||||
|
|
||||||
|
public static final MarcRecord EMPTY = Marc.builder().buildRecord();
|
||||||
|
|
||||||
|
private final String format;
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
|
||||||
|
private final transient RecordLabel recordLabel;
|
||||||
|
|
||||||
|
private final transient List<MarcField> marcFields;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a MARC record. Use {@link Marc.Builder} to create a MARC record.
|
||||||
|
* @param format the format of the record
|
||||||
|
* @param type the type
|
||||||
|
* @param recordLabel the record label
|
||||||
|
* @param marcFields the MARC field
|
||||||
|
* @param lightweight true if MARC record fields should not be entered into the underlying hash map.
|
||||||
|
*/
|
||||||
|
MarcRecord(String format, String type, RecordLabel recordLabel,
|
||||||
|
List<MarcField> marcFields, boolean lightweight) {
|
||||||
|
super();
|
||||||
|
this.format = format;
|
||||||
|
this.type = type;
|
||||||
|
this.recordLabel = recordLabel;
|
||||||
|
this.marcFields = marcFields;
|
||||||
|
if (!lightweight) {
|
||||||
|
createMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the MARC record format.
|
||||||
|
* @return the MARC record format
|
||||||
|
*/
|
||||||
|
public String getFormat() {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the MARC record type.
|
||||||
|
* @return the MARC record type
|
||||||
|
*/
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return MARC record label.
|
||||||
|
* @return the MARC record label
|
||||||
|
*/
|
||||||
|
public RecordLabel getRecordLabel() {
|
||||||
|
return recordLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the MARC fields of this record.
|
||||||
|
* @return the MARC field list
|
||||||
|
*/
|
||||||
|
public List<MarcField> getFields() {
|
||||||
|
return marcFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of MARC fields of this record where key pattern matches were found.
|
||||||
|
* @param pattern the pattern
|
||||||
|
* @return a list of MARC fields
|
||||||
|
*/
|
||||||
|
public List<MarcField> filterKey(Pattern pattern) {
|
||||||
|
return marcFields.stream().map(field ->
|
||||||
|
field.matchKey(pattern)).filter(Objects::nonNull).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Return a list of MARC fields of this record where pattern matches were found.
|
||||||
|
* @param pattern the pattern
|
||||||
|
* @return a list of MARC fields
|
||||||
|
*/
|
||||||
|
public List<MarcField> filterValue(Pattern pattern) {
|
||||||
|
return marcFields.stream().map(field ->
|
||||||
|
field.matchValue(pattern)).filter(Objects::nonNull).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return obj == this || (obj instanceof MarcRecord)
|
||||||
|
&& recordLabel.equals(((MarcRecord) obj).getRecordLabel())
|
||||||
|
&& marcFields.equals(((MarcRecord) obj).getFields());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (recordLabel.toString() + marcFields.toString()).hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void createMap() {
|
||||||
|
put(FORMAT_TAG, format);
|
||||||
|
put(TYPE_TAG, type);
|
||||||
|
put(LEADER_TAG, recordLabel.toString());
|
||||||
|
for (MarcField marcField : marcFields) {
|
||||||
|
String tag = marcField.getTag();
|
||||||
|
if (marcField.isControl()) {
|
||||||
|
put(tag, marcField.getValue());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!containsKey(tag)) {
|
||||||
|
put(tag, new HashMap<>());
|
||||||
|
}
|
||||||
|
String indicator = marcField.getIndicator();
|
||||||
|
if (indicator != null) {
|
||||||
|
indicator = indicator.replace(' ', '_');
|
||||||
|
Map<String, Object> indicators = (Map<String, Object>) get(tag);
|
||||||
|
if (!indicators.containsKey(indicator)) {
|
||||||
|
indicators.put(indicator, new HashMap<>());
|
||||||
|
}
|
||||||
|
Map<String, Object> subfields = (Map<String, Object>) indicators.get(indicator);
|
||||||
|
for (MarcField.Subfield subfield : marcField.getSubfields()) {
|
||||||
|
Object subfieldValue = subfields.get(subfield.getId());
|
||||||
|
if (subfieldValue instanceof List) {
|
||||||
|
List<String> list = (List<String>) subfieldValue;
|
||||||
|
list.add(subfield.getValue());
|
||||||
|
} else if (subfieldValue instanceof String) {
|
||||||
|
List<String> list = new LinkedList<>();
|
||||||
|
list.add((String) subfieldValue);
|
||||||
|
list.add(subfield.getValue());
|
||||||
|
subfields.put(subfield.getId(), list);
|
||||||
|
} else {
|
||||||
|
subfields.put(subfield.getId(), subfield.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
src/main/java/org/xbib/marc/MarcRecordAdapter.java
Normal file
50
src/main/java/org/xbib/marc/MarcRecordAdapter.java
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package org.xbib.marc;
|
||||||
|
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MarcRecordAdapter implements MarcListener {
|
||||||
|
|
||||||
|
private final MarcRecordListener marcRecordListener;
|
||||||
|
|
||||||
|
private Marc.Builder builder;
|
||||||
|
|
||||||
|
public MarcRecordAdapter(MarcRecordListener marcRecordListener) {
|
||||||
|
this.marcRecordListener = marcRecordListener;
|
||||||
|
this.builder = Marc.builder().lightweightRecord();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beginCollection() {
|
||||||
|
marcRecordListener.beginCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beginRecord(String format, String type) {
|
||||||
|
builder.setFormat(format);
|
||||||
|
builder.setType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void leader(String label) {
|
||||||
|
builder.recordLabel(RecordLabel.builder().from(label.toCharArray()).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void field(MarcField field) {
|
||||||
|
builder.addField(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endRecord() {
|
||||||
|
marcRecordListener.record(builder.buildRecord());
|
||||||
|
builder = Marc.builder().lightweightRecord();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endCollection() {
|
||||||
|
marcRecordListener.endCollection();
|
||||||
|
}
|
||||||
|
}
|
39
src/main/java/org/xbib/marc/MarcRecordListener.java
Normal file
39
src/main/java/org/xbib/marc/MarcRecordListener.java
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for catching MARC records.
|
||||||
|
*/
|
||||||
|
public interface MarcRecordListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin of a record collection.
|
||||||
|
*/
|
||||||
|
void beginCollection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive a MARC Record.
|
||||||
|
* @param marcRecord the record
|
||||||
|
*/
|
||||||
|
void record(MarcRecord marcRecord);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End of a collection.
|
||||||
|
*/
|
||||||
|
void endCollection();
|
||||||
|
}
|
218
src/main/java/org/xbib/marc/MarcWriter.java
Normal file
218
src/main/java/org/xbib/marc/MarcWriter.java
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc;
|
||||||
|
|
||||||
|
import org.xbib.marc.io.BytesStreamOutput;
|
||||||
|
import org.xbib.marc.io.DefaultChunk;
|
||||||
|
import org.xbib.marc.io.InformationSeparator;
|
||||||
|
import org.xbib.marc.io.SeparatorOutputStream;
|
||||||
|
import org.xbib.marc.transformer.value.MarcValueTransformer;
|
||||||
|
import org.xbib.marc.xml.MarcContentHandler;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.Flushable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ISO 2709 "stream format" MARC writer.
|
||||||
|
*/
|
||||||
|
public class MarcWriter extends MarcContentHandler implements Flushable, Closeable {
|
||||||
|
|
||||||
|
private static final int DEFAULT_BUFFER_SIZE = 8192;
|
||||||
|
|
||||||
|
private final ReentrantLock lock = new ReentrantLock(true);
|
||||||
|
|
||||||
|
private final BytesStreamOutput bytesStreamOutput;
|
||||||
|
|
||||||
|
private final SeparatorOutputStream out;
|
||||||
|
|
||||||
|
private final Charset charset;
|
||||||
|
|
||||||
|
private MarcValueTransformer marcValueTransformer;
|
||||||
|
|
||||||
|
private boolean fatalErrors;
|
||||||
|
|
||||||
|
private Exception exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a MarcWriter on an underlying output stream.
|
||||||
|
* @param out the underlying output stream
|
||||||
|
* @param charset the character set
|
||||||
|
* @throws IOException if writer can not be created
|
||||||
|
*/
|
||||||
|
public MarcWriter(OutputStream out, Charset charset) throws IOException {
|
||||||
|
this(out, charset, DEFAULT_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a MarcWriter on an underlying output stream.
|
||||||
|
* @param out the underlying output stream
|
||||||
|
* @param charset the character set
|
||||||
|
* @param buffersize the buffer size writing to the underlying output stream
|
||||||
|
* @throws IOException if writer can not be created
|
||||||
|
*/
|
||||||
|
public MarcWriter(OutputStream out, Charset charset, int buffersize) throws IOException {
|
||||||
|
this.out = new SeparatorOutputStream(out, buffersize);
|
||||||
|
this.charset = charset;
|
||||||
|
this.bytesStreamOutput = new BytesStreamOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MarcWriter setFormat(String format) {
|
||||||
|
super.setFormat(format);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MarcWriter setType(String type) {
|
||||||
|
super.setType(type);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcWriter setMarcValueTransformer(MarcValueTransformer marcValueTransformer) {
|
||||||
|
this.marcValueTransformer = marcValueTransformer;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcWriter setFatalErrors(boolean fatalErrors) {
|
||||||
|
this.fatalErrors = fatalErrors;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MarcWriter setMarcListener(MarcListener listener) {
|
||||||
|
super.setMarcListener(listener);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beginRecord(String format, String type) {
|
||||||
|
super.beginRecord(format, type);
|
||||||
|
if (exception != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void leader(String label) {
|
||||||
|
super.leader(label);
|
||||||
|
if (exception != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (label == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(label.getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
out.chunk(new DefaultChunk(InformationSeparator.GS, bytesStreamOutput.bytes()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
handleException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void field(MarcField field) {
|
||||||
|
super.field(field);
|
||||||
|
if (exception != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
// we clean up a bit. Write control field, and fields that are not empty.
|
||||||
|
// Do not care about the control field / data field order.
|
||||||
|
if (field.isControl()) {
|
||||||
|
String value = field.getValue();
|
||||||
|
if (value != null && !value.isEmpty()) {
|
||||||
|
bytesStreamOutput.write(field.getTag().getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
bytesStreamOutput.write(transform(value).getBytes(charset));
|
||||||
|
out.chunk(new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes()));
|
||||||
|
}
|
||||||
|
} else if (!field.isEmpty()) {
|
||||||
|
bytesStreamOutput.write(field.getTag().getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
bytesStreamOutput.write(field.getIndicator().getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
String value = field.getValue();
|
||||||
|
if (value != null && !value.isEmpty()) {
|
||||||
|
bytesStreamOutput.write(transform(value).getBytes(charset));
|
||||||
|
}
|
||||||
|
out.chunk(new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes()));
|
||||||
|
for (MarcField.Subfield subfield : field.getSubfields()) {
|
||||||
|
value = subfield.getValue();
|
||||||
|
if (value != null && !value.isEmpty()) {
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(subfield.getId().getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
bytesStreamOutput.write(transform(value).getBytes(charset));
|
||||||
|
out.chunk(new DefaultChunk(InformationSeparator.US, bytesStreamOutput.bytes()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
handleException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endRecord() {
|
||||||
|
super.endRecord();
|
||||||
|
try {
|
||||||
|
if (exception != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// "A record terminator (RT), ASCII control character 1D(hex), is used as the final character
|
||||||
|
// of the record, following the field terminator of the last data field."
|
||||||
|
// https://www.loc.gov/marc/specifications/specrecstruc.html
|
||||||
|
out.chunk(new DefaultChunk(InformationSeparator.GS, null));
|
||||||
|
} catch (IOException e) {
|
||||||
|
handleException(e);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
// not specified in MARC, but we require a file separator as last character of the file.
|
||||||
|
out.chunk(new DefaultChunk(InformationSeparator.FS, null));
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() throws IOException {
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Exception getException() {
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String transform(String value) {
|
||||||
|
return marcValueTransformer != null ? marcValueTransformer.transform(value) : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleException(IOException e) {
|
||||||
|
exception = e;
|
||||||
|
if (fatalErrors) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
src/main/java/org/xbib/marc/MarcXchangeConstants.java
Normal file
74
src/main/java/org/xbib/marc/MarcXchangeConstants.java
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ISO/DIS 25577 MarcXchange constants.
|
||||||
|
*/
|
||||||
|
public interface MarcXchangeConstants {
|
||||||
|
|
||||||
|
String MARCXCHANGE_V1_NS_URI = "info:lc/xmlns/marcxchange-v1";
|
||||||
|
|
||||||
|
String MARCXCHANGE_V2_NS_URI = "info:lc/xmlns/marcxchange-v2";
|
||||||
|
|
||||||
|
String MARCXCHANGE_V2_0_SCHEMA_LOCATION = "http://www.loc.gov/standards/iso25577/marcxchange-2-0.xsd";
|
||||||
|
|
||||||
|
// related (strict superset)
|
||||||
|
|
||||||
|
String MARC21_SCHEMA_URI = "http://www.loc.gov/MARC21/slim";
|
||||||
|
|
||||||
|
String MARC21_SCHEMA_LOCATION = "http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd";
|
||||||
|
|
||||||
|
// element names
|
||||||
|
|
||||||
|
String COLLECTION = "collection";
|
||||||
|
|
||||||
|
String RECORD = "record";
|
||||||
|
|
||||||
|
String LEADER = "leader";
|
||||||
|
|
||||||
|
String CONTROLFIELD = "controlfield";
|
||||||
|
|
||||||
|
String DATAFIELD = "datafield";
|
||||||
|
|
||||||
|
String SUBFIELD = "subfield";
|
||||||
|
|
||||||
|
// attribute names
|
||||||
|
|
||||||
|
String TAG_ATTRIBUTE = "tag";
|
||||||
|
|
||||||
|
String IND_ATTRIBUTE = "ind";
|
||||||
|
|
||||||
|
String CODE_ATTRIBUTE = "code";
|
||||||
|
|
||||||
|
String FORMAT_ATTRIBUTE = "format";
|
||||||
|
|
||||||
|
String TYPE_ATTRIBUTE = "type";
|
||||||
|
|
||||||
|
// formats
|
||||||
|
|
||||||
|
String MARCXCHANGE_FORMAT = "MarcXchange";
|
||||||
|
|
||||||
|
String MARC21_FORMAT = "MARC21";
|
||||||
|
|
||||||
|
// types
|
||||||
|
|
||||||
|
String BIBLIOGRAPHIC_TYPE = "Bibliographic";
|
||||||
|
|
||||||
|
String HOLDINGS_TYPE = "Holdings";
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.aleph;
|
||||||
|
|
||||||
|
import org.xbib.marc.MarcGenerator;
|
||||||
|
import org.xbib.marc.io.BytesReference;
|
||||||
|
import org.xbib.marc.io.BytesStreamOutput;
|
||||||
|
import org.xbib.marc.io.Chunk;
|
||||||
|
import org.xbib.marc.io.DefaultChunk;
|
||||||
|
import org.xbib.marc.io.InformationSeparator;
|
||||||
|
import org.xbib.marc.io.PatternInputStream;
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ALEPH SEQUENTIAL input stream implementation.
|
||||||
|
*/
|
||||||
|
public class AlephSequentialInputStream extends PatternInputStream {
|
||||||
|
|
||||||
|
private final MarcGenerator marcGenerator;
|
||||||
|
|
||||||
|
private final BytesStreamOutput bytesStreamOutput;
|
||||||
|
|
||||||
|
private RecordLabel label;
|
||||||
|
|
||||||
|
private String alephSysNumber;
|
||||||
|
|
||||||
|
public AlephSequentialInputStream(InputStream in, byte[] pattern, MarcGenerator marcGenerator) {
|
||||||
|
super(in, pattern);
|
||||||
|
this.marcGenerator = marcGenerator;
|
||||||
|
this.bytesStreamOutput = new BytesStreamOutput();
|
||||||
|
// this format might come without a record label, create a default one
|
||||||
|
this.label = RecordLabel.builder().setIndicatorLength(2).setSubfieldIdentifierLength(1).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processChunk(Chunk<byte[], BytesReference> chunk) throws IOException {
|
||||||
|
BytesReference data = chunk.data();
|
||||||
|
String str = data.toUtf8();
|
||||||
|
String value = str.substring(18);
|
||||||
|
String nextAlephSysNumber = str.substring(0, 9);
|
||||||
|
BytesReference tag = data.slice(10, 3);
|
||||||
|
BytesReference indicator = data.slice(13, 2);
|
||||||
|
boolean newLabel;
|
||||||
|
if ("LDR".equals(tag.toUtf8())) {
|
||||||
|
label = RecordLabel.builder().from(value.replace('^', ' ').toCharArray()).build();
|
||||||
|
newLabel = true;
|
||||||
|
} else {
|
||||||
|
newLabel = false;
|
||||||
|
}
|
||||||
|
if (alephSysNumber == null || !alephSysNumber.equals(nextAlephSysNumber)) {
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(label.toString().getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.GS, bytesStreamOutput.bytes()));
|
||||||
|
this.alephSysNumber = nextAlephSysNumber;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (newLabel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ("00".equals(str.substring(10, 12))) {
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(tag.toBytes());
|
||||||
|
// skip indicator on control fiels
|
||||||
|
bytesStreamOutput.write(value.replace('^', ' ').getBytes(StandardCharsets.UTF_8));
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(tag.toBytes());
|
||||||
|
bytesStreamOutput.write(indicator.toBytes());
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes()));
|
||||||
|
String[] subfields = value.split(Pattern.quote("$$"));
|
||||||
|
for (String subfield : subfields) {
|
||||||
|
if (subfield.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(subfield.getBytes(StandardCharsets.UTF_8));
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.US, bytesStreamOutput.bytes()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.FS, null));
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for processing Aleph MARC dialect.
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.aleph;
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.bibliomondo;
|
||||||
|
|
||||||
|
import org.xbib.marc.MarcGenerator;
|
||||||
|
import org.xbib.marc.io.BytesArray;
|
||||||
|
import org.xbib.marc.io.BytesReference;
|
||||||
|
import org.xbib.marc.io.BytesStreamOutput;
|
||||||
|
import org.xbib.marc.io.Chunk;
|
||||||
|
import org.xbib.marc.io.DefaultChunk;
|
||||||
|
import org.xbib.marc.io.InformationSeparator;
|
||||||
|
import org.xbib.marc.io.PatternInputStream;
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BiblioMondo dialect of MARC.
|
||||||
|
*
|
||||||
|
* The format is specified as follows:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>character set is ANSEL</li>
|
||||||
|
* <li>each MARC field is delimited by carriage-return/line-feed (not by RS)</li>
|
||||||
|
* <li>each record is introduced by a record label with tag "###"</li>
|
||||||
|
* <li>each control field has a tag immediately followed by value</li>
|
||||||
|
* <li>each data field has two indicator characters, and subfields</li>
|
||||||
|
* <li>subfields are delimited by US</li>
|
||||||
|
* <li>but each subfield begins with a subfield ID plus FS (so FS must be dropped)</li>
|
||||||
|
* <li>there may be extra empty lines between records</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class BiblioMondoInputStream extends PatternInputStream {
|
||||||
|
|
||||||
|
private final MarcGenerator marcGenerator;
|
||||||
|
|
||||||
|
private final BytesStreamOutput bytesStreamOutput;
|
||||||
|
|
||||||
|
public BiblioMondoInputStream(InputStream in, byte[] pattern, MarcGenerator marcGenerator) {
|
||||||
|
super(in, pattern);
|
||||||
|
this.marcGenerator = marcGenerator;
|
||||||
|
this.bytesStreamOutput = new BytesStreamOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processChunk(Chunk<byte[], BytesReference> chunk) throws IOException {
|
||||||
|
BytesReference data = chunk.data();
|
||||||
|
if (data.length() < 5) {
|
||||||
|
// broken, invalid tag+indicator info
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[] bytes = data.slice(0, 3).toBytes();
|
||||||
|
String tag = new String(bytes, StandardCharsets.ISO_8859_1);
|
||||||
|
if ("###".equals(tag)) { // leader
|
||||||
|
String value = new String(data.slice(4, data.length() - 4).toBytes(), StandardCharsets.ISO_8859_1);
|
||||||
|
RecordLabel label = RecordLabel.builder().from(value.toCharArray())
|
||||||
|
.setIndicatorLength(2).setSubfieldIdentifierLength(2).build();
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.GS, new BytesArray(label.asBytes())));
|
||||||
|
} else if (tag.startsWith("00")) {
|
||||||
|
// control field
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(bytes);
|
||||||
|
bytesStreamOutput.write(data.slice(3, data.length() - 3).toBytes());
|
||||||
|
bytesStreamOutput.close();
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes()));
|
||||||
|
} else {
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(bytes); // tag
|
||||||
|
bytesStreamOutput.write(data.slice(3, 2).toBytes()); // indicator
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes()));
|
||||||
|
BytesArray bytesArray = new BytesArray(data.slice(5, data.length() - 5).toBytes());
|
||||||
|
List<byte[]> list = bytesArray.split((byte) 0x1f);
|
||||||
|
for (byte[] b : list) {
|
||||||
|
if (b.length < 3) {
|
||||||
|
continue; //empty subfield, skip
|
||||||
|
}
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(b[0]); // subfield ID
|
||||||
|
// skip strange 0x1f byte at b[1]
|
||||||
|
bytesStreamOutput.write(b, 2, b.length - 2); // subfield value
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.US, bytesStreamOutput.bytes()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.FS, null));
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for processing "tagged" MARC format (text files).
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.bibliomondo;
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.mab.diskette;
|
||||||
|
|
||||||
|
import org.xbib.marc.MarcGenerator;
|
||||||
|
import org.xbib.marc.io.BytesArray;
|
||||||
|
import org.xbib.marc.io.BytesReference;
|
||||||
|
import org.xbib.marc.io.BytesStreamOutput;
|
||||||
|
import org.xbib.marc.io.Chunk;
|
||||||
|
import org.xbib.marc.io.DefaultChunk;
|
||||||
|
import org.xbib.marc.io.InformationSeparator;
|
||||||
|
import org.xbib.marc.io.PatternInputStream;
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An input stream for MAB DISKETTE, using an underlying pattern input stream.
|
||||||
|
* The chunks will be rearranged to get fired off using a
|
||||||
|
* given MarcListener in order to produce valid MARC chunks.
|
||||||
|
*/
|
||||||
|
public class MabDisketteInputStream extends PatternInputStream {
|
||||||
|
|
||||||
|
private final MarcGenerator marcGenerator;
|
||||||
|
|
||||||
|
private final BytesStreamOutput bytesStreamOutput;
|
||||||
|
|
||||||
|
private final char subfieldDelimiter;
|
||||||
|
|
||||||
|
private byte[] lastchunk;
|
||||||
|
|
||||||
|
public MabDisketteInputStream(InputStream in, byte[] pattern, MarcGenerator marcGenerator) {
|
||||||
|
this(in, pattern, '\u0000', marcGenerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MabDisketteInputStream(InputStream in, byte[] pattern, char subfieldDelimiter, MarcGenerator marcGenerator) {
|
||||||
|
super(in, pattern);
|
||||||
|
this.marcGenerator = marcGenerator;
|
||||||
|
this.subfieldDelimiter = subfieldDelimiter;
|
||||||
|
this.bytesStreamOutput = new BytesStreamOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processChunk(Chunk<byte[], BytesReference> chunk) throws IOException {
|
||||||
|
BytesReference data = chunk.data();
|
||||||
|
if (data.length() < 5) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[] numberBytes = data.slice(0, 3).toBytes();
|
||||||
|
String number = new String(numberBytes, StandardCharsets.ISO_8859_1);
|
||||||
|
if ("###".equals(number)) { // leader
|
||||||
|
// skip blank after ###
|
||||||
|
String value = new String(data.slice(4, data.length() - 4).toBytes(), StandardCharsets.ISO_8859_1);
|
||||||
|
RecordLabel label = RecordLabel.builder().from(value.toCharArray())
|
||||||
|
.setIndicatorLength(2).setSubfieldIdentifierLength(2).build();
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.GS, new BytesArray(label.asBytes())));
|
||||||
|
} else if (number.startsWith("00")) {
|
||||||
|
// control field, throw away indicators and subfields (if any)
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(numberBytes);
|
||||||
|
bytesStreamOutput.write(data.slice(4, data.length() - 4).toBytes());
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes()));
|
||||||
|
} else if (isNumber(number)) {
|
||||||
|
// data field
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(numberBytes);
|
||||||
|
bytesStreamOutput.write(data.slice(3, 1).toBytes()); // first indicator
|
||||||
|
bytesStreamOutput.write(' '); // second indicator
|
||||||
|
Chunk<byte[], BytesReference> newchunk = new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes());
|
||||||
|
marcGenerator.chunk(newchunk);
|
||||||
|
lastchunk = newchunk.data().toBytes().clone();
|
||||||
|
boolean hasSubfields = data.slice(4, 1).toBytes()[0] == subfieldDelimiter;
|
||||||
|
if (!hasSubfields) {
|
||||||
|
// The challenge of mapping MAB-Diskette to MarcXchange is
|
||||||
|
// that MAB is subfield-less. We map to a "default" subfield, e.g. "a".
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write('a');
|
||||||
|
bytesStreamOutput.write(data.slice(4, data.length() - 4).toBytes());
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.US, bytesStreamOutput.bytes()));
|
||||||
|
} else {
|
||||||
|
// challenge: split only if subfieldDelimiter is set on the first character. If not set, no subfields at all.
|
||||||
|
BytesArray bytesArray = new BytesArray(data.slice(4, data.length() - 4).toBytes());
|
||||||
|
List<byte[]> list = bytesArray.split((byte) subfieldDelimiter);
|
||||||
|
for (byte[] b : list) {
|
||||||
|
if (b.length < 3) {
|
||||||
|
continue; //empty subfield, skip
|
||||||
|
}
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(b); // subfield ID + value
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.US, bytesStreamOutput.bytes()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (lastchunk != null) {
|
||||||
|
// we found a continuation line. Just repeat last tag with the continuation content.
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(lastchunk);
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes()));
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write('a');
|
||||||
|
bytesStreamOutput.write(data.toBytes());
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.US, bytesStreamOutput.bytes()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isNumber(String s) {
|
||||||
|
boolean b = true;
|
||||||
|
for (char ch : s.toCharArray()) {
|
||||||
|
if (ch < '0' || ch > '9') {
|
||||||
|
b = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for MAB-DISKETTE format.
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.mab.diskette;
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for processing MAB dialect of MARC.
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.mab;
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.mab.xml;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MAB XML constants.
|
||||||
|
*/
|
||||||
|
public interface MabXMLConstants {
|
||||||
|
|
||||||
|
String MABXML_NAMESPACE = "http://www.ddb.de/professionell/mabxml/mabxml-1.xsd";
|
||||||
|
|
||||||
|
// element names
|
||||||
|
|
||||||
|
String DATEI = "datei";
|
||||||
|
|
||||||
|
String DATENSATZ = "datensatz";
|
||||||
|
|
||||||
|
String FELD = "feld";
|
||||||
|
|
||||||
|
String UF = "uf";
|
||||||
|
|
||||||
|
// attribute names
|
||||||
|
|
||||||
|
String TYP = "typ";
|
||||||
|
|
||||||
|
String NR = "nr";
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.mab.xml;
|
||||||
|
|
||||||
|
import org.xbib.marc.MarcField;
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
import org.xbib.marc.xml.MarcContentHandler;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Sax-ContentHandler-based MAB XML handler can handle SaX event input
|
||||||
|
* and fires events to a MarcXchange listener.
|
||||||
|
*/
|
||||||
|
public class MabXMLContentHandler extends MarcContentHandler implements MabXMLConstants {
|
||||||
|
|
||||||
|
private Set<String> validNamespaces = new HashSet<>(Collections.singletonList(MABXML_NAMESPACE));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultFormat() {
|
||||||
|
return "MabXML";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultType() {
|
||||||
|
return "h";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MabXMLContentHandler addNamespace(String uri) {
|
||||||
|
this.validNamespaces.add(uri);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
|
||||||
|
content.setLength(0);
|
||||||
|
if (!isNamespace(uri)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (localName) {
|
||||||
|
case DATEI: {
|
||||||
|
beginCollection();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DATENSATZ: {
|
||||||
|
String type = null;
|
||||||
|
for (int i = 0; i < atts.getLength(); i++) {
|
||||||
|
if (TYP.equals(atts.getLocalName(i))) {
|
||||||
|
type = atts.getValue(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type == null) {
|
||||||
|
type = this.type;
|
||||||
|
}
|
||||||
|
beginRecord(format, type);
|
||||||
|
// create leader
|
||||||
|
RecordLabel recordLabel = RecordLabel.builder().setIndicatorLength(1).setSubfieldIdentifierLength(0)
|
||||||
|
.build();
|
||||||
|
leader(recordLabel.toString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FELD: {
|
||||||
|
String tag = null;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.setLength(atts.getLength());
|
||||||
|
for (int i = 0; i < atts.getLength(); i++) {
|
||||||
|
String name = atts.getLocalName(i);
|
||||||
|
if (NR.equals(name)) {
|
||||||
|
tag = atts.getValue(i);
|
||||||
|
}
|
||||||
|
if (name.startsWith(IND_ATTRIBUTE)) {
|
||||||
|
// 'ind', one char for one indicator
|
||||||
|
sb.setCharAt(0, atts.getValue(i).charAt(0));
|
||||||
|
sb.setLength(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MarcField.Builder builder = MarcField.builder().tag(tag);
|
||||||
|
builder.indicator(sb.toString());
|
||||||
|
stack.push(builder);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UF: {
|
||||||
|
stack.peek().subfield(atts.getValue(CODE_ATTRIBUTE), null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||||
|
if (!isNamespace(uri)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (localName) {
|
||||||
|
case DATEI: {
|
||||||
|
endCollection();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DATENSATZ: {
|
||||||
|
endRecord();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FELD: {
|
||||||
|
MarcField marcField = stack.pop().value(content.toString()).build();
|
||||||
|
if (marcValueTransformers != null) {
|
||||||
|
marcField = marcValueTransformers.transformValue(marcField);
|
||||||
|
}
|
||||||
|
field(marcField);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UF: {
|
||||||
|
stack.peek().subfieldValue(content.toString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
content.setLength(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isNamespace(String uri) {
|
||||||
|
return validNamespaces.contains(uri);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for processing MAB-XML dialect of MARC.
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.mab.xml;
|
49
src/main/java/org/xbib/marc/dialects/pica/PicaConstants.java
Normal file
49
src/main/java/org/xbib/marc/dialects/pica/PicaConstants.java
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.pica;
|
||||||
|
|
||||||
|
import org.xbib.marc.MarcXchangeConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface PicaConstants extends MarcXchangeConstants {
|
||||||
|
|
||||||
|
String PICAXML_NAMESPACE = "http://www.oclcpica.org/xmlns/ppxml-1.0";
|
||||||
|
|
||||||
|
String PICAXML_PREFIX = "ppxml";
|
||||||
|
|
||||||
|
String SRW_PICAXML_NAMESPACE = "info:srw/schema/5/picaXML-v1.0";
|
||||||
|
|
||||||
|
// tags
|
||||||
|
|
||||||
|
String GLOBAL_TAG = "global";
|
||||||
|
|
||||||
|
String SUBF_TAG = "subf";
|
||||||
|
|
||||||
|
// attributes
|
||||||
|
|
||||||
|
String OPACFLAG = "opacflag";
|
||||||
|
|
||||||
|
String STATUS = "status";
|
||||||
|
|
||||||
|
String ID_ATTRIBUTE = "id";
|
||||||
|
|
||||||
|
String OCC = "occ";
|
||||||
|
|
||||||
|
String OCCURENCE_ATTRIBUTE = "occurrence";
|
||||||
|
}
|
115
src/main/java/org/xbib/marc/dialects/pica/PicaInputStream.java
Normal file
115
src/main/java/org/xbib/marc/dialects/pica/PicaInputStream.java
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.pica;
|
||||||
|
|
||||||
|
import org.xbib.marc.MarcGenerator;
|
||||||
|
import org.xbib.marc.io.BytesArray;
|
||||||
|
import org.xbib.marc.io.BytesReference;
|
||||||
|
import org.xbib.marc.io.BytesStreamOutput;
|
||||||
|
import org.xbib.marc.io.Chunk;
|
||||||
|
import org.xbib.marc.io.DefaultChunk;
|
||||||
|
import org.xbib.marc.io.InformationSeparator;
|
||||||
|
import org.xbib.marc.io.PatternInputStream;
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pica dialect of MARC.
|
||||||
|
*
|
||||||
|
* The format is specified as follows:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>character set is PICA or UTF-8</li>
|
||||||
|
* <li>each record is delimited by line-feed</li>
|
||||||
|
* <li>each field is delimited by RS</li>
|
||||||
|
* <li>no record label</li>
|
||||||
|
* <li>each field tag has one indicator (including "@") and a repeat counter (like 201B/01)</li>
|
||||||
|
* <li>subfields are delimited by US and can even be empty</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class PicaInputStream extends PatternInputStream {
|
||||||
|
|
||||||
|
private final MarcGenerator marcGenerator;
|
||||||
|
|
||||||
|
private final BytesStreamOutput bytesStreamOutput;
|
||||||
|
|
||||||
|
public PicaInputStream(InputStream in, byte[] pattern, MarcGenerator marcGenerator) {
|
||||||
|
super(in, pattern);
|
||||||
|
this.marcGenerator = marcGenerator;
|
||||||
|
this.bytesStreamOutput = new BytesStreamOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processChunk(Chunk<byte[], BytesReference> chunk) throws IOException {
|
||||||
|
BytesArray array = new BytesArray(chunk.data().toBytes());
|
||||||
|
Chunk<byte[], BytesReference> newChunk;
|
||||||
|
// split into data fields
|
||||||
|
List<byte[]> fields = array.split((byte) 0x1e);
|
||||||
|
if (fields.size() > 1) {
|
||||||
|
RecordLabel label = RecordLabel.builder()
|
||||||
|
.setIndicatorLength(2).setSubfieldIdentifierLength(2).build();
|
||||||
|
newChunk = new DefaultChunk(InformationSeparator.GS, new BytesArray(label.asBytes()));
|
||||||
|
marcGenerator.chunk(newChunk);
|
||||||
|
for (byte[] field : fields) {
|
||||||
|
if (field.length < 3) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BytesArray fieldByteArray = new BytesArray(field);
|
||||||
|
// control field?
|
||||||
|
if (field[0] == '0' && field[1] == '0') {
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(fieldByteArray.slice(0, 3).toBytes());
|
||||||
|
// skip two indicators and subfield delimiter '$' and '0'
|
||||||
|
bytesStreamOutput.write(fieldByteArray.slice(7, fieldByteArray.length() - 7).toBytes());
|
||||||
|
newChunk = new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes());
|
||||||
|
marcGenerator.chunk(newChunk);
|
||||||
|
} else {
|
||||||
|
// split into subfields
|
||||||
|
List<byte[]> subfields = fieldByteArray.split((byte) 0x1f);
|
||||||
|
if (!subfields.isEmpty()) {
|
||||||
|
byte[] datafield = subfields.get(0);
|
||||||
|
// move PICA key into MARC indicators
|
||||||
|
byte[] ind1 = fieldByteArray.slice(3, 1).toBytes();
|
||||||
|
byte ind2 = ' ';
|
||||||
|
if (datafield.length == 8) {
|
||||||
|
// does not always work well...
|
||||||
|
ind2 = (byte) ('0' + (10 * (datafield[5] - '0')) + (datafield[6] - '0'));
|
||||||
|
}
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(fieldByteArray.slice(0, 3).toBytes());
|
||||||
|
bytesStreamOutput.write(ind1); // indicator 1
|
||||||
|
bytesStreamOutput.write(ind2); // indicator 2
|
||||||
|
newChunk = new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes());
|
||||||
|
marcGenerator.chunk(newChunk);
|
||||||
|
for (int i = 1; i < subfields.size(); i++) {
|
||||||
|
byte[] subfield = subfields.get(i);
|
||||||
|
if (subfield.length > 1) {
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(subfield);
|
||||||
|
newChunk = new DefaultChunk(InformationSeparator.US, bytesStreamOutput.bytes());
|
||||||
|
marcGenerator.chunk(newChunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.pica;
|
||||||
|
|
||||||
|
import org.xbib.marc.MarcGenerator;
|
||||||
|
import org.xbib.marc.io.BytesArray;
|
||||||
|
import org.xbib.marc.io.BytesReference;
|
||||||
|
import org.xbib.marc.io.BytesStreamOutput;
|
||||||
|
import org.xbib.marc.io.Chunk;
|
||||||
|
import org.xbib.marc.io.DefaultChunk;
|
||||||
|
import org.xbib.marc.io.InformationSeparator;
|
||||||
|
import org.xbib.marc.io.PatternInputStream;
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pica plain, a line-feed-delimited text file dialect of MARC.
|
||||||
|
*
|
||||||
|
* The format is specified as follows:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>character set is PICA or UTF-8</li>
|
||||||
|
* <li>each record is delimited by empy line</li>
|
||||||
|
* <li>each field is delimited by line-feed</li>
|
||||||
|
* <li>no record label</li>
|
||||||
|
* <li>each field tag has one indicator (including "@") and a repeat counter (like 201B/01)</li>
|
||||||
|
* <li>subfields are delimited by '$' and can even be empty</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class PicaPlainInputStream extends PatternInputStream {
|
||||||
|
|
||||||
|
private final MarcGenerator marcGenerator;
|
||||||
|
|
||||||
|
private final BytesStreamOutput bytesStreamOutput;
|
||||||
|
|
||||||
|
private boolean started;
|
||||||
|
|
||||||
|
public PicaPlainInputStream(InputStream in, byte[] pattern, MarcGenerator marcGenerator) {
|
||||||
|
super(in, pattern);
|
||||||
|
this.marcGenerator = marcGenerator;
|
||||||
|
this.bytesStreamOutput = new BytesStreamOutput();
|
||||||
|
this.started = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processChunk(Chunk<byte[], BytesReference> chunk) throws IOException {
|
||||||
|
BytesArray array = new BytesArray(chunk.data().toBytes());
|
||||||
|
Chunk<byte[], BytesReference> newChunk;
|
||||||
|
// no leaders, so we need our own start logic
|
||||||
|
if (started) {
|
||||||
|
startRecord();
|
||||||
|
started = false;
|
||||||
|
}
|
||||||
|
if (chunk.data().length() < 2) {
|
||||||
|
startRecord();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// control field?
|
||||||
|
if (array.get(0) == '0' && array.get(1) == '0') {
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(array.slice(0, 3).toBytes());
|
||||||
|
// skip two indicators and subfield delimiter '$' and '0'
|
||||||
|
bytesStreamOutput.write(array.slice(7, array.length() - 7).toBytes());
|
||||||
|
newChunk = new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes());
|
||||||
|
marcGenerator.chunk(newChunk);
|
||||||
|
} else {
|
||||||
|
// split into subfields
|
||||||
|
List<byte[]> subfields = array.split((byte) '$');
|
||||||
|
if (!subfields.isEmpty()) {
|
||||||
|
byte[] datafield = subfields.get(0);
|
||||||
|
// move PICA key into MARC indicators
|
||||||
|
byte[] ind1 = array.slice(3, 1).toBytes();
|
||||||
|
byte ind2 = ' ';
|
||||||
|
if (datafield.length == 8) {
|
||||||
|
// does not always work well...
|
||||||
|
ind2 = (byte) ('0' + (10 * (datafield[5] - '0')) + (datafield[6] - '0'));
|
||||||
|
}
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(array.slice(0, 3).toBytes());
|
||||||
|
bytesStreamOutput.write(ind1); // indicator 1
|
||||||
|
bytesStreamOutput.write(ind2); // indicator 2
|
||||||
|
newChunk = new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes());
|
||||||
|
marcGenerator.chunk(newChunk);
|
||||||
|
for (int i = 1; i < subfields.size(); i++) {
|
||||||
|
byte[] subfield = subfields.get(i);
|
||||||
|
if (subfield.length > 1) {
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
bytesStreamOutput.write(subfield);
|
||||||
|
newChunk = new DefaultChunk(InformationSeparator.US, bytesStreamOutput.bytes());
|
||||||
|
marcGenerator.chunk(newChunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startRecord() throws IOException {
|
||||||
|
RecordLabel label = RecordLabel.builder()
|
||||||
|
.setIndicatorLength(2).setSubfieldIdentifierLength(2).build();
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.GS, new BytesArray(label.asBytes())));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.pica;
|
||||||
|
|
||||||
|
import org.xbib.marc.MarcField;
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
import org.xbib.marc.xml.MarcContentHandler;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Sax-ContentHandler-based Pica XML handler can handle SaX event input
|
||||||
|
* and fires events to a MarcXchange listener.
|
||||||
|
*/
|
||||||
|
public class PicaXMLContentHandler extends MarcContentHandler implements PicaConstants {
|
||||||
|
|
||||||
|
private Set<String> validNamespaces =
|
||||||
|
new HashSet<>(Arrays.asList(PICAXML_NAMESPACE, SRW_PICAXML_NAMESPACE));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultFormat() {
|
||||||
|
return "Pica";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultType() {
|
||||||
|
return "XML";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beginRecord(String format, String type) {
|
||||||
|
this.marcListener = listeners.get(type != null ? type : this.type);
|
||||||
|
if (marcListener != null) {
|
||||||
|
marcListener.beginRecord(format, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void field(MarcField marcField) {
|
||||||
|
MarcField field = marcField;
|
||||||
|
if (marcValueTransformers != null) {
|
||||||
|
field = marcValueTransformers.transformValue(field);
|
||||||
|
}
|
||||||
|
if (marcListener != null) {
|
||||||
|
marcListener.field(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
|
||||||
|
content.setLength(0);
|
||||||
|
if (!isNamespace(uri)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (localName) {
|
||||||
|
case RECORD: {
|
||||||
|
beginRecord(format, type);
|
||||||
|
// create leader
|
||||||
|
RecordLabel recordLabel = RecordLabel.builder().setIndicatorLength(1)
|
||||||
|
.setSubfieldIdentifierLength(0).build();
|
||||||
|
leader(recordLabel.toString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DATAFIELD: {
|
||||||
|
String tag = null;
|
||||||
|
String indicator = null;
|
||||||
|
for (int i = 0; i < atts.getLength(); i++) {
|
||||||
|
String name = atts.getLocalName(i);
|
||||||
|
String value = atts.getValue(i);
|
||||||
|
if (TAG_ATTRIBUTE.equals(name)) {
|
||||||
|
tag = value.substring(0, 3);
|
||||||
|
indicator = value.substring(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
MarcField.Builder builder = MarcField.builder().tag(tag).indicator(indicator);
|
||||||
|
stack.push(builder);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TAG_ATTRIBUTE: {
|
||||||
|
String tag = null;
|
||||||
|
String indicator = null;
|
||||||
|
for (int i = 0; i < atts.getLength(); i++) {
|
||||||
|
String name = atts.getLocalName(i);
|
||||||
|
String value = atts.getValue(i);
|
||||||
|
if (ID_ATTRIBUTE.equals(name)) {
|
||||||
|
tag = value.substring(0, 3);
|
||||||
|
indicator = value.substring(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
MarcField.Builder builder = MarcField.builder().tag(tag).indicator(indicator);
|
||||||
|
stack.push(builder);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SUBFIELD: {
|
||||||
|
stack.peek().subfield(atts.getValue(CODE_ATTRIBUTE), null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SUBF_TAG: {
|
||||||
|
stack.peek().subfield(atts.getValue(ID_ATTRIBUTE), null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GLOBAL_TAG:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("unknown begin element: " +
|
||||||
|
uri + " " + localName + " " + qName + " atts=" + atts.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||||
|
if (!isNamespace(uri)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (localName) {
|
||||||
|
case RECORD: {
|
||||||
|
endRecord();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DATAFIELD: {
|
||||||
|
MarcField marcField = stack.pop().build();
|
||||||
|
if (marcValueTransformers != null) {
|
||||||
|
marcField = marcValueTransformers.transformValue(marcField);
|
||||||
|
}
|
||||||
|
field(marcField);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TAG_ATTRIBUTE: {
|
||||||
|
MarcField marcField = stack.pop().value(content.toString()).build();
|
||||||
|
if (marcValueTransformers != null) {
|
||||||
|
marcField = marcValueTransformers.transformValue(marcField);
|
||||||
|
}
|
||||||
|
field(marcField);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SUBFIELD:
|
||||||
|
case SUBF_TAG: {
|
||||||
|
stack.peek().subfieldValue(content.toString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GLOBAL_TAG:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("unknown end element: " + uri + " " + localName + " " + qName);
|
||||||
|
}
|
||||||
|
content.setLength(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isNamespace(String uri) {
|
||||||
|
return validNamespaces.contains(uri);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for processing the Pica dialect of MARC.
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.pica;
|
147
src/main/java/org/xbib/marc/dialects/sisis/SisisInputStream.java
Normal file
147
src/main/java/org/xbib/marc/dialects/sisis/SisisInputStream.java
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.sisis;
|
||||||
|
|
||||||
|
import org.xbib.marc.MarcGenerator;
|
||||||
|
import org.xbib.marc.io.BytesReference;
|
||||||
|
import org.xbib.marc.io.BytesStreamOutput;
|
||||||
|
import org.xbib.marc.io.Chunk;
|
||||||
|
import org.xbib.marc.io.DefaultChunk;
|
||||||
|
import org.xbib.marc.io.InformationSeparator;
|
||||||
|
import org.xbib.marc.io.PatternInputStream;
|
||||||
|
import org.xbib.marc.label.RecordLabel;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An input stream for reading SISIS format, a dialect of MARC.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* 0000:248821
|
||||||
|
* 0002:04.03.2009
|
||||||
|
* 0014.001:61 P 08/09-36B
|
||||||
|
* 0015.001:ger
|
||||||
|
* 0029.001:06
|
||||||
|
* 0100.001:Beimdiek, Christoph
|
||||||
|
* 0101.001:Hanrath, Wilhelm [Betreuer]
|
||||||
|
* 0331.001:Portierung des webbasierten multimedialen Lehr- und Lernsystems NUMAS zur numerischen Mathematik
|
||||||
|
* und Statistik auf ein Linux-basiertes Serversystem
|
||||||
|
* 0425:2008
|
||||||
|
* 0519.001:Aachen, FH, Bachelorarbeit, 2008
|
||||||
|
* 9999:
|
||||||
|
*
|
||||||
|
* 0000:468277
|
||||||
|
* 0002:13.12.2013
|
||||||
|
* 0014.001:61 EU 13-46B
|
||||||
|
* 0015.001:eng
|
||||||
|
* 0029.001:06
|
||||||
|
* 0100.001:Belouanas, Abdel
|
||||||
|
* 0101.001:Helsper, Christoph [Betreuer]
|
||||||
|
* 0331.001:A proposal for future clean power production for morocco
|
||||||
|
* 0425:2013
|
||||||
|
* 0519.001:Aachen, FH, Bachelorarbeit, 2013
|
||||||
|
* 9999:
|
||||||
|
*
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
public class SisisInputStream extends PatternInputStream {
|
||||||
|
|
||||||
|
private final MarcGenerator marcGenerator;
|
||||||
|
|
||||||
|
private final BytesStreamOutput bytesStreamOutput;
|
||||||
|
|
||||||
|
private final RecordLabel label;
|
||||||
|
|
||||||
|
private boolean labelEmitted;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a SISIS input stream.
|
||||||
|
* @param in the underlying input stream
|
||||||
|
* @param pattern the pattern for the separator
|
||||||
|
* @param marcGenerator a MARC generator
|
||||||
|
*/
|
||||||
|
public SisisInputStream(InputStream in, byte[] pattern, MarcGenerator marcGenerator) {
|
||||||
|
super(in, pattern);
|
||||||
|
this.marcGenerator = marcGenerator;
|
||||||
|
this.bytesStreamOutput = new BytesStreamOutput();
|
||||||
|
// this format comes without a record label, create a default one
|
||||||
|
this.label = RecordLabel.builder().setIndicatorLength(2).setSubfieldIdentifierLength(1).build();
|
||||||
|
this.labelEmitted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processChunk(Chunk<byte[], BytesReference> chunk) throws IOException {
|
||||||
|
BytesReference data = chunk.data();
|
||||||
|
int pos = data.indexOf((byte) ':', 0, data.length());
|
||||||
|
if (pos <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[] numberBytes = data.slice(0, pos).toBytes();
|
||||||
|
String number = new String(numberBytes, StandardCharsets.US_ASCII);
|
||||||
|
String ind2 = " ";
|
||||||
|
// number can have a counter for field repetitions
|
||||||
|
int pos2 = number.indexOf('.');
|
||||||
|
if (pos2 > 0) {
|
||||||
|
ind2 = number.substring(pos2 + 3, pos2 + 4); // drop pos+1, pos+2 (always "0"?)
|
||||||
|
number = number.substring(0, pos2);
|
||||||
|
}
|
||||||
|
// number is always four characters, take the last three and make the first character to "indicator 1"
|
||||||
|
String ind1 = number.substring(0, 1);
|
||||||
|
number = number.substring(1, 4);
|
||||||
|
// special field 9999 means "end of record" (i.e. group delimiter)
|
||||||
|
if ("999".equals(number)) {
|
||||||
|
labelEmitted = false;
|
||||||
|
} else {
|
||||||
|
String designator;
|
||||||
|
// move "kat key" from 000 to 001
|
||||||
|
if ("000".equals(number)) {
|
||||||
|
number = "001";
|
||||||
|
designator = number;
|
||||||
|
} else if (number.startsWith("00")) {
|
||||||
|
if (!" ".equals(ind2)) {
|
||||||
|
// move fields out of controlfield area "000"-"009"
|
||||||
|
// to (a hopefully unndefined) area "900-909" (plus ind2="9")
|
||||||
|
designator = "9" + number.substring(1, 3) + "9" + ind2 + "a";
|
||||||
|
} else {
|
||||||
|
designator = number;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
designator = number + ind1 + ind2 + "a";
|
||||||
|
}
|
||||||
|
if (!labelEmitted) {
|
||||||
|
bytesStreamOutput.write(label.toString().getBytes(StandardCharsets.US_ASCII));
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.GS, bytesStreamOutput.bytes()));
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
labelEmitted = true;
|
||||||
|
}
|
||||||
|
bytesStreamOutput.write(designator.getBytes(StandardCharsets.US_ASCII));
|
||||||
|
bytesStreamOutput.write(data.slice(pos + 1, data.length() - (pos + 1)).toBytes());
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.RS, bytesStreamOutput.bytes()));
|
||||||
|
bytesStreamOutput.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
marcGenerator.chunk(new DefaultChunk(InformationSeparator.FS, null));
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for processing SISIS dialect of MARC.
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.dialects.sisis;
|
120
src/main/java/org/xbib/marc/io/BaseChunkStream.java
Normal file
120
src/main/java/org/xbib/marc/io/BaseChunkStream.java
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Spliterator;
|
||||||
|
import java.util.Spliterators;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base class for streams that work with chunks. The chunks are delimited by
|
||||||
|
* information separator characters or by patterns (CR/LF for example).
|
||||||
|
*/
|
||||||
|
abstract class BaseChunkStream extends BufferedInputStream implements ChunkStream<byte[], BytesReference> {
|
||||||
|
|
||||||
|
private static final int DEFAULT_BUFFER_SIZE = 8192;
|
||||||
|
|
||||||
|
protected final BytesStreamOutput ref;
|
||||||
|
|
||||||
|
protected byte[] buffer;
|
||||||
|
|
||||||
|
protected int begin;
|
||||||
|
|
||||||
|
protected int end;
|
||||||
|
|
||||||
|
int buffersize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a base chunk stream.
|
||||||
|
* @param in the underlying input stream
|
||||||
|
*/
|
||||||
|
BaseChunkStream(InputStream in) {
|
||||||
|
this(in, DEFAULT_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a base chunk stream.
|
||||||
|
* @param in the underlying input stream
|
||||||
|
* @param buffersize the buffer size, default is 8192
|
||||||
|
*/
|
||||||
|
BaseChunkStream(InputStream in, int buffersize) {
|
||||||
|
super(in, buffersize);
|
||||||
|
this.buffersize = buffersize;
|
||||||
|
this.buffer = new byte[buffersize];
|
||||||
|
this.begin = 0;
|
||||||
|
this.end = -1;
|
||||||
|
this.ref = new BytesStreamOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This methods creates a Java 8 stream of chunks.
|
||||||
|
* @return a stream of chunks
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Stream<Chunk<byte[], BytesReference>> chunks() {
|
||||||
|
Iterator<Chunk<byte[], BytesReference>> iterator = new Iterator<Chunk<byte[], BytesReference>>() {
|
||||||
|
Chunk<byte[], BytesReference> nextData = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
if (nextData != null) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
nextData = readChunk();
|
||||||
|
return nextData != null;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Chunk<byte[], BytesReference> next() {
|
||||||
|
if (nextData != null || hasNext()) {
|
||||||
|
Chunk<byte[], BytesReference> data = nextData;
|
||||||
|
nextData = null;
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator,
|
||||||
|
Spliterator.ORDERED | Spliterator.NONNULL), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fillBuf() throws IOException {
|
||||||
|
return fillBuf(buffersize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int fillBuf(int n) throws IOException {
|
||||||
|
if (end - begin <= 0) {
|
||||||
|
begin = 0;
|
||||||
|
return super.read(buffer, begin, n);
|
||||||
|
} else {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
154
src/main/java/org/xbib/marc/io/BufferedSeparatorInputStream.java
Normal file
154
src/main/java/org/xbib/marc/io/BufferedSeparatorInputStream.java
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A buffered input stream for iterating over structured data streams with information
|
||||||
|
* separators.
|
||||||
|
*
|
||||||
|
* The information separators of the C0 control group are defined in:
|
||||||
|
* - ANSI X3.4-1967 (ASCII)
|
||||||
|
* - IETF RFC 20 (Vint Cerf, 1969)
|
||||||
|
* - ISO-646:1972
|
||||||
|
* - ECMA-6 3rd revision August 1973
|
||||||
|
* - ECMA-48
|
||||||
|
* - ISO/IEC 6429
|
||||||
|
* - CCITT International Telegraph Alphabet Number 5 (ITA-5)
|
||||||
|
*
|
||||||
|
* From ASCII-1967:
|
||||||
|
* "Can be used as delimiters to mark fields of data structures.
|
||||||
|
* If used for hierarchical levels, US is the lowest level (dividing
|
||||||
|
* plain-text data items), while RS, GS, and FS are of increasing level
|
||||||
|
* to divide groups made up of items of the level beneath it."
|
||||||
|
*
|
||||||
|
* Form IETF RFC 20:
|
||||||
|
* "Information Separator: A character which is used to separate
|
||||||
|
* and qualify information in a logical sense. There is a group of four
|
||||||
|
* such characters, which are to be used in a hierarchical order."
|
||||||
|
*
|
||||||
|
* From ECMA-48 (ISO/IEC 6429):
|
||||||
|
*
|
||||||
|
* "Each information separator is given two names. The names,
|
||||||
|
* INFORMATION SEPARATOR FOUR (IS4), INFORMATION SEPARATOR THREE (IS3),
|
||||||
|
* INFORMATION SEPARATOR TWO (IS2), and INFORMATION SEPARATOR ONE (IS1)
|
||||||
|
* are the general names. The names FILE SEPARATOR (FS), GROUP SEPARATOR (GS),
|
||||||
|
* RECORD SEPARATOR (RS), and UNIT SEPARATOR (US) are the specific names and
|
||||||
|
* are intended mainly for applications where the information separators are
|
||||||
|
* used hierarchically. The ascending order is then US, RS, GS, FS.
|
||||||
|
* In this case, data normally delimited by a particular separator cannot
|
||||||
|
* be split by a higher-order separator but will be considered as delimited by
|
||||||
|
* any other higher-order separator.
|
||||||
|
* In ISO/IEC 10538, IS3 and IS4 are given the names PAGE TERMINATOR (PT)
|
||||||
|
* and DOCUMENT TERMINATOR (DT), respectively and may be used to reset
|
||||||
|
* presentation attributes to the default state."
|
||||||
|
*/
|
||||||
|
public class BufferedSeparatorInputStream extends BaseChunkStream {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trick: first separator emitted will be a file separator.
|
||||||
|
*/
|
||||||
|
private char separator = InformationSeparator.FS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a buffered information separator stream.
|
||||||
|
* @param in the underlying input stream
|
||||||
|
*/
|
||||||
|
public BufferedSeparatorInputStream(InputStream in) {
|
||||||
|
super(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Chunk<byte[], BytesReference> readChunk() throws IOException {
|
||||||
|
while (true) {
|
||||||
|
end = fillBuf();
|
||||||
|
if (end == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Coordinate c = indexOf(buffer, begin, end);
|
||||||
|
if (c.pos != -1) {
|
||||||
|
ref.write(buffer, begin, c.pos - begin);
|
||||||
|
final char chunkSeparator = separator;
|
||||||
|
final BytesReference chunkData = ref.bytes();
|
||||||
|
Chunk<byte[], BytesReference> chunk = new Chunk<byte[], BytesReference>() {
|
||||||
|
@Override
|
||||||
|
public byte[] separator() {
|
||||||
|
return new byte[]{ (byte) chunkSeparator };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesReference data() {
|
||||||
|
return chunkData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Integer.toHexString(chunkSeparator)
|
||||||
|
+ ": " + Arrays.toString(chunkData.toBytes())
|
||||||
|
+ ": " + chunkData.toUtf8();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
processChunk(chunk);
|
||||||
|
ref.reset();
|
||||||
|
separator = c.sep;
|
||||||
|
begin = c.pos + 1;
|
||||||
|
return chunk;
|
||||||
|
} else {
|
||||||
|
ref.write(buffer, begin, buffersize - begin);
|
||||||
|
begin = buffersize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method can be overriden by classes to extend the processing of a chunk
|
||||||
|
* before it is returned to the caller.
|
||||||
|
* @param chunk the chunk to be processed.
|
||||||
|
* @throws IOException if chunk processing fails
|
||||||
|
*/
|
||||||
|
protected void processChunk(Chunk<byte[], BytesReference> chunk) throws IOException {
|
||||||
|
// intentionally left blank
|
||||||
|
}
|
||||||
|
|
||||||
|
private Coordinate indexOf(byte[] b, int start, int end) {
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
if (b[i] == InformationSeparator.US) {
|
||||||
|
return new Coordinate(i, InformationSeparator.US);
|
||||||
|
} else if (b[i] == InformationSeparator.RS) {
|
||||||
|
return new Coordinate(i, InformationSeparator.RS);
|
||||||
|
} else if (b[i] == InformationSeparator.GS) {
|
||||||
|
return new Coordinate(i, InformationSeparator.GS);
|
||||||
|
} else if (b[i] == InformationSeparator.FS) {
|
||||||
|
return new Coordinate(i, InformationSeparator.FS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Coordinate(-1, '\u0000');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Coordinate {
|
||||||
|
int pos;
|
||||||
|
char sep;
|
||||||
|
|
||||||
|
Coordinate(int pos, char sep) {
|
||||||
|
this.pos = pos;
|
||||||
|
this.sep = sep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
129
src/main/java/org/xbib/marc/io/BytesArray.java
Normal file
129
src/main/java/org/xbib/marc/io/BytesArray.java
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A byte array, wrapped in a {@link BytesReference}.
|
||||||
|
*/
|
||||||
|
public class BytesArray implements BytesReference {
|
||||||
|
|
||||||
|
private static final String EMPTY_STRING = "";
|
||||||
|
|
||||||
|
private byte[] bytes;
|
||||||
|
|
||||||
|
private int offset;
|
||||||
|
|
||||||
|
private int length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create {@link BytesArray} from a byte array.
|
||||||
|
* @param bytes the byte array
|
||||||
|
*/
|
||||||
|
public BytesArray(byte[] bytes) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
this.offset = 0;
|
||||||
|
this.length = bytes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create {@link BytesArray} from a part of a byte array.
|
||||||
|
* @param bytes the byte array
|
||||||
|
* @param offset the offset
|
||||||
|
* @param length the length
|
||||||
|
*/
|
||||||
|
public BytesArray(byte[] bytes, int offset, int length) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
this.offset = offset;
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte get(int index) {
|
||||||
|
return bytes[offset + index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int length() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexOf(byte b, int offset, int len) {
|
||||||
|
if (offset < 0 || (offset + length) > this.length) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
for (int i = offset; i < offset + len; i++) {
|
||||||
|
if (bytes[i] == b) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesReference slice(int from, int length) {
|
||||||
|
if (from < 0 || (from + length) > this.length) {
|
||||||
|
throw new IllegalArgumentException("can't slice a buffer with length [" + this.length +
|
||||||
|
"], with slice parameters from [" + from + "], length [" + length + "]");
|
||||||
|
}
|
||||||
|
return new BytesArray(bytes, offset + from, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toBytes() {
|
||||||
|
if (offset == 0 && bytes.length == length) {
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
return Arrays.copyOfRange(bytes, offset, offset + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toUtf8() {
|
||||||
|
if (length == 0) {
|
||||||
|
return EMPTY_STRING;
|
||||||
|
}
|
||||||
|
return new String(bytes, offset, length, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split byte array by a separator byte.
|
||||||
|
* @param sep the separator
|
||||||
|
* @return a list of byte arrays
|
||||||
|
*/
|
||||||
|
public List<byte[]> split(byte sep) {
|
||||||
|
List<byte[]> l = new LinkedList<>();
|
||||||
|
int start = 0;
|
||||||
|
for (int i = 0; i < bytes.length; i++) {
|
||||||
|
if (sep == bytes[i]) {
|
||||||
|
byte[] b = Arrays.copyOfRange(bytes, start, i);
|
||||||
|
if (b.length > 0) {
|
||||||
|
l.add(b);
|
||||||
|
}
|
||||||
|
start = i + 1;
|
||||||
|
i = start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l.add(Arrays.copyOfRange(bytes, start, bytes.length));
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
}
|
70
src/main/java/org/xbib/marc/io/BytesReference.java
Normal file
70
src/main/java/org/xbib/marc/io/BytesReference.java
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to bytes.
|
||||||
|
*/
|
||||||
|
public interface BytesReference {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the byte at the specified index. Need to be between 0 and length.
|
||||||
|
*
|
||||||
|
* @param index index
|
||||||
|
* @return byte at specified index
|
||||||
|
*/
|
||||||
|
byte get(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length.
|
||||||
|
*
|
||||||
|
* @return length
|
||||||
|
*/
|
||||||
|
int length();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the index of a given byte, in the given area.
|
||||||
|
* @param b the byte
|
||||||
|
* @param offset offset
|
||||||
|
* @param len len
|
||||||
|
* @return -1 if not found, otherwise the position, counting from offset
|
||||||
|
*/
|
||||||
|
int indexOf(byte b, int offset, int len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slice the bytes from the <tt>from</tt> index up to <tt>length</tt>.
|
||||||
|
*
|
||||||
|
* @param from from
|
||||||
|
* @param length length
|
||||||
|
* @return bytes reference
|
||||||
|
*/
|
||||||
|
BytesReference slice(int from, int length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the bytes as a single byte array.
|
||||||
|
*
|
||||||
|
* @return bytes
|
||||||
|
*/
|
||||||
|
byte[] toBytes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts to a string based on utf8.
|
||||||
|
*
|
||||||
|
* @return UTF-8 encoded string
|
||||||
|
*/
|
||||||
|
String toUtf8();
|
||||||
|
}
|
220
src/main/java/org/xbib/marc/io/BytesStreamOutput.java
Normal file
220
src/main/java/org/xbib/marc/io/BytesStreamOutput.java
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A growable stream of bytes, with random access methods.
|
||||||
|
*/
|
||||||
|
public class BytesStreamOutput extends OutputStream {
|
||||||
|
|
||||||
|
private static final int DEFAULT_BUFFER_SIZE = 1024;
|
||||||
|
|
||||||
|
private static final boolean JRE_IS_64BIT;
|
||||||
|
|
||||||
|
static {
|
||||||
|
String oaarch = System.getProperty("os.arch");
|
||||||
|
String sunarch = System.getProperty("sun.arch.data.model");
|
||||||
|
JRE_IS_64BIT = sunarch != null ? sunarch.contains("64") :
|
||||||
|
oaarch != null && oaarch.contains("64");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The buffer where data is stored.
|
||||||
|
*/
|
||||||
|
private byte[] buf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of valid bytes in the buffer.
|
||||||
|
*/
|
||||||
|
private int count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@code BytesStreamOutput} with default buffer size.
|
||||||
|
*/
|
||||||
|
public BytesStreamOutput() {
|
||||||
|
this(DEFAULT_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@code BytesStreamOutput} with given buffer size.
|
||||||
|
* @param size size
|
||||||
|
*/
|
||||||
|
public BytesStreamOutput(int size) {
|
||||||
|
this.buf = new byte[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the position in the stream.
|
||||||
|
* @return the position
|
||||||
|
*/
|
||||||
|
public long position() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to new position in stream. Must be in the current buffer.
|
||||||
|
* @param position the new position.
|
||||||
|
*/
|
||||||
|
public void seek(long position) {
|
||||||
|
if (position > Integer.MAX_VALUE) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
count = (int) position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write an integer.
|
||||||
|
*
|
||||||
|
* @param b int
|
||||||
|
* @throws IOException if write fails
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
int newcount = count + 1;
|
||||||
|
if (newcount > buf.length) {
|
||||||
|
buf = Arrays.copyOf(buf, oversize(newcount));
|
||||||
|
}
|
||||||
|
buf[count] = (byte) b;
|
||||||
|
count = newcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write byte array.
|
||||||
|
*
|
||||||
|
* @param b byte array
|
||||||
|
* @param offset offset
|
||||||
|
* @param length length
|
||||||
|
* @throws IOException if write fails
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b, int offset, int length) throws IOException {
|
||||||
|
if (length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int newcount = count + length;
|
||||||
|
if (newcount > buf.length) {
|
||||||
|
buf = Arrays.copyOf(buf, oversize(newcount));
|
||||||
|
}
|
||||||
|
System.arraycopy(b, offset, buf, count, length);
|
||||||
|
count = newcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skip a number of bytes.
|
||||||
|
* @param length the number of bytes to skip.
|
||||||
|
*/
|
||||||
|
public void skip(int length) {
|
||||||
|
int newcount = count + length;
|
||||||
|
if (newcount > buf.length) {
|
||||||
|
buf = Arrays.copyOf(buf, oversize(newcount));
|
||||||
|
}
|
||||||
|
count = newcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seek to absolute position. Must be in buffer.
|
||||||
|
* @param pos the position.
|
||||||
|
*/
|
||||||
|
public void seek(int pos) {
|
||||||
|
count = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() throws IOException {
|
||||||
|
// nothing to do there
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a {@link BytesReference} to the buffer of this output stream.
|
||||||
|
* @return the byets reference
|
||||||
|
*/
|
||||||
|
public BytesReference bytes() {
|
||||||
|
return new BytesArray(buf, 0, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current size of the buffer.
|
||||||
|
*
|
||||||
|
* @return the value of the <code>count</code> field, which is the number
|
||||||
|
* of valid bytes in this output stream.
|
||||||
|
* @see java.io.ByteArrayOutputStream#count
|
||||||
|
*/
|
||||||
|
public int size() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array size >= minTargetSize, generally
|
||||||
|
* over-allocating exponentially to achieve amortized
|
||||||
|
* linear-time cost as the array grows.
|
||||||
|
* NOTE: this was originally borrowed from Python 2.4.2
|
||||||
|
* listobject.c sources (attribution in LICENSE.txt), but
|
||||||
|
* has now been substantially changed based on
|
||||||
|
* discussions from java-dev thread with subject "Dynamic
|
||||||
|
* array reallocation algorithms", started on Jan 12
|
||||||
|
* 2010.
|
||||||
|
*
|
||||||
|
* @param minTargetSize Minimum required value to be returned.
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private static int oversize(int minTargetSize) {
|
||||||
|
if (minTargetSize < 0) {
|
||||||
|
// catch usage that accidentally overflows int
|
||||||
|
throw new IllegalArgumentException("invalid array size " + minTargetSize);
|
||||||
|
}
|
||||||
|
if (minTargetSize == 0) {
|
||||||
|
// wait until at least one element is requested
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// asymptotic exponential growth by 1/8th, favors
|
||||||
|
// spending a bit more CPU to not tie up too much wasted
|
||||||
|
// RAM:
|
||||||
|
int extra = minTargetSize >> 3;
|
||||||
|
if (extra < 3) {
|
||||||
|
// for very small arrays, where constant overhead of
|
||||||
|
// realloc is presumably relatively high, we grow
|
||||||
|
// faster
|
||||||
|
extra = 3;
|
||||||
|
}
|
||||||
|
int newSize = minTargetSize + extra;
|
||||||
|
// add 7 to allow for worst case byte alignment addition below:
|
||||||
|
if (newSize + 7 < 0) {
|
||||||
|
// int overflowed -- return max allowed array size
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
if (JRE_IS_64BIT) {
|
||||||
|
// round up to multiple of 8
|
||||||
|
return (newSize + 7) & 0x7ffffff8;
|
||||||
|
} else {
|
||||||
|
// round up to multiple of 4
|
||||||
|
return (newSize + 3) & 0x7ffffffc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
src/main/java/org/xbib/marc/io/Chunk.java
Normal file
37
src/main/java/org/xbib/marc/io/Chunk.java
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A chunk.
|
||||||
|
* @param <S> the separator type
|
||||||
|
* @param <D> the data type
|
||||||
|
*/
|
||||||
|
public interface Chunk<S, D> {
|
||||||
|
/**
|
||||||
|
* The separator of the chunk.
|
||||||
|
* @return the separator
|
||||||
|
*/
|
||||||
|
S separator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data of the chunk.
|
||||||
|
*
|
||||||
|
* @return the data
|
||||||
|
*/
|
||||||
|
D data();
|
||||||
|
}
|
34
src/main/java/org/xbib/marc/io/ChunkListener.java
Normal file
34
src/main/java/org/xbib/marc/io/ChunkListener.java
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Listener interface for capturing chunks.
|
||||||
|
* @param <S> the separator type
|
||||||
|
* @param <D> the datat type
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ChunkListener<S, D> {
|
||||||
|
/**
|
||||||
|
* A chunk has arrived.
|
||||||
|
* @param chunk the chunk
|
||||||
|
* @throws IOException if chunk processing fails
|
||||||
|
*/
|
||||||
|
void chunk(Chunk<S, D> chunk) throws IOException;
|
||||||
|
}
|
42
src/main/java/org/xbib/marc/io/ChunkStream.java
Normal file
42
src/main/java/org/xbib/marc/io/ChunkStream.java
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A chunk stream.
|
||||||
|
* @param <S> the separator type
|
||||||
|
* @param <D> the data type
|
||||||
|
*/
|
||||||
|
public interface ChunkStream<S, D> extends Closeable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a stream of chunks.
|
||||||
|
* @return a stream of chunks
|
||||||
|
*/
|
||||||
|
Stream<Chunk<S, D>> chunks();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a single chunk from stream.
|
||||||
|
* @return a single chunk.
|
||||||
|
* @throws IOException if chunk read fails
|
||||||
|
*/
|
||||||
|
Chunk<S, D> readChunk() throws IOException;
|
||||||
|
}
|
58
src/main/java/org/xbib/marc/io/DefaultChunk.java
Normal file
58
src/main/java/org/xbib/marc/io/DefaultChunk.java
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A default chunk implementation. The separator is a abyte array,
|
||||||
|
* and the data is a {@link BytesReference}.
|
||||||
|
*/
|
||||||
|
public class DefaultChunk implements Chunk<byte[], BytesReference> {
|
||||||
|
|
||||||
|
private final byte[] separator;
|
||||||
|
|
||||||
|
private final BytesReference bytesReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a default chunk.
|
||||||
|
* @param separator the separator
|
||||||
|
* @param bytesReference the bytes reference for the chunk data
|
||||||
|
*/
|
||||||
|
public DefaultChunk(char separator, BytesReference bytesReference) {
|
||||||
|
this.separator = new byte[]{(byte) separator};
|
||||||
|
this.bytesReference = bytesReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] separator() {
|
||||||
|
return separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesReference data() {
|
||||||
|
return bytesReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Arrays.toString(separator)
|
||||||
|
+ (bytesReference == null ?
|
||||||
|
"" : ": " + Arrays.toString(bytesReference.toBytes()) + ": " + bytesReference.toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import java.io.FilterInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A replacement input stream with a fixed token.
|
||||||
|
*/
|
||||||
|
public class FixedTokenReplacementInputStream extends FilterInputStream {
|
||||||
|
|
||||||
|
private final ScanBuffer tokenBuffer;
|
||||||
|
|
||||||
|
private final StreamTokenHandler handler;
|
||||||
|
|
||||||
|
private InputStream value;
|
||||||
|
|
||||||
|
private StreamReadingStrategy strategy;
|
||||||
|
|
||||||
|
private boolean done = false;
|
||||||
|
|
||||||
|
private final StreamReadingStrategy lookingForToken = new StreamReadingStrategy() {
|
||||||
|
@Override
|
||||||
|
public int internalRead() throws IOException {
|
||||||
|
int stream = superRead();
|
||||||
|
int buffer = tokenBuffer.append(stream);
|
||||||
|
if (tokenBuffer.match()) {
|
||||||
|
tokenBuffer.flush();
|
||||||
|
value = handler.processToken(tokenBuffer.getScanString());
|
||||||
|
strategy = flushingValue;
|
||||||
|
return buffer == -1 && stream != -1 ? read() : buffer;
|
||||||
|
}
|
||||||
|
return buffer == -1 && tokenBuffer.hasData() ? internalRead() : buffer;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private final StreamReadingStrategy flushingValue = new StreamReadingStrategy() {
|
||||||
|
@Override
|
||||||
|
public int internalRead() throws IOException {
|
||||||
|
int i = value.read();
|
||||||
|
if (i == -1) {
|
||||||
|
strategy = lookingForToken;
|
||||||
|
i = read();
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a case-sensitive replacement input stream with fixed token.
|
||||||
|
* @param in the underlying input stream
|
||||||
|
* @param token the token
|
||||||
|
* @param handler the stream token handler
|
||||||
|
*/
|
||||||
|
public FixedTokenReplacementInputStream(InputStream in, String token, StreamTokenHandler handler) {
|
||||||
|
this(in, token, handler, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a replacement input stream with fixed token.
|
||||||
|
* @param in the underlying input stream
|
||||||
|
* @param token the token
|
||||||
|
* @param handler the stream token handler
|
||||||
|
* @param caseSensitive true if case sensitive, false if not
|
||||||
|
*/
|
||||||
|
public FixedTokenReplacementInputStream(InputStream in, String token, StreamTokenHandler handler,
|
||||||
|
boolean caseSensitive) {
|
||||||
|
super(in);
|
||||||
|
tokenBuffer = new ScanBuffer(token, caseSensitive);
|
||||||
|
this.handler = handler;
|
||||||
|
strategy = lookingForToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
return strategy.internalRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int superRead() throws IOException {
|
||||||
|
return super.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] bytes, int off, int len) throws IOException {
|
||||||
|
int count = 0;
|
||||||
|
if (done) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (int i = off, max = off + len; i < max; i++) {
|
||||||
|
final int read = read();
|
||||||
|
if (read == -1) {
|
||||||
|
done = true;
|
||||||
|
return count == 0 ? -1 : count;
|
||||||
|
}
|
||||||
|
bytes[i] = (byte) read;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] b) throws IOException {
|
||||||
|
return read(b, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for reading strategy.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
interface StreamReadingStrategy {
|
||||||
|
/**
|
||||||
|
* Read next byte.
|
||||||
|
* @return next byte
|
||||||
|
* @throws IOException if read fails
|
||||||
|
*/
|
||||||
|
int internalRead() throws IOException;
|
||||||
|
}
|
||||||
|
}
|
48
src/main/java/org/xbib/marc/io/InformationSeparator.java
Normal file
48
src/main/java/org/xbib/marc/io/InformationSeparator.java
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for Information separators for formatted data.
|
||||||
|
* Also known as control characters group 0 ("C0"), ASCII-1967
|
||||||
|
* defines units, records, groups and files as separable hierarchically
|
||||||
|
* organized data structures. The structures are separated not by protocol,
|
||||||
|
* but by embedded separator codes.
|
||||||
|
* Originally, these codes were used to simulate punch card data on magnetic
|
||||||
|
* tape. Trailing blanks on tape could be saved by using separator characters
|
||||||
|
* instead.
|
||||||
|
*/
|
||||||
|
public interface InformationSeparator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FILE SEPARATOR.
|
||||||
|
*/
|
||||||
|
char FS = '\u001c';
|
||||||
|
/**
|
||||||
|
* RECORD TERMINATOR / GROUP SEPARATOR / Satzende (SE).
|
||||||
|
*/
|
||||||
|
char GS = '\u001d';
|
||||||
|
/**
|
||||||
|
* FIELD TERMINATOR / RECORD SEPARATOR / Feldende (FE).
|
||||||
|
*/
|
||||||
|
char RS = '\u001e';
|
||||||
|
/**
|
||||||
|
* SUBFIELD DELIMITER / UNIT SEPARATOR / Unterfeld (UF).
|
||||||
|
*/
|
||||||
|
char US = '\u001f';
|
||||||
|
|
||||||
|
}
|
164
src/main/java/org/xbib/marc/io/PatternInputStream.java
Normal file
164
src/main/java/org/xbib/marc/io/PatternInputStream.java
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A buffered input stream that is organized in chunks separated by byte array patterns.
|
||||||
|
* Convenience implements are give by {@code PatternInputStream.lf()} for line-feed separated
|
||||||
|
* streams, and {@code PatternInputStream.CRLF} for carriage-rturn/line-feed separated streams.
|
||||||
|
*/
|
||||||
|
public class PatternInputStream extends BaseChunkStream {
|
||||||
|
|
||||||
|
private static final byte[] LF = {'\n'};
|
||||||
|
|
||||||
|
private static final byte[] CRLF = {'\r', '\n'};
|
||||||
|
|
||||||
|
private final byte[] pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a pattern delimited input stream.
|
||||||
|
* @param in the underlying input stream
|
||||||
|
* @param pattern the pattern
|
||||||
|
*/
|
||||||
|
public PatternInputStream(InputStream in, byte[] pattern) {
|
||||||
|
super(in);
|
||||||
|
requireNonNull(pattern);
|
||||||
|
this.pattern = pattern.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to cerate a line-feed pattern separated input stream.
|
||||||
|
* @param in the input stream to wrap
|
||||||
|
* @return the pattern input stream
|
||||||
|
*/
|
||||||
|
public static PatternInputStream lf(InputStream in) {
|
||||||
|
return new PatternInputStream(in, LF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to cerate a carriage-return/line-feed pattern separated input stream.
|
||||||
|
* @param in the input stream to wrap
|
||||||
|
* @return the pattern input stream
|
||||||
|
*/
|
||||||
|
public static PatternInputStream crlf(InputStream in) {
|
||||||
|
return new PatternInputStream(in, CRLF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read next chunk from this stream.
|
||||||
|
* @return a chunk
|
||||||
|
* @throws IOException if chunk can not be read
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Chunk<byte[], BytesReference> readChunk() throws IOException {
|
||||||
|
Chunk<byte[], BytesReference> chunk = internalReadChunk();
|
||||||
|
if (chunk != null) {
|
||||||
|
processChunk(chunk);
|
||||||
|
}
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method can be overriden by classes to extend the processing of a chunk
|
||||||
|
* before it is returned to the caller.
|
||||||
|
* @param chunk the chunk to be processed.
|
||||||
|
* @throws IOException if chunk processing fails
|
||||||
|
*/
|
||||||
|
protected void processChunk(Chunk<byte[], BytesReference> chunk) throws IOException {
|
||||||
|
// intentionally left blank
|
||||||
|
}
|
||||||
|
|
||||||
|
private Chunk<byte[], BytesReference> internalReadChunk() throws IOException {
|
||||||
|
int matches = 0;
|
||||||
|
while (true) {
|
||||||
|
end = fillBuf();
|
||||||
|
if (end == -1) {
|
||||||
|
if (ref.size() > 0) {
|
||||||
|
// return last read chunk
|
||||||
|
final BytesReference bytesReference = ref.bytes();
|
||||||
|
ref.reset();
|
||||||
|
return new Chunk<byte[], BytesReference>() {
|
||||||
|
@Override
|
||||||
|
public byte[] separator() {
|
||||||
|
return pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesReference data() {
|
||||||
|
return bytesReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Arrays.toString(separator())
|
||||||
|
+ ": " + Arrays.toString(bytesReference.toBytes())
|
||||||
|
+ ": " + bytesReference.toUtf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = begin; i < end; i++) {
|
||||||
|
if (buffer[i] == pattern[matches]) {
|
||||||
|
matches++;
|
||||||
|
} else {
|
||||||
|
matches = 0;
|
||||||
|
}
|
||||||
|
if (matches == pattern.length) {
|
||||||
|
int len = i - begin - pattern.length + 1;
|
||||||
|
if (len < 0) {
|
||||||
|
ref.skip(len);
|
||||||
|
} else {
|
||||||
|
ref.write(buffer, begin, len);
|
||||||
|
}
|
||||||
|
final BytesReference bytesReference = ref.bytes();
|
||||||
|
Chunk<byte[], BytesReference> chunk = new Chunk<byte[], BytesReference>() {
|
||||||
|
@Override
|
||||||
|
public byte[] separator() {
|
||||||
|
return pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesReference data() {
|
||||||
|
return bytesReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Arrays.toString(separator())
|
||||||
|
+ ": " + Arrays.toString(bytesReference.toBytes())
|
||||||
|
+ ": " + bytesReference.toUtf8();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ref.reset();
|
||||||
|
begin = i + 1;
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ref.write(buffer, begin, end - begin);
|
||||||
|
begin = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
src/main/java/org/xbib/marc/io/ReplaceStringInputStream.java
Normal file
58
src/main/java/org/xbib/marc/io/ReplaceStringInputStream.java
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string replacing input stream.
|
||||||
|
*/
|
||||||
|
public class ReplaceStringInputStream extends FixedTokenReplacementInputStream {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create string replacing input stream.
|
||||||
|
* @param in the underlying input stream
|
||||||
|
* @param token the token
|
||||||
|
* @param fixedValue the fixed value
|
||||||
|
*/
|
||||||
|
public ReplaceStringInputStream(InputStream in, String token, String fixedValue) {
|
||||||
|
super(in, token, new FixedStringValueTokenHandler(fixedValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stream token handler for this replacement input stream.
|
||||||
|
*/
|
||||||
|
private static class FixedStringValueTokenHandler implements StreamTokenHandler {
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create stream token handler.
|
||||||
|
* @param value value
|
||||||
|
*/
|
||||||
|
FixedStringValueTokenHandler(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream processToken(String token) {
|
||||||
|
return new ByteArrayInputStream(value.getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
201
src/main/java/org/xbib/marc/io/ScanBuffer.java
Normal file
201
src/main/java/org/xbib/marc/io/ScanBuffer.java
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan buffer.
|
||||||
|
*/
|
||||||
|
public class ScanBuffer {
|
||||||
|
|
||||||
|
private boolean cs;
|
||||||
|
|
||||||
|
private char[] buffer = new char[0];
|
||||||
|
|
||||||
|
private int[] buffer2 = new int[0];
|
||||||
|
|
||||||
|
private char[] token = new char[0];
|
||||||
|
|
||||||
|
private int pos;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create scan buffer.
|
||||||
|
* @param size the size
|
||||||
|
*/
|
||||||
|
public ScanBuffer(int size) {
|
||||||
|
buffer = new char[size];
|
||||||
|
buffer2 = new int[size];
|
||||||
|
token = new char[size];
|
||||||
|
flush();
|
||||||
|
cs = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create scan buffer.
|
||||||
|
* @param scanString the scan string
|
||||||
|
* @param caseSensitive true if case sensitive, false if not
|
||||||
|
*/
|
||||||
|
public ScanBuffer(String scanString, boolean caseSensitive) {
|
||||||
|
this(scanString.length());
|
||||||
|
setScanString(scanString, caseSensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return scan buffer size.
|
||||||
|
* @return scan buffer size
|
||||||
|
*/
|
||||||
|
public int size() {
|
||||||
|
return buffer.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset scan buffer position.
|
||||||
|
*/
|
||||||
|
public void resetPosition() {
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get scan string.
|
||||||
|
* @return scan string
|
||||||
|
*/
|
||||||
|
public String getScanString() {
|
||||||
|
return new String(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScanString(String stringToken, boolean caseSensitive) {
|
||||||
|
cs = caseSensitive;
|
||||||
|
token = new char[stringToken.length()];
|
||||||
|
stringToken.getChars(0, token.length, token, 0);
|
||||||
|
if (token.length > buffer.length) {
|
||||||
|
buffer = new char[token.length * 4];
|
||||||
|
buffer2 = new int[token.length * 4];
|
||||||
|
}
|
||||||
|
pos = 0;
|
||||||
|
if (!cs) {
|
||||||
|
for (int i = 0; i < token.length; i++) {
|
||||||
|
token[i] = Character.toLowerCase(token[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append byte.
|
||||||
|
* @param newByte the byte
|
||||||
|
* @return old byte
|
||||||
|
*/
|
||||||
|
public int append(int newByte) {
|
||||||
|
int old = buffer2[pos];
|
||||||
|
buffer2[pos] = newByte;
|
||||||
|
buffer[pos] = cs ? (char) newByte : Character.toLowerCase((char) newByte);
|
||||||
|
pos = (++pos < buffer.length) ? pos : 0;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
char ch = (char) -1;
|
||||||
|
for (int i = 0; i < buffer.length; i++) {
|
||||||
|
buffer[i] = ch;
|
||||||
|
buffer2[i] = -1;
|
||||||
|
}
|
||||||
|
resetPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean match() {
|
||||||
|
int apos = token.length - 1;
|
||||||
|
int rpos = pos - 1;
|
||||||
|
|
||||||
|
for (; rpos > -1 && apos > -1; rpos--, apos--) {
|
||||||
|
if (buffer[rpos] != token[apos]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (rpos = buffer.length - 1; apos > -1; rpos--, apos--) {
|
||||||
|
if (buffer[rpos] != token[apos]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has scan buffer any data?
|
||||||
|
* @return true if it has data
|
||||||
|
*/
|
||||||
|
public boolean hasData() {
|
||||||
|
int apos = token.length - 1;
|
||||||
|
int rpos = pos - 1;
|
||||||
|
for (; rpos > -1 && apos > -1; rpos--, apos--) {
|
||||||
|
if (buffer2[rpos] != -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (rpos = buffer2.length - 1; apos > -1; rpos--, apos--) {
|
||||||
|
if (buffer2[rpos] != -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear scan buffer at position.
|
||||||
|
* @param i the position
|
||||||
|
*/
|
||||||
|
public void clear(int i) {
|
||||||
|
char ch = (char) -1;
|
||||||
|
int apos = i - 1;
|
||||||
|
int rpos = pos - 1;
|
||||||
|
for (; rpos > -1 && apos > -1; rpos--, apos--) {
|
||||||
|
buffer[rpos] = ch;
|
||||||
|
buffer2[rpos] = -1;
|
||||||
|
}
|
||||||
|
for (rpos = buffer.length - 1; apos > -1; rpos--, apos--) {
|
||||||
|
buffer[rpos] = ch;
|
||||||
|
buffer2[rpos] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBuffer() {
|
||||||
|
byte[] out = new byte[getSize()];
|
||||||
|
for (int i = 0; i < out.length; i++) {
|
||||||
|
out[i] = (byte) getByte(buffer.length - out.length + i);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSize() {
|
||||||
|
int size = 0;
|
||||||
|
for (int i = buffer.length - 1; i >= 0; i--) {
|
||||||
|
int b = getByte(i);
|
||||||
|
if (b != -1) {
|
||||||
|
size++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getByte(int absolutePosition) {
|
||||||
|
if (absolutePosition >= buffer.length) {
|
||||||
|
throw new IndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
int realPosition = (pos + absolutePosition) % buffer.length;
|
||||||
|
return buffer2[realPosition];
|
||||||
|
}
|
||||||
|
}
|
76
src/main/java/org/xbib/marc/io/SeparatorInputStream.java
Normal file
76
src/main/java/org/xbib/marc/io/SeparatorInputStream.java
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import java.io.FilterInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An unbuffered separator stream. This is a very slow implementation.
|
||||||
|
* Use this only if {@link BufferedSeparatorInputStream} is not possible.
|
||||||
|
*/
|
||||||
|
public class SeparatorInputStream extends FilterInputStream {
|
||||||
|
|
||||||
|
private BytesStreamOutput ref;
|
||||||
|
|
||||||
|
private char separator = InformationSeparator.FS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create separator stream.
|
||||||
|
* @param in the underlying input stream
|
||||||
|
*/
|
||||||
|
public SeparatorInputStream(InputStream in) {
|
||||||
|
super(in);
|
||||||
|
this.ref = new BytesStreamOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read next chunk. This is slow, it uses the {@code read()} method.
|
||||||
|
* @return the next chunk
|
||||||
|
* @throws IOException if chunk reading fails
|
||||||
|
*/
|
||||||
|
public Chunk<byte[], BytesReference> readChunk() throws IOException {
|
||||||
|
while (true) {
|
||||||
|
int ch = super.read();
|
||||||
|
if (ch == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (ch == InformationSeparator.US || ch == InformationSeparator.RS ||
|
||||||
|
ch == InformationSeparator.GS || ch == InformationSeparator.FS) {
|
||||||
|
final BytesReference bytesReference = ref.bytes();
|
||||||
|
Chunk<byte[], BytesReference> chunk = new Chunk<byte[], BytesReference>() {
|
||||||
|
@Override
|
||||||
|
public byte[] separator() {
|
||||||
|
return new byte[]{(byte) separator };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesReference data() {
|
||||||
|
return bytesReference;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
separator = (char) ch;
|
||||||
|
ref.reset();
|
||||||
|
return chunk;
|
||||||
|
} else {
|
||||||
|
ref.write(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
45
src/main/java/org/xbib/marc/io/SeparatorOutputStream.java
Normal file
45
src/main/java/org/xbib/marc/io/SeparatorOutputStream.java
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A buffered output stream with separators, using the @{link ChunkSink} interface.
|
||||||
|
*/
|
||||||
|
public class SeparatorOutputStream extends BufferedOutputStream implements ChunkListener<byte[], BytesReference> {
|
||||||
|
|
||||||
|
public SeparatorOutputStream(OutputStream out) {
|
||||||
|
super(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SeparatorOutputStream(OutputStream out, int buffersize) {
|
||||||
|
super(out, buffersize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void chunk(Chunk<byte[], BytesReference> chunk) throws IOException {
|
||||||
|
Objects.requireNonNull(chunk);
|
||||||
|
super.write(chunk.separator());
|
||||||
|
if (chunk.data() != null) {
|
||||||
|
super.write(chunk.data().toBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
src/main/java/org/xbib/marc/io/StreamTokenHandler.java
Normal file
34
src/main/java/org/xbib/marc/io/StreamTokenHandler.java
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for stream token handlers.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
interface StreamTokenHandler {
|
||||||
|
/**
|
||||||
|
* Process token.
|
||||||
|
* @param token the token
|
||||||
|
* @return input stream
|
||||||
|
* @throws IOException if processing fails
|
||||||
|
*/
|
||||||
|
InputStream processToken(String token) throws IOException;
|
||||||
|
}
|
4
src/main/java/org/xbib/marc/io/package-info.java
Normal file
4
src/main/java/org/xbib/marc/io/package-info.java
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for generic input/output.
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.io;
|
313
src/main/java/org/xbib/marc/json/MarcJsonWriter.java
Normal file
313
src/main/java/org/xbib/marc/json/MarcJsonWriter.java
Normal file
|
@ -0,0 +1,313 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.json;
|
||||||
|
|
||||||
|
import org.xbib.marc.MarcField;
|
||||||
|
import org.xbib.marc.MarcListener;
|
||||||
|
import org.xbib.marc.MarcRecord;
|
||||||
|
import org.xbib.marc.xml.MarcContentHandler;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.Flushable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This Marc Writer is a MarcContentHandler that writes Marc events to JSON.
|
||||||
|
*/
|
||||||
|
public class MarcJsonWriter extends MarcContentHandler implements Flushable, Closeable {
|
||||||
|
|
||||||
|
public static final String LEADER_TAG = "_LEADER";
|
||||||
|
|
||||||
|
public static final String FORMAT_TAG = "_FORMAT";
|
||||||
|
|
||||||
|
public static final String TYPE_TAG = "_TYPE";
|
||||||
|
|
||||||
|
private static final String JSON_1 = "\":\"";
|
||||||
|
|
||||||
|
private final Lock lock = new ReentrantLock();
|
||||||
|
|
||||||
|
private final BufferedWriter writer;
|
||||||
|
|
||||||
|
private final StringBuilder sb;
|
||||||
|
|
||||||
|
private boolean fatalErrors = false;
|
||||||
|
|
||||||
|
private boolean jsonlines;
|
||||||
|
|
||||||
|
private int fieldCount;
|
||||||
|
|
||||||
|
private Exception exception;
|
||||||
|
|
||||||
|
public MarcJsonWriter(OutputStream out) throws IOException {
|
||||||
|
this(out, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcJsonWriter(OutputStream out, boolean jsonlines) throws IOException {
|
||||||
|
this(new OutputStreamWriter(out, StandardCharsets.UTF_8), jsonlines);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcJsonWriter(Writer writer) throws IOException {
|
||||||
|
this(writer, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcJsonWriter(Writer writer, boolean jsonlines) throws IOException {
|
||||||
|
this.writer = new BufferedWriter(writer);
|
||||||
|
this.sb = new StringBuilder();
|
||||||
|
this.fieldCount = 0;
|
||||||
|
this.jsonlines = jsonlines;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarcJsonWriter setFatalErrors(boolean fatalErrors) {
|
||||||
|
this.fatalErrors = fatalErrors;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MarcJsonWriter setMarcListener(MarcListener listener) {
|
||||||
|
super.setMarcListener(listener);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MarcJsonWriter setFormat(String format) {
|
||||||
|
super.setFormat(format);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MarcJsonWriter setType(String type) {
|
||||||
|
super.setType(type);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startDocument() {
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beginCollection() {
|
||||||
|
if (jsonlines) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sb.append("[");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beginRecord(String format, String type) {
|
||||||
|
super.beginRecord(format, type);
|
||||||
|
if (recordCounter.get() > 0) {
|
||||||
|
sb.append(jsonlines ? "\n" : ",");
|
||||||
|
}
|
||||||
|
sb.append("{");
|
||||||
|
String s = format != null ? format : this.format;
|
||||||
|
sb.append("\"").append(FORMAT_TAG).append("\":\"").append(escape(s)).append("\"");
|
||||||
|
fieldCount++;
|
||||||
|
s = type != null ? type : this.type;
|
||||||
|
if (fieldCount > 0) {
|
||||||
|
sb.append(",");
|
||||||
|
}
|
||||||
|
sb.append("\"").append(TYPE_TAG).append("\":\"").append(escape(s)).append("\"");
|
||||||
|
fieldCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void leader(String label) {
|
||||||
|
super.leader(label);
|
||||||
|
if (fieldCount > 0) {
|
||||||
|
sb.append(",");
|
||||||
|
}
|
||||||
|
sb.append("\"").append(LEADER_TAG).append("\":\"").append(label).append("\"");
|
||||||
|
fieldCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void field(MarcField field) {
|
||||||
|
super.field(field);
|
||||||
|
fieldCount = toJson(field, fieldCount, sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void record(MarcRecord marcRecord) {
|
||||||
|
if (exception != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// do not call super method in MarcContentHandler, it branches to the field methods and this
|
||||||
|
// would confuse us. Plus, we have our own locking here on record level.
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
toJson(marcRecord, sb);
|
||||||
|
writer.write(sb.toString());
|
||||||
|
sb.setLength(0);
|
||||||
|
recordCounter.incrementAndGet();
|
||||||
|
} catch (IOException e) {
|
||||||
|
handleException(e);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endRecord() {
|
||||||
|
super.endRecord();
|
||||||
|
try {
|
||||||
|
sb.append("}");
|
||||||
|
writer.write(sb.toString());
|
||||||
|
sb.setLength(0);
|
||||||
|
recordCounter.incrementAndGet();
|
||||||
|
} catch (IOException e) {
|
||||||
|
handleException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endCollection() {
|
||||||
|
if (jsonlines) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sb.append("]");
|
||||||
|
try {
|
||||||
|
writer.write(sb.toString());
|
||||||
|
} catch (IOException e) {
|
||||||
|
handleException(e);
|
||||||
|
}
|
||||||
|
sb.setLength(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endDocument() {
|
||||||
|
try {
|
||||||
|
writer.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
handleException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format MARC record as key-oriented JSON.
|
||||||
|
* @param sb a string builder to append JSON to
|
||||||
|
*/
|
||||||
|
private void toJson(MarcRecord marcRecord, StringBuilder sb) {
|
||||||
|
if (recordCounter.get() > 0) {
|
||||||
|
sb.append(jsonlines ? "\n" : ",");
|
||||||
|
}
|
||||||
|
sb.append("{");
|
||||||
|
int recordFieldCount = 0;
|
||||||
|
if (format != null) {
|
||||||
|
sb.append("\"_FORMAT\":\"").append(escape(format)).append("\"");
|
||||||
|
recordFieldCount++;
|
||||||
|
}
|
||||||
|
if (type != null) {
|
||||||
|
if (recordFieldCount > 0) {
|
||||||
|
sb.append(",");
|
||||||
|
}
|
||||||
|
sb.append("\"_TYPE\":\"").append(escape(type)).append("\"");
|
||||||
|
recordFieldCount++;
|
||||||
|
}
|
||||||
|
if (recordFieldCount > 0) {
|
||||||
|
sb.append(",");
|
||||||
|
}
|
||||||
|
sb.append("\"_LEADER\":\"").append(marcRecord.getRecordLabel()).append("\"");
|
||||||
|
recordFieldCount++;
|
||||||
|
for (MarcField field : marcRecord.getFields()) {
|
||||||
|
recordFieldCount = toJson(field, recordFieldCount, sb);
|
||||||
|
}
|
||||||
|
sb.append('}');
|
||||||
|
if (jsonlines) {
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a key-oriented JSON represenation of this MARC field.
|
||||||
|
*
|
||||||
|
* @param fieldCount how many MARC field are writte before. Used for emitting a comma
|
||||||
|
* if necessary.
|
||||||
|
* @param sb the string builder to attach the JSON representation to.
|
||||||
|
*
|
||||||
|
* @return the new MARC field count. Empty MARC fields not not increase the field count.
|
||||||
|
*/
|
||||||
|
private int toJson(MarcField marcField, int fieldCount, StringBuilder sb) {
|
||||||
|
int count = fieldCount;
|
||||||
|
if (marcField.isControl()) {
|
||||||
|
if (count > 0) {
|
||||||
|
sb.append(",");
|
||||||
|
}
|
||||||
|
sb.append("\"").append(marcField.getTag()).append(JSON_1).append(escape(marcField.getValue())).append("\"");
|
||||||
|
count++;
|
||||||
|
return count;
|
||||||
|
} else if (!marcField.isEmpty()) {
|
||||||
|
if (count > 0) {
|
||||||
|
sb.append(",");
|
||||||
|
}
|
||||||
|
sb.append("\"").append(marcField.getTag()).append("\":{\"")
|
||||||
|
.append(marcField.getIndicator().replace(' ', '_')).append("\":");
|
||||||
|
if (marcField.getSubfields().size() == 1) {
|
||||||
|
MarcField.Subfield subfield = marcField.getSubfields().get(0);
|
||||||
|
sb.append("{\"").append(subfield.getId()).append(JSON_1).append(escape(subfield.getValue())).append("\"}");
|
||||||
|
} else {
|
||||||
|
sb.append("[");
|
||||||
|
StringBuilder subfieldBuilder = new StringBuilder();
|
||||||
|
for (MarcField.Subfield subfield : marcField.getSubfields()) {
|
||||||
|
if (subfieldBuilder.length() > 0) {
|
||||||
|
subfieldBuilder.append(",");
|
||||||
|
}
|
||||||
|
subfieldBuilder.append("{\"").append(subfield.getId()).append(JSON_1)
|
||||||
|
.append(escape(subfield.getValue())).append("\"}");
|
||||||
|
}
|
||||||
|
sb.append(subfieldBuilder);
|
||||||
|
sb.append("]");
|
||||||
|
}
|
||||||
|
sb.append("}");
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Exception getException() {
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String escape(String value) {
|
||||||
|
return value != null ? value.replaceAll("\"", "\\\"") : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleException(IOException e) {
|
||||||
|
exception = e;
|
||||||
|
if (fatalErrors) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() throws IOException {
|
||||||
|
writer.flush();
|
||||||
|
}
|
||||||
|
}
|
4
src/main/java/org/xbib/marc/json/package-info.java
Normal file
4
src/main/java/org/xbib/marc/json/package-info.java
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for creating JSON from MARC.
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.json;
|
113
src/main/java/org/xbib/marc/label/BibliographicLevel.java
Normal file
113
src/main/java/org/xbib/marc/label/BibliographicLevel.java
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bibliographic level
|
||||||
|
*
|
||||||
|
* One-character alphabetic code indicating the bibliographic level of the record.
|
||||||
|
*
|
||||||
|
* a - Monographic component part
|
||||||
|
* Monographic bibliographic unit that is physically attached to or contained in another unit
|
||||||
|
* such that the retrieval of the component part is dependent on the identification and location
|
||||||
|
* of the host item or container. Contains fields that describe the component part and data that
|
||||||
|
* identify the host, field 773 (Host Item Entry).
|
||||||
|
*
|
||||||
|
* Examples of monographic component parts with corresponding host items include an article in a
|
||||||
|
* single issue of a periodical, a chapter in a book, a band on a phonodisc, and a map on a single
|
||||||
|
* sheet that contains several maps.
|
||||||
|
*
|
||||||
|
* b - Serial component part
|
||||||
|
* Serial bibliographic unit that is physically attached to or contained in another unit such
|
||||||
|
* that the retrieval of the component part is dependent on the identification and location
|
||||||
|
* of the host item or container. Contains fields that describe the component part and data that
|
||||||
|
* identify the host, field 773 (Host Item Entry).
|
||||||
|
*
|
||||||
|
* Example of a serial component part with corresponding host item is a regularly appearing column
|
||||||
|
* or feature in a periodical.
|
||||||
|
*
|
||||||
|
* c - Collection
|
||||||
|
* Made-up multipart group of items that were not originally published, distributed, or produced
|
||||||
|
* together. The record describes units defined by common provenance or administrative convenience
|
||||||
|
* for which the record is intended as the most comprehensive in the system.
|
||||||
|
*
|
||||||
|
* d - Subunit
|
||||||
|
* Part of collection, especially an archival unit described collectively elsewhere in the system.
|
||||||
|
* Contains fields that describe the subunit and data that identify the host item.
|
||||||
|
*
|
||||||
|
* Subunits may be items, folders, boxes, archival series, subgroups, or subcollections.
|
||||||
|
*
|
||||||
|
* i - Integrating resource
|
||||||
|
* Bibliographic resource that is added to or changed by means of updates that do not remain
|
||||||
|
* discrete and are integrated into the whole. Examples include updating loose-leafs and
|
||||||
|
* updating Web sites.
|
||||||
|
*
|
||||||
|
* Integrating resources may be finite or continuing.
|
||||||
|
*
|
||||||
|
* m - Monograph/Item
|
||||||
|
* Item either complete in one part (e.g., a single monograph, a single map, a single manuscript,
|
||||||
|
* etc.) or intended to be completed, in a finite number of separate parts (e.g., a multivolume
|
||||||
|
* monograph, a sound recording with multiple tracks, etc.).
|
||||||
|
*
|
||||||
|
* s - Serial
|
||||||
|
* Bibliographic item issued in successive parts bearing numerical or chronological designations
|
||||||
|
* and intended to be continued indefinitely. Includes periodicals; newspapers; annuals (reports,
|
||||||
|
* yearbooks, etc.); the journals, memoirs, proceedings, transactions, etc., of societies; and
|
||||||
|
* numbered monographic series, etc.
|
||||||
|
*/
|
||||||
|
public enum BibliographicLevel {
|
||||||
|
|
||||||
|
MONOGRPAHIC_COMPONENT_PART('a'),
|
||||||
|
SERIAL_COMPONENT_PART('b'),
|
||||||
|
COLLECTION('c'),
|
||||||
|
SUBUNIT('d'),
|
||||||
|
INTEGRATING_RESOURCE('i'),
|
||||||
|
MONOGRAPH('m'),
|
||||||
|
SERIAL('s');
|
||||||
|
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
BibliographicLevel(char ch) {
|
||||||
|
this.ch = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BibliographicLevel from(char ch) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'a':
|
||||||
|
return MONOGRPAHIC_COMPONENT_PART;
|
||||||
|
case 'b':
|
||||||
|
return SERIAL_COMPONENT_PART;
|
||||||
|
case 'c':
|
||||||
|
return COLLECTION;
|
||||||
|
case 'd':
|
||||||
|
return SUBUNIT;
|
||||||
|
case 'i':
|
||||||
|
return INTEGRATING_RESOURCE;
|
||||||
|
case 'm':
|
||||||
|
return MONOGRAPH;
|
||||||
|
case 's':
|
||||||
|
return SERIAL;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getChar() {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Descriptive cataloging form
|
||||||
|
*
|
||||||
|
* One-character alphanumeric code that indicates characteristics of the descriptive data in the
|
||||||
|
* record through reference to cataloging norms. Subfield $e (Description conventions)
|
||||||
|
* of field 040 (Cataloging Source) also contains information on the cataloging conventions used.
|
||||||
|
*
|
||||||
|
* # - Non-ISBD
|
||||||
|
* Descriptive portion of the record does not follow International Standard Bibliographic
|
||||||
|
* Description (ISBD) cataloging and punctuation provisions.
|
||||||
|
*
|
||||||
|
* a - AACR 2
|
||||||
|
* Descriptive portion of the record is formulated according to the description and punctuation
|
||||||
|
* provisions as incorporated into the Anglo-American Cataloging Rules, 2nd Edition (AACR 2)
|
||||||
|
* and its manuals.
|
||||||
|
*
|
||||||
|
* c - ISBD punctuation omitted
|
||||||
|
* Descriptive portion of the record contains the punctuation provisions of ISBD, except ISBD punctuation
|
||||||
|
* is not present at the end of a subfield.
|
||||||
|
*
|
||||||
|
* i - ISBD punctuation included
|
||||||
|
* Descriptive portion of the record contains the punctuation provisions of ISBD.
|
||||||
|
*
|
||||||
|
* u - Unknown
|
||||||
|
* Institution receiving or sending data in Leader/18 cannot adequately determine the appropriate
|
||||||
|
* descriptive cataloging form used in the record. May be used in records converted from another
|
||||||
|
* metadata format.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum DescriptiveCatalogingForm {
|
||||||
|
|
||||||
|
NON_ISBD(' '),
|
||||||
|
AACR2('a'),
|
||||||
|
ISBD_PUNCTUATION_OMITTED('c'),
|
||||||
|
ISBD_PUNCTUATION_INCLUDED('i'),
|
||||||
|
UNKNOWN('u')
|
||||||
|
;
|
||||||
|
|
||||||
|
char ch;
|
||||||
|
DescriptiveCatalogingForm(char ch) {
|
||||||
|
this.ch = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getChar() {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
52
src/main/java/org/xbib/marc/label/Encoding.java
Normal file
52
src/main/java/org/xbib/marc/label/Encoding.java
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Character encoding
|
||||||
|
*
|
||||||
|
* Identifies the character encoding used in the record.
|
||||||
|
*
|
||||||
|
* The encoding affects the number of octets needed per character, the placement of
|
||||||
|
* non-spacing characters, the use of escape sequences, and may affect the character
|
||||||
|
* repertoire.
|
||||||
|
*
|
||||||
|
* # - MARC-8
|
||||||
|
* Character coding in the record uses the 8-bit character sets described in MARC 21 Specifications
|
||||||
|
* for Record Structure, Character Sets, and Exchange Media. Non-default character sets used are
|
||||||
|
* identified in field 066.
|
||||||
|
*
|
||||||
|
* a - UCS/Unicode
|
||||||
|
* Character coding in the record makes use of characters from the Universal Coded Character Set (UCS)
|
||||||
|
* (ISO 10646), or Unicode, an industry subset.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum Encoding {
|
||||||
|
|
||||||
|
MARC8(' '),
|
||||||
|
UCS_UNICODE('a');
|
||||||
|
|
||||||
|
char ch;
|
||||||
|
Encoding(char ch) {
|
||||||
|
this.ch = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getChar() {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
100
src/main/java/org/xbib/marc/label/EncodingLevel.java
Normal file
100
src/main/java/org/xbib/marc/label/EncodingLevel.java
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encoding level
|
||||||
|
*
|
||||||
|
* One-character alphanumeric code that indicates the fullness of the bibliographic information
|
||||||
|
* and/or content designation of the MARC record.
|
||||||
|
*
|
||||||
|
* # - Full level
|
||||||
|
* Most complete MARC record created from information derived from an inspection of the physical item.
|
||||||
|
*
|
||||||
|
* For serials, at least one issue of the serial is inspected.
|
||||||
|
*
|
||||||
|
* 1 - Full level, material not examined
|
||||||
|
* Next most complete MARC record after the full level created from information derived from an extant
|
||||||
|
* description of the item (e.g., a printed catalog card or a description in an institutional guide)
|
||||||
|
* without reinspection of the physical item. Used primarily in the retrospective conversion of records
|
||||||
|
* when all of the information on the extant description is transcribed.
|
||||||
|
* Certain control field coding and other data (e.g., field 043 (Geographic Area Code)) are based
|
||||||
|
* only on explicit information in the description.
|
||||||
|
*
|
||||||
|
* 2 - Less-than-full level, material not examined
|
||||||
|
* Less-than-full level record (i.e., a record that falls between minimal level and full) created
|
||||||
|
* from an extant description of the material (e.g., a printed catalog card) without reinspection of
|
||||||
|
* the physical item. Used primarily in the retrospective conversion of records when all of the
|
||||||
|
* descriptive access points but only a specified subset of other data elements are transcribed.
|
||||||
|
* Authoritative headings may not be current.
|
||||||
|
*
|
||||||
|
* 3 - Abbreviated level
|
||||||
|
* Brief record that does not meet minimal level cataloging specifications. Headings in the records may
|
||||||
|
* reflect established forms to the extent that such forms were available at the time the record was created.
|
||||||
|
*
|
||||||
|
* 4 - Core level
|
||||||
|
* Less-than-full but greater-than-minimal level cataloging record that meets core record standards for completeness.
|
||||||
|
*
|
||||||
|
* 5 - Partial (preliminary) level
|
||||||
|
* Preliminary cataloging level record that is not considered final by the creating agency
|
||||||
|
* (e.g., the headings may not reflect established forms; the record may not meet national-level cataloging
|
||||||
|
* specifications).
|
||||||
|
*
|
||||||
|
* 7 - Minimal level
|
||||||
|
* Record that meets the U.S. National Level Bibliographic Record minimal level cataloging specifications
|
||||||
|
* and is considered final by the creating agency. Headings have been checked against an authority file
|
||||||
|
* and reflect established forms to the extent that such forms were available at the time the minimal level
|
||||||
|
* record was created. The U.S. requirements for minimal-level records can be found in National Level
|
||||||
|
* and Minimal Level Record Requirements
|
||||||
|
*
|
||||||
|
* 8 - Prepublication level
|
||||||
|
* Prepublication level record. Includes records created in cataloging in publication programs.
|
||||||
|
*
|
||||||
|
* u - Unknown
|
||||||
|
* Used by an agency receiving or sending data with a local code in Leader/17 cannot adequately determine
|
||||||
|
* the appropriate encoding level of the record. Code u thus replaces the local code.
|
||||||
|
* Not used in newly input or updated records.
|
||||||
|
*
|
||||||
|
* For example, code u is used in Dublin Core originated records.
|
||||||
|
*
|
||||||
|
* z - Not applicable
|
||||||
|
* Concept of encoding level does not apply to the record.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum EncodingLevel {
|
||||||
|
|
||||||
|
FULL(' '),
|
||||||
|
FULL_NOT_EXAMINED('1'),
|
||||||
|
LESS_THAN_FULL_NOT_EXAMINED('2'),
|
||||||
|
ABBREV('3'),
|
||||||
|
CORE('4'),
|
||||||
|
PARTIAL('5'),
|
||||||
|
MINIMAL('7'),
|
||||||
|
PREPUBLICATION('8'),
|
||||||
|
UNKNOWN('u'),
|
||||||
|
NOT_APPLICABLE('z')
|
||||||
|
;
|
||||||
|
|
||||||
|
char ch;
|
||||||
|
EncodingLevel(char ch) {
|
||||||
|
this.ch = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getChar() {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multipart resource record level
|
||||||
|
* Record level to which a resource pertains and any record dependencies.
|
||||||
|
* This information will facilitate processing the record in different situations.
|
||||||
|
* For example, the record may describe a set of items, or it may describe a part of a set.
|
||||||
|
* The part may only have a dependent title to be used for identification purposes thus
|
||||||
|
* requiring use of additional information to understand its context.
|
||||||
|
*
|
||||||
|
* # - Not specified or not applicable
|
||||||
|
* The distinction between record levels is not specified or not applicable for the type of resource.
|
||||||
|
*
|
||||||
|
* a - Set
|
||||||
|
* Record is for a set consisting of multiple items.
|
||||||
|
*
|
||||||
|
* b - Part with independent title
|
||||||
|
* The record is for a resource which is part of a set and has a title that allows it
|
||||||
|
* to be independent of the set record.
|
||||||
|
*
|
||||||
|
* c - Part with dependent title
|
||||||
|
* The record is for a resource which is part of a set but has a title that makes it dependent
|
||||||
|
* on the set record to understand its context.
|
||||||
|
*/
|
||||||
|
public enum MultipartResourceRecordLevel {
|
||||||
|
|
||||||
|
NOT_SPECIFIED(' '),
|
||||||
|
SET('a'),
|
||||||
|
PART_WITH_INDEPENDENT_TITLE('b'),
|
||||||
|
PART_WITH_DEPENDENT_TITLE('c')
|
||||||
|
;
|
||||||
|
|
||||||
|
char ch;
|
||||||
|
MultipartResourceRecordLevel(char ch) {
|
||||||
|
this.ch = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getChar() {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
542
src/main/java/org/xbib/marc/label/RecordLabel.java
Normal file
542
src/main/java/org/xbib/marc/label/RecordLabel.java
Normal file
|
@ -0,0 +1,542 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.label;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record label of ISO 2709 records.
|
||||||
|
*/
|
||||||
|
public class RecordLabel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of a record label is fixed at 24 characters.
|
||||||
|
*/
|
||||||
|
public static final int LENGTH = 24;
|
||||||
|
|
||||||
|
public static final RecordLabel EMPTY = RecordLabel.builder().build();
|
||||||
|
|
||||||
|
private final Builder builder;
|
||||||
|
|
||||||
|
private final String label;
|
||||||
|
|
||||||
|
private RecordLabel(Builder builder, String label) {
|
||||||
|
this.builder = builder;
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRecordLength() {
|
||||||
|
return builder.recordLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordStatus getRecordStatus() {
|
||||||
|
return builder.recordStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BibliographicLevel getBibliographicLevel() {
|
||||||
|
return builder.bibliographicLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EncodingLevel getEncodingLevel() {
|
||||||
|
return builder.encodingLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DescriptiveCatalogingForm getDescriptiveCatalogingForm() {
|
||||||
|
return builder.descriptiveCatalogingForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MultipartResourceRecordLevel getMultipartResourceRecordLevel() {
|
||||||
|
return builder.multipartResourceRecordLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeOfRecord getTypeOfRecord() {
|
||||||
|
return builder.typeOfRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeOfControl getTypeOfControl() {
|
||||||
|
return builder.typeOfControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndicatorLength() {
|
||||||
|
return builder.indicatorLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSubfieldIdentifierLength() {
|
||||||
|
return builder.subfieldIdentifierLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBaseAddressOfData() {
|
||||||
|
return builder.baseAddressOfData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDataFieldLength() {
|
||||||
|
return builder.dataFieldLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStartingCharacterPositionLength() {
|
||||||
|
return builder.startingCharacterPositionLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSegmentIdentifierLength() {
|
||||||
|
return builder.segmentIdentifierLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] asBytes() {
|
||||||
|
return label.getBytes(StandardCharsets.ISO_8859_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for record label.
|
||||||
|
*/
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
private final char[] empty = new char[] {
|
||||||
|
' ', ' ', ' ', ' ', ' ', ' ',
|
||||||
|
' ', ' ', ' ', ' ', ' ', ' ',
|
||||||
|
' ', ' ', ' ', ' ', ' ', ' ',
|
||||||
|
' ', ' ', ' ', ' ', ' ', ' '
|
||||||
|
};
|
||||||
|
|
||||||
|
private char[] cfix;
|
||||||
|
|
||||||
|
private int recordLength;
|
||||||
|
|
||||||
|
private RecordStatus recordStatus;
|
||||||
|
|
||||||
|
private BibliographicLevel bibliographicLevel;
|
||||||
|
|
||||||
|
private int indicatorLength;
|
||||||
|
|
||||||
|
private int subfieldIdentifierLength;
|
||||||
|
|
||||||
|
private int baseAddressOfData;
|
||||||
|
|
||||||
|
private int dataFieldLength;
|
||||||
|
|
||||||
|
private int startingCharacterPositionLength;
|
||||||
|
|
||||||
|
private int segmentIdentifierLength;
|
||||||
|
|
||||||
|
private EncodingLevel encodingLevel;
|
||||||
|
|
||||||
|
private DescriptiveCatalogingForm descriptiveCatalogingForm;
|
||||||
|
|
||||||
|
private MultipartResourceRecordLevel multipartResourceRecordLevel;
|
||||||
|
|
||||||
|
private TypeOfRecord typeOfRecord;
|
||||||
|
|
||||||
|
private TypeOfControl typeOfControl;
|
||||||
|
|
||||||
|
private Builder() {
|
||||||
|
cfix = empty;
|
||||||
|
repair();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder from(RecordLabel recordLabel) {
|
||||||
|
cfix = recordLabel.toString().toCharArray();
|
||||||
|
repair();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Five decimal digits, right justified, with zero fill where necessary,
|
||||||
|
* representing the number of characters in the entire record, including the
|
||||||
|
* label itself, the directory, and the variable fields. This data element
|
||||||
|
* is normally calculated automatically when the total record is assembled
|
||||||
|
* for exchange.
|
||||||
|
*
|
||||||
|
* @param length the length
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setRecordLength(int length) {
|
||||||
|
if (length >= 0 && length < 10000) {
|
||||||
|
this.recordLength = length;
|
||||||
|
String s = String.format("%05d", length);
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
cfix[i] = s.charAt(i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single character, denoting the processing status of the record.
|
||||||
|
*
|
||||||
|
* c corrected record
|
||||||
|
*
|
||||||
|
* A record to which changes have been made to correct errors, one which has
|
||||||
|
* been amended to bring it up to date, or one where fields have been
|
||||||
|
* deleted. However, if the previous record was a prepublication record
|
||||||
|
* (e.g.; CIP) and a full record replacement is now being issued, code 'p'
|
||||||
|
* should be used instead of 'c'. A record labelled 'n', 'o' or 'p' on which
|
||||||
|
* a correction is made is coded as 'c'.
|
||||||
|
*
|
||||||
|
* d deleted record
|
||||||
|
*
|
||||||
|
* A record which is exchanged in order to indicate that a record bearing
|
||||||
|
* this control number is no longer valid. The record may contain only the
|
||||||
|
* label, directory; and 001 (record control number) field, or it may
|
||||||
|
* contain all the fields in the record as issued; in either case GENERAL
|
||||||
|
* NOTE 300 field may be used to explain why the record is deleted.
|
||||||
|
*
|
||||||
|
* n new record
|
||||||
|
*
|
||||||
|
* A new record (including a pre-publication record, e.g., CIP). If code 'o'
|
||||||
|
* applies, it is used in preference to ' n '.
|
||||||
|
*
|
||||||
|
* o previously issued higher level record
|
||||||
|
*
|
||||||
|
* A new record at a hierarchical level below the highest level for which a
|
||||||
|
* higher level record has already been issued (see also character position
|
||||||
|
* 8).
|
||||||
|
*
|
||||||
|
* p previously issued as an incomplete, pre-publication record
|
||||||
|
*
|
||||||
|
* A record for a published item replacing a pre-publication record, e.g.,
|
||||||
|
* CIP.
|
||||||
|
*
|
||||||
|
* @param recordStatus the record status
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setRecordStatus(RecordStatus recordStatus) {
|
||||||
|
this.recordStatus = recordStatus;
|
||||||
|
cfix[5] = recordStatus.getChar();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set type of record. See {@link TypeOfRecord}.
|
||||||
|
* @param typeOfRecord the type of record
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setTypeOfRecord(TypeOfRecord typeOfRecord) {
|
||||||
|
this.typeOfRecord = typeOfRecord;
|
||||||
|
cfix[6] = typeOfRecord.getChar();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bibliographic level of a record relates to the main part of the
|
||||||
|
* record. Some cataloguing codes may not make a clear distinction between a
|
||||||
|
* multipart item (multivolume monograph) and a monographic series. In such
|
||||||
|
* cases an agency should use whichever of the values is more appropriate in
|
||||||
|
* the majority of cases. Where such a distinction is made, but cannot be
|
||||||
|
* determined in a particular instance, the item should be coded as a
|
||||||
|
* serial.
|
||||||
|
*
|
||||||
|
* 'a' analytic (component part)
|
||||||
|
*
|
||||||
|
* bibliographic item that is physically contained in another item such that
|
||||||
|
* the location of the component part is dependent upon the physical
|
||||||
|
* identification and location of the containing item. A component part may
|
||||||
|
* itself be either monographic or serial.
|
||||||
|
*
|
||||||
|
* The following are examples of materials that are coded 'a': an article in
|
||||||
|
* a journal; a continuing column or feature within a journal; a single
|
||||||
|
* paper in a collection of conference proceedings.
|
||||||
|
*
|
||||||
|
* 'c' collection
|
||||||
|
*
|
||||||
|
* bibliographic item that is a made-up collection.
|
||||||
|
*
|
||||||
|
* The following are examples of materials which are coded 'c': a collection
|
||||||
|
* of pamphlets housed in a box; a set of memorabilia in various formats
|
||||||
|
* kept together as a collection; all the manuscripts of an individual
|
||||||
|
* author.
|
||||||
|
*
|
||||||
|
* This code is used only for made-up collections.
|
||||||
|
*
|
||||||
|
* 'm' monographic
|
||||||
|
*
|
||||||
|
* bibliographic item complete in one physical part or intended to be
|
||||||
|
* completed in a finite number of parts.
|
||||||
|
*
|
||||||
|
* The following are examples of materials which are coded 'm': a single
|
||||||
|
* part item (monograph); a multipart item (multivolume monograph); a
|
||||||
|
* separately catalogued single part of a multipart item; a book in a
|
||||||
|
* series; a separately catalogued special issue of a newspaper; a sheet map
|
||||||
|
* in a series; a complete series of maps, assuming the series was intended
|
||||||
|
* to be completed in a finite number of parts; a single globe.
|
||||||
|
*
|
||||||
|
* 's' serial
|
||||||
|
*
|
||||||
|
* bibliographic item issued in successive parts and intended to be
|
||||||
|
* continued indefinitely.
|
||||||
|
*
|
||||||
|
* The following are examples of materials which are coded 's': a journal
|
||||||
|
* that is still being published; a complete run of a journal that has
|
||||||
|
* ceased publication; a newspaper; a monographic series.
|
||||||
|
*
|
||||||
|
* @param level the level
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setBibliographicLevel(BibliographicLevel level) {
|
||||||
|
this.bibliographicLevel = level;
|
||||||
|
cfix[7] = level.getChar();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set type of control. See {@link TypeOfControl}.
|
||||||
|
* @param typeOfControl the type of control
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setTypeOfControl(TypeOfControl typeOfControl) {
|
||||||
|
this.typeOfControl = typeOfControl;
|
||||||
|
cfix[8] = typeOfControl.getChar();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicator length is a numeric digit giving the length of the indicators.
|
||||||
|
*
|
||||||
|
* @param length the length
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setIndicatorLength(int length) {
|
||||||
|
if (length >= 0 && length < 10) {
|
||||||
|
this.indicatorLength = length;
|
||||||
|
cfix[10] = (char) ('0' + length);
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A numeric digit giving the length of the subfield identifier.
|
||||||
|
*
|
||||||
|
* @param subfieldIdentifierLength the subfield identifier length
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setSubfieldIdentifierLength(int subfieldIdentifierLength) {
|
||||||
|
if (subfieldIdentifierLength >= 0 && subfieldIdentifierLength < 10) {
|
||||||
|
this.subfieldIdentifierLength = subfieldIdentifierLength;
|
||||||
|
cfix[11] = (char) ('0' + subfieldIdentifierLength);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base address of data. The location within the record at which the first
|
||||||
|
* datafield begins, relative to the first character in the record, which is
|
||||||
|
* designated character position `0' (zero).
|
||||||
|
*
|
||||||
|
* Five numeric digits, right justified with leading zeros, indicating the
|
||||||
|
* starting character position of the first data field relative to the
|
||||||
|
* beginning of the record. Since the first character of the record is
|
||||||
|
* numbered 0 (zero), the number entered as the base address of data will be
|
||||||
|
* equal to the total number of characters in the label and directory
|
||||||
|
* including the field separator that terminates the directory. In the
|
||||||
|
* directory, the starting character position for each field is given
|
||||||
|
* relative to the first character of the first data field which will be
|
||||||
|
* field 001, rather than the beginning of the record. The base address thus
|
||||||
|
* gives the base from which the position of each field is calculated.
|
||||||
|
*
|
||||||
|
* @param baseAddressOfData the base address of data
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setBaseAddressOfData(int baseAddressOfData) {
|
||||||
|
if (baseAddressOfData >= 0 && baseAddressOfData < 10000) {
|
||||||
|
this.baseAddressOfData = baseAddressOfData;
|
||||||
|
String s = String.format("%05d", baseAddressOfData);
|
||||||
|
for (int i = 12; i < 17; i++) {
|
||||||
|
cfix[i] = s.charAt(i - 12);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set encoding level. See {@link EncodingLevel}.
|
||||||
|
* @param encodingLevel the encoding level
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setEncodingLevel(EncodingLevel encodingLevel) {
|
||||||
|
this.encodingLevel = encodingLevel;
|
||||||
|
cfix[17] = encodingLevel.getChar();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set descriptive cataloging form. See {@link DescriptiveCatalogingForm}.
|
||||||
|
* @param descriptiveCatalogingForm the descriptive cataloging form
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setDescriptiveCatalogingForm(DescriptiveCatalogingForm descriptiveCatalogingForm) {
|
||||||
|
this.descriptiveCatalogingForm = descriptiveCatalogingForm;
|
||||||
|
cfix[18] = descriptiveCatalogingForm.getChar();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set multipart resource record level. See {@link MultipartResourceRecordLevel}.
|
||||||
|
* @param multipartResourceRecordLevel the multipart resource record level
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setMultipartResourceRecordLevel(MultipartResourceRecordLevel multipartResourceRecordLevel) {
|
||||||
|
this.multipartResourceRecordLevel = multipartResourceRecordLevel;
|
||||||
|
cfix[19] = multipartResourceRecordLevel.getChar();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Length of data field A four-digit number showing how many characters are
|
||||||
|
* occupied the datafield, including indicators and datafield separator but
|
||||||
|
* excluding the record separator code if the datafield is the last field in
|
||||||
|
* the record. The use of 4 characters permits datafields as long as 9999
|
||||||
|
* characters.
|
||||||
|
*
|
||||||
|
* @param length the length
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setDataFieldLength(int length) {
|
||||||
|
if (length >= 0 && length < 10) {
|
||||||
|
this.dataFieldLength = length;
|
||||||
|
cfix[20] = (char) ('0' + length);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Length of the starting-character-position portion of each entry.
|
||||||
|
*
|
||||||
|
* @param length the length
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder setStartingCharacterPositionLength(int length) {
|
||||||
|
if (length >= 0 && length < 10) {
|
||||||
|
this.startingCharacterPositionLength = length;
|
||||||
|
cfix[21] = (char) ('0' + length);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of implementation-defined section of each entry in the
|
||||||
|
* directory. Of the two characters, one is used for the segment identifier,
|
||||||
|
* the other for the occurrence identifier.
|
||||||
|
*
|
||||||
|
* @param length the length
|
||||||
|
* @return tthis builder
|
||||||
|
*/
|
||||||
|
public Builder setSegmentIdentifierLength(int length) {
|
||||||
|
if (length >= 0 && length < 10) {
|
||||||
|
this.segmentIdentifierLength = length;
|
||||||
|
cfix[22] = (char) ('0' + length);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse given record label.
|
||||||
|
* @param recordLabel the record label
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
public Builder from(char[] recordLabel) {
|
||||||
|
char[] label = recordLabel;
|
||||||
|
if (label.length > LENGTH) {
|
||||||
|
label = Arrays.copyOf(label, LENGTH);
|
||||||
|
} else if (label.length < LENGTH) {
|
||||||
|
// fill with blanks
|
||||||
|
char[] ch = new char[LENGTH - label.length];
|
||||||
|
for (int i = 0; i < ch.length; i++) {
|
||||||
|
ch[i] = ' ';
|
||||||
|
}
|
||||||
|
char[] newLabel = new char[LENGTH];
|
||||||
|
System.arraycopy(label, 0, newLabel, 0, label.length);
|
||||||
|
System.arraycopy(ch, 0, newLabel, label.length, ch.length);
|
||||||
|
label = newLabel;
|
||||||
|
}
|
||||||
|
System.arraycopy(label, 0, cfix, 0, LENGTH);
|
||||||
|
repair();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void repair() {
|
||||||
|
int[] pos = new int[] { 0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 15, 16, 20, 21, 22 };
|
||||||
|
for (int i : pos) {
|
||||||
|
if (cfix[i] < '0' || cfix[i] > '9') {
|
||||||
|
cfix[i] = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos = new int[] { 5, 6, 7, 8, 9, 17, 18, 19, 23 };
|
||||||
|
for (int i : pos) {
|
||||||
|
if (cfix[i] == '^' || cfix[i] == '-') {
|
||||||
|
cfix[i] = ' ';
|
||||||
|
}
|
||||||
|
// suppress C0 control chars (for XML 1.0 output)
|
||||||
|
if (cfix[i] < 32) {
|
||||||
|
cfix[i] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assign() {
|
||||||
|
this.recordLength = Integer.parseInt(new StringBuilder()
|
||||||
|
.append(cfix[0])
|
||||||
|
.append(cfix[1])
|
||||||
|
.append(cfix[2])
|
||||||
|
.append(cfix[3])
|
||||||
|
.append(cfix[4]).toString());
|
||||||
|
this.recordStatus = RecordStatus.from(cfix[5]);
|
||||||
|
this.bibliographicLevel = BibliographicLevel.from(cfix[7]);
|
||||||
|
this.indicatorLength = cfix[10] - '0';
|
||||||
|
this.subfieldIdentifierLength = cfix[11] - '0';
|
||||||
|
this.baseAddressOfData = Integer.parseInt(new StringBuilder()
|
||||||
|
.append(cfix[12])
|
||||||
|
.append(cfix[13])
|
||||||
|
.append(cfix[14])
|
||||||
|
.append(cfix[15])
|
||||||
|
.append(cfix[16]).toString());
|
||||||
|
this.dataFieldLength = cfix[20] - '0';
|
||||||
|
this.startingCharacterPositionLength = cfix[21] - '0';
|
||||||
|
this.segmentIdentifierLength = cfix[22] - '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build record label.
|
||||||
|
* @return the record label
|
||||||
|
*/
|
||||||
|
public RecordLabel build() {
|
||||||
|
assign();
|
||||||
|
return new RecordLabel(this, new String(cfix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
src/main/java/org/xbib/marc/label/RecordLabelFixer.java
Normal file
26
src/main/java/org/xbib/marc/label/RecordLabelFixer.java
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface allows to fix existing record labels.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface RecordLabelFixer {
|
||||||
|
|
||||||
|
RecordLabel fix(RecordLabel recordLabel);
|
||||||
|
}
|
81
src/main/java/org/xbib/marc/label/RecordStatus.java
Normal file
81
src/main/java/org/xbib/marc/label/RecordStatus.java
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record status
|
||||||
|
*
|
||||||
|
* One-character alphabetic code that indicates the relationship of the record to a file
|
||||||
|
* for file maintenance purposes.
|
||||||
|
*
|
||||||
|
* a - Increase in encoding level
|
||||||
|
* Encoding level (Leader/17) of the record has been changed to a higher encoding level.
|
||||||
|
*
|
||||||
|
* Indicates an increase in the level of cataloging (e.g., code a is used when a preliminary
|
||||||
|
* cataloging record (code 5 in Leader/17) is raised to full cataloging level (code # in Leader/17)).
|
||||||
|
*
|
||||||
|
* c - Corrected or revised
|
||||||
|
* Addition/change other than in the Encoding level code has been made to the record.
|
||||||
|
*
|
||||||
|
* d - Deleted
|
||||||
|
* Record has been deleted.
|
||||||
|
*
|
||||||
|
* n - New
|
||||||
|
* Record is newly input.
|
||||||
|
*
|
||||||
|
* p - Increase in encoding level from prepublication
|
||||||
|
* Prepublication record has had a change in cataloging level resulting from the availability
|
||||||
|
* of the published item.
|
||||||
|
*
|
||||||
|
* Example: a CIP record (code 8 in Leader/17)) upgraded to a full record (code # or 1 in Leader/17.)
|
||||||
|
*/
|
||||||
|
public enum RecordStatus {
|
||||||
|
|
||||||
|
INCREASE_IN_ENCODING_LEVEL('a'),
|
||||||
|
CORRECTED_OR_REVISED('c'),
|
||||||
|
DELETED('d'),
|
||||||
|
NEW('n'),
|
||||||
|
INCREASE_IN_ENCODING_LEVEL_FROM_PREPUBLICATION('p');
|
||||||
|
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
RecordStatus(char ch) {
|
||||||
|
this.ch = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RecordStatus from(char ch) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'a':
|
||||||
|
return INCREASE_IN_ENCODING_LEVEL;
|
||||||
|
case 'c':
|
||||||
|
return CORRECTED_OR_REVISED;
|
||||||
|
case 'd':
|
||||||
|
return DELETED;
|
||||||
|
case 'n':
|
||||||
|
return NEW;
|
||||||
|
case 'p':
|
||||||
|
return INCREASE_IN_ENCODING_LEVEL_FROM_PREPUBLICATION;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getChar() {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
45
src/main/java/org/xbib/marc/label/TypeOfControl.java
Normal file
45
src/main/java/org/xbib/marc/label/TypeOfControl.java
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of control
|
||||||
|
*
|
||||||
|
* # - No specified type
|
||||||
|
* No type applies to the item being described.
|
||||||
|
*
|
||||||
|
* a - Archival
|
||||||
|
* Material is described according to archival descriptive rules, which focus on the contextual
|
||||||
|
* relationships between items and on their provenance rather than on bibliographic detail.
|
||||||
|
* The specific set of rules for description may be found in field 040, subfield $e.
|
||||||
|
* All forms of material can be controlled archivally.
|
||||||
|
*/
|
||||||
|
public enum TypeOfControl {
|
||||||
|
|
||||||
|
NO_SPECIFIED_TYPE(' '),
|
||||||
|
ARCHIVAL('a')
|
||||||
|
;
|
||||||
|
|
||||||
|
char ch;
|
||||||
|
TypeOfControl(char ch) {
|
||||||
|
this.ch = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getChar() {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
161
src/main/java/org/xbib/marc/label/TypeOfRecord.java
Normal file
161
src/main/java/org/xbib/marc/label/TypeOfRecord.java
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 Jörg Prante
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of record
|
||||||
|
*
|
||||||
|
* One-character alphabetic code used to define the characteristics and components of the record.
|
||||||
|
*
|
||||||
|
* Used to differentiate MARC records created for various types of content and material and
|
||||||
|
* to determine the appropriateness and validity of certain data elements in the record.
|
||||||
|
*
|
||||||
|
* Microforms, whether original or reproductions, are not identified by a distinctive
|
||||||
|
* Type of record code. The type of content characteristics described by the codes
|
||||||
|
* take precedence over the microform characteristics of the item.
|
||||||
|
* Computer files are identified by a distinctive Type of record code only if they belong
|
||||||
|
* to certain categories of electronic resources as specified below; in all other cases
|
||||||
|
* the type of content characteristics described by the other codes take precedence
|
||||||
|
* over the computer file characteristics of the item.
|
||||||
|
*
|
||||||
|
* Determination of the code for a multi-item bibliographic entity (types of material
|
||||||
|
* are those specified by values a through t below):
|
||||||
|
*
|
||||||
|
* Items are multiple forms of material
|
||||||
|
*
|
||||||
|
* o (Kit) - entity is issued as a single unit; no type of material predominates
|
||||||
|
* p (Mixed materials) - entity is a made-up collection; no type of material predominates
|
||||||
|
* other codes - entity is a made-up collection; one type of material predominates
|
||||||
|
*
|
||||||
|
* Items are all one form of material
|
||||||
|
*
|
||||||
|
* any except o or p - all cases
|
||||||
|
* a - Language material
|
||||||
|
* Used for non-manuscript language material. Manuscript language material uses code t.
|
||||||
|
*
|
||||||
|
* Includes microforms and electronic resources that are basically textual in nature,
|
||||||
|
* whether they are reproductions from print or originally produced.
|
||||||
|
*
|
||||||
|
* c - Notated music
|
||||||
|
* Used for printed, microform, or electronic notated music.
|
||||||
|
*
|
||||||
|
* d - Manuscript notated music
|
||||||
|
* Used for manuscript notated music or a microform of manuscript music.
|
||||||
|
*
|
||||||
|
* e - Cartographic material
|
||||||
|
* Used for non-manuscript cartographic material or a microform of non-manuscript cartographic material.
|
||||||
|
*
|
||||||
|
* Includes maps, atlases, globes, digital maps, and other cartographic items.
|
||||||
|
*
|
||||||
|
* f - Manuscript cartographic material
|
||||||
|
* Used for manuscript cartographic material or a microform of manuscript cartographic material.
|
||||||
|
*
|
||||||
|
* g - Projected medium
|
||||||
|
* Used for motion pictures, videorecordings (including digital video), filmstrips, slide,
|
||||||
|
* transparencies or material specifically designed for projection.
|
||||||
|
*
|
||||||
|
* Material specifically designed for overhead projection is also included in this type of record category.
|
||||||
|
*
|
||||||
|
* i - Nonmusical sound recording
|
||||||
|
* Used for a recording of nonmusical sounds (e.g., speech).
|
||||||
|
*
|
||||||
|
* j - Musical sound recording
|
||||||
|
* Used for a musical sound recording (e.g., phonodiscs, compact discs, or cassette tapes.
|
||||||
|
*
|
||||||
|
* k - Two-dimensional nonprojectable graphic
|
||||||
|
* Used for two-dimensional nonprojectable graphics such as, activity cards, charts, collages,
|
||||||
|
* computer graphics, digital pictures, drawings, duplication masters, flash cards, paintings,
|
||||||
|
* photo CDs, photomechanical reproductions, photonegatives, photoprints, pictures, postcards,
|
||||||
|
* posters, prints, spirit masters, study prints, technical drawings, transparency masters,
|
||||||
|
* and reproductions of any of these.
|
||||||
|
*
|
||||||
|
* m - Computer file
|
||||||
|
* Used for the following classes of electronic resources: computer software
|
||||||
|
* (including programs, games, fonts), numeric data, computer-oriented multimedia,
|
||||||
|
* online systems or services. For these classes of materials, if there is a significant
|
||||||
|
* aspect that causes it to fall into another Leader/06 category, the code for that
|
||||||
|
* significant aspect is used instead of code m (e.g., vector data that is cartographic
|
||||||
|
* is not coded as numeric but as cartographic). Other classes of electronic resources are
|
||||||
|
* coded for their most significant aspect (e.g. language material, graphic, cartographic material,
|
||||||
|
* sound, music, moving image). In case of doubt or if the most significant aspect cannot be
|
||||||
|
* determined, consider the item a computer file.
|
||||||
|
*
|
||||||
|
* o - Kit
|
||||||
|
* Used for a mixture of various components issued as a unit and intended primarily
|
||||||
|
* for instructional purposes where no one item is the predominant component of the kit.
|
||||||
|
*
|
||||||
|
* Examples are packages of assorted materials, such as a set of school social studies
|
||||||
|
* curriculum material (books, workbooks, guides, activities, etc.), or packages of
|
||||||
|
* educational test materials (tests, answer sheets, scoring guides, score charts,
|
||||||
|
* interpretative manuals, etc.).
|
||||||
|
*
|
||||||
|
* p - Mixed materials
|
||||||
|
* Used when there are significant materials in two or more forms that are usually related
|
||||||
|
* by virtue of their having been accumulated by or about a person or body.
|
||||||
|
* Includes archival fonds and manuscript collections of mixed forms of materials,
|
||||||
|
* such as text, photographs, and sound recordings.
|
||||||
|
*
|
||||||
|
* Intended primary purpose is other than for instructional purposes (i.e., other than
|
||||||
|
* the purpose of those materials coded as o (Kit)).
|
||||||
|
*
|
||||||
|
* r - Three-dimensional artifact or naturally occurring object
|
||||||
|
* Includes man-made objects such as models, dioramas, games, puzzles, simulations,
|
||||||
|
* sculptures and other three-dimensional art works, exhibits, machines, clothing, toys,
|
||||||
|
* and stitchery. Also includes naturally occurring objects such as, microscope specimens
|
||||||
|
* (or representations of them) and other specimens mounted for viewing.
|
||||||
|
*
|
||||||
|
* t - Manuscript language material
|
||||||
|
* Used for manuscript language material or a microform of manuscript language material.
|
||||||
|
* This category is applied to items for language material in handwriting, typescript, or
|
||||||
|
* computer printout including printed materials completed by hand or by keyboard.
|
||||||
|
* At the time it is created, this material is usually intended, either implicitly or explicitly,
|
||||||
|
* to exist as a single instance. Examples include marked or corrected galley and page proofs,
|
||||||
|
* manuscript books, legal papers, and unpublished theses and dissertations.
|
||||||
|
*
|
||||||
|
* http://www.ifla.org/files/assets/uca/unimarc_updates/BIBLIOGRAPHIC/u-b_reclabl_update.pdf
|
||||||
|
*/
|
||||||
|
public enum TypeOfRecord {
|
||||||
|
|
||||||
|
LANGUAGE_MATERIAL('a'),
|
||||||
|
LANGUAGE_MATERIAL_MANUSCRIPT('b'),
|
||||||
|
NOTATED_MUSIC('c'),
|
||||||
|
NOTATED_MUSIC_MANUSCRIPT('d'),
|
||||||
|
CARTOGRAPHIC_MATERIAL('e'),
|
||||||
|
CARTOGRAPHIC_MATERIAL_MANUSCRIPT('f'),
|
||||||
|
PROJECTED_MEDIUM('g'),
|
||||||
|
NONMUSICAL_SOUND_RECORDING('i'),
|
||||||
|
MUSICAL_SOUND_RECORDING('j'),
|
||||||
|
PICTURE('k'),
|
||||||
|
ELECTRONIC_RESOURCE('l'),
|
||||||
|
COMPUTER_FILE('m'),
|
||||||
|
KIT('o'),
|
||||||
|
MIXED_MATERIALS('p'),
|
||||||
|
ARTIFACT('r'),
|
||||||
|
LANGUAGE_MATERIAL_MANUSCRIPT_MARC21('t')
|
||||||
|
;
|
||||||
|
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
TypeOfRecord(char ch) {
|
||||||
|
this.ch = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getChar() {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
4
src/main/java/org/xbib/marc/label/package-info.java
Normal file
4
src/main/java/org/xbib/marc/label/package-info.java
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for MARC record labels.
|
||||||
|
*/
|
||||||
|
package org.xbib.marc.label;
|
4
src/main/java/org/xbib/marc/package-info.java
Normal file
4
src/main/java/org/xbib/marc/package-info.java
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Classes for processing MARC (machine-readble cataloging).
|
||||||
|
*/
|
||||||
|
package org.xbib.marc;
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue