{"id":13588139,"url":"https://github.com/opencultureconsulting/openrefine-batch","last_synced_at":"2025-04-08T02:35:09.378Z","repository":{"id":18058017,"uuid":"83249103","full_name":"opencultureconsulting/openrefine-batch","owner":"opencultureconsulting","description":"Shell script to run OpenRefine in batch mode (import, transform, export). It orchestrates OpenRefine (server) and a python client that communicates with the OpenRefine API.","archived":false,"fork":false,"pushed_at":"2024-06-11T21:13:27.000Z","size":224470,"stargazers_count":83,"open_issues_count":1,"forks_count":15,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-11-06T07:40:25.184Z","etag":null,"topics":["bash-script","batch-processing","code4lib","docker","etl","openrefine"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/opencultureconsulting.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-26T23:40:05.000Z","updated_at":"2024-07-31T19:16:20.000Z","dependencies_parsed_at":"2024-11-06T07:33:33.764Z","dependency_job_id":null,"html_url":"https://github.com/opencultureconsulting/openrefine-batch","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opencultureconsulting%2Fopenrefine-batch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opencultureconsulting%2Fopenrefine-batch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opencultureconsulting%2Fopenrefine-batch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opencultureconsulting%2Fopenrefine-batch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/opencultureconsulting","download_url":"https://codeload.github.com/opencultureconsulting/openrefine-batch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247765210,"owners_count":20992263,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash-script","batch-processing","code4lib","docker","etl","openrefine"],"created_at":"2024-08-01T15:06:31.896Z","updated_at":"2025-04-08T02:35:07.266Z","avatar_url":"https://github.com/opencultureconsulting.png","language":"Shell","funding_links":[],"categories":["Shell"],"sub_categories":[],"readme":"## OpenRefine batch processing (openrefine-batch.sh)\n\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/ad8a97e42e634bbe87203ea48efb436e)](https://www.codacy.com/gh/opencultureconsulting/openrefine-batch/dashboard) [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/opencultureconsulting/openrefine-batch/master?urlpath=lab/tree/demo.ipynb)\n\nShell script to run OpenRefine in batch mode (import, transform, export). This bash script automatically...\n\n1. imports all data from a given directory into OpenRefine\n2. transforms the data by applying OpenRefine transformation rules from all json files in another given directory and\n3. finally exports the data in csv, tsv, html, xlsx or ods.\n\nIt orchestrates [OpenRefine](https://github.com/OpenRefine/OpenRefine) (server) and a [python client](https://github.com/felixlohmeier/openrefine-client) that communicates with the OpenRefine API. By restarting the server after each process it reduces memory requirements to a minimum.\n\nIf you prefer a containerized approach, see a [variation of this script for Docker](#docker) below.\n\n### Typical Workflow\n\n- **Step 1**: Do some experiments with your data (or parts of it) in the graphical user interface of OpenRefine. If you are fine with all transformation rules, [extract the json code](http://kb.refinepro.com/2012/06/google-refine-json-and-my-notepad-or.html) and save it as file (e.g. transform.json).\n- **Step 2**: Put your data and the json file(s) in two different directories and execute the script. The script will automatically import all data files in OpenRefine projects, apply the transformation rules in the json files to each project and export all projects to files in the format specified (default: TSV - tab-separated values).\n\n### Demo via binder\n\n[![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/opencultureconsulting/openrefine-batch/master?urlpath=lab/tree/demo.ipynb)\n\n- free to use on-demand server with Jupyterlab and Bash Kernel\n- no registration needed, will start within a few minutes\n- [restricted](https://mybinder.readthedocs.io/en/latest/about/about.html#how-much-memory-am-i-given-when-using-binder) to 2 GB RAM and server will be deleted after 10 minutes of inactivity\n\n### Install\n\nDownload the script and grant file permissions to execute:\n```\nwget https://github.com/felixlohmeier/openrefine-batch/raw/master/openrefine-batch.sh\nchmod +x openrefine-batch.sh\n```\n\nThat's all. The script will automatically download copies of OpenRefine and the python client on first run and will tell you if something (python, java) is missing.\n\n### Usage\n\n```\nmkdir input\ncp INPUTFILES input/\nmkdir config\ncp CONFIGFILES config/\n./openrefine-batch.sh -a input/ -b config/ -c OUTPUT/\n```\n\n**INPUTFILES**\n* any data that [OpenRefine supports](https://github.com/OpenRefine/OpenRefine/wiki/Importers). CSV, TSV and line-based files should work out of the box. XML, JSON, fixed-width, XSLX and ODS need one additional input parameter (see chapter [Options](https://github.com/felixlohmeier/openrefine-batch#options) below)\n* multiple slices of data may be transformed into a into a single file [by providing a zip or tar.gz archive](https://github.com/OpenRefine/OpenRefine/wiki/Importers)\n* you may use hard symlinks instead of cp: `ln INPUTFILE input/`\n\n**CONFIGFILES**\n* JSON files with [OpenRefine transformation rules](http://kb.refinepro.com/2012/06/google-refine-json-and-my-notepad-or.html)\n\n**OUTPUT/**\n* path to directory where results and temporary data should be stored\n* Transformed data will be stored in this directory in the format specified (default: TSV). Show results: `ls OUTPUT/*.tsv`\n* OpenRefine stores data in directories like \"1234567890123.project\". You may have a look at the results by starting OpenRefine with this workspace. Delete the directories if you do not need them: `rm -r -f OUTPUT/*.project`\n\n### Example\n\n[Example Powerhouse Museum](examples/powerhouse-museum)\n\ndownload example data\n\n```\nwget https://github.com/opencultureconsulting/openrefine-batch/archive/master.zip\nunzip master.zip openrefine-batch-master/examples/*\nmv openrefine-batch-master/examples .\nrm -f master.zip\n```\n\nexecute openrefine-batch.sh\n\n```\n./openrefine-batch.sh \\\n-a examples/powerhouse-museum/input/ \\\n-b examples/powerhouse-museum/config/ \\\n-c examples/powerhouse-museum/output/ \\\n-f tsv \\\n-i processQuotes=false \\\n-i guessCellValueTypes=true \\\n-RX\n```\n\n### Help Screen\n\n```\n[felix@tux openrefine-batch]$ ./openrefine-batch.sh\nUsage: ./openrefine-batch.sh [-a INPUTDIR] [-b TRANSFORMDIR] [-c OUTPUTDIR] ...\n\n== basic arguments ==\n    -a INPUTDIR      path to directory with source files (leave empty to transform only ; multiple files may be imported into a single project by providing a zip or tar.gz archive, cf. https://github.com/OpenRefine/OpenRefine/wiki/Importers )\n    -b TRANSFORMDIR  path to directory with OpenRefine transformation rules (json files, cf. http://kb.refinepro.com/2012/06/google-refine-json-and-my-notepad-or.html ; leave empty to transform only)\n    -c OUTPUTDIR     path to directory for exported files (and OpenRefine workspace)\n\n== options ==\n    -d CROSSDIR      path to directory with additional OpenRefine projects (will be copied to workspace before transformation step to support the cross function, cf. https://github.com/OpenRefine/OpenRefine/wiki/GREL-Other-Functions )\n    -e EXPORTFORMAT  (csv, tsv, html, xls, xlsx, ods)\n    -f INPUTFORMAT   (csv, tsv, xml, json, line-based, fixed-width, xlsx, ods)\n    -i INPUTOPTIONS  several options provided by openrefine-client, see below...\n    -m RAM           maximum RAM for OpenRefine java heap space (default: 2048M)\n    -p PORT          PORT on which OpenRefine should listen (default: 3333)\n    -t TEMPLATING    several options for templating export, see below...\n    -E               do NOT export files\n    -R               do NOT restart OpenRefine after each transformation (e.g. config file)\n    -X               do NOT restart OpenRefine after each project (e.g. input file)\n    -h               displays this help screen\n\n== inputoptions (mandatory for xml, json, fixed-width, xslx, ods) ==\n    -i recordPath=RECORDPATH (xml, json): please provide path in multiple arguments without slashes, e.g. /collection/record/ should be entered like this: -i recordPath=collection -i recordPath=record, default xml: record, default json: _ _\n    -i columnWidths=COLUMNWIDTHS (fixed-width): please provide widths separated by comma (e.g. 7,5)\n    -i sheets=SHEETS (xls, xlsx, ods): please provide sheets separated by comma (e.g. 0,1), default: 0 (first sheet)\n\n== more inputoptions (optional, only together with inputformat) ==\n    -i projectName=PROJECTNAME (all formats), default: filename\n    -i limit=LIMIT (all formats), default: -1\n    -i includeFileSources=true/false (all formats), default: false\n    -i trimStrings=true/false (xml, json), default: false\n    -i storeEmptyStrings=true/false (xml, json), default: true\n    -i guessCellValueTypes=true/false (xml, csv, tsv, fixed-width, json), default: false\n    -i encoding=ENCODING (csv, tsv, line-based, fixed-width), please provide short encoding name (e.g. UTF-8)\n    -i ignoreLines=IGNORELINES (csv, tsv, line-based, fixed-width, xls, xlsx, ods), default: -1\n    -i headerLines=HEADERLINES (csv, tsv, fixed-width, xls, xlsx, ods), default: 1, default fixed-width: 0\n    -i skipDataLines=true/false (csv, tsv, line-based, fixed-width, xls, xlsx, ods), default: 0, default line-based: -1\n    -i storeBlankRows=true/false (csv, tsv, line-based, fixed-width, xls, xlsx, ods), default: true\n    -i processQuotes=true/false (csv, tsv), default: true\n    -i storeBlankCellsAsNulls=true/false (csv, tsv, line-based, fixed-width, xls, xlsx, ods), default: true\n    -i linesPerRow=LINESPERROW (line-based), default: 1\n\n== templating options (alternative exportformat) ==\n    -t template=TEMPLATE (mandatory; (big) text string that you enter in the *row template* textfield in the export/templating menu in the browser app)\n    -t mode=row-based/record-based (engine mode, default: row-based)\n    -t prefix=PREFIX (text string that you enter in the *prefix* textfield in the browser app)\n    -t rowSeparator=ROWSEPARATOR (text string that you enter in the *row separator* textfield in the browser app)\n    -t suffix=SUFFIX (text string that you enter in the *suffix* textfield in the browser app)\n    -t filterQuery=REGEX (Simple RegEx text filter on filterColumn, e.g. ^12015$)\n    -t filterColumn=COLUMNNAME (column name for filterQuery, default: name of first column)\n    -t facets=FACETS (facets config in json format, may be extracted with browser dev tools in browser app)\n    -t splitToFiles=true/false (will split each row/record into a single file; it specifies a presumably unique character series for splitting; prefix and suffix will be applied to all files\n    -t suffixById=true/false (enhancement option for splitToFiles; will generate filename-suffix from values in key column)\n\n== examples ==\n\ndownload example data\n\nwget https://github.com/opencultureconsulting/openrefine-batch/archive/master.zip\nunzip master.zip openrefine-batch-master/examples/*\nmv openrefine-batch-master/examples .\nrm -f master.zip\n\nexample 1 (input, transform, export to tsv)\n\n./openrefine-batch.sh -a examples/powerhouse-museum/input/ -b examples/powerhouse-museum/config/ -c examples/powerhouse-museum/output/ -f tsv -i processQuotes=false -i guessCellValueTypes=true -RX\n\nexample 2 (input, transform, templating export)\n\n./openrefine-batch.sh -a examples/powerhouse-museum/input/ -b examples/powerhouse-museum/config/ -c examples/powerhouse-museum/output/ -f tsv -i processQuotes=false -i guessCellValueTypes=true -RX -t template='{ \"Record ID\" : {{jsonize(cells[\"Record ID\"].value)}}, \"Object Title\" : {{jsonize(cells[\"Object Title\"].value)}}, \"Registration Number\" : {{jsonize(cells[\"Registration Number\"].value)}}, \"Description.\" : {{jsonize(cells[\"Description.\"].value)}}, \"Marks\" : {{jsonize(cells[\"Marks\"].value)}}, \"Production Date\" : {{jsonize(cells[\"Production Date\"].value)}}, \"Provenance (Production)\" : {{jsonize(cells[\"Provenance (Production)\"].value)}}, \"Provenance (History)\" : {{jsonize(cells[\"Provenance (History)\"].value)}}, \"Categories\" : {{jsonize(cells[\"Categories\"].value)}}, \"Persistent Link\" : {{jsonize(cells[\"Persistent Link\"].value)}}, \"Height\" : {{jsonize(cells[\"Height\"].value)}}, \"Width\" : {{jsonize(cells[\"Width\"].value)}}, \"Depth\" : {{jsonize(cells[\"Depth\"].value)}}, \"Diameter\" : {{jsonize(cells[\"Diameter\"].value)}}, \"Weight\" : {{jsonize(cells[\"Weight\"].value)}}, \"License info\" : {{jsonize(cells[\"License info\"].value)}} }' -t rowSeparator=',' -t prefix='{ \"rows\" : [ ' -t suffix='] }' -t splitToFiles=true\n```\n\n### Logging\n\nThe script prints log messages from OpenRefine server and makes use of `ps` to show statistics for each step. Here is a sample:\n\n```\n[felix@tux openrefine-batch]$ ./openrefine-batch.sh -a examples/powerhouse-museum/input/ -b examples/powerhouse-museum/config/ -c examples/powerhouse-museum/output/ -f tsv -i processQuotes=false -i guessCellValueTypes=true -RX\nDownload OpenRefine...\nopenrefine-linux-3.5.0.tar.gz                               100%[=========================================================================================================================================\u003e] 125,73M  9,50MB/s    in 13s     \nInstall OpenRefine in subdirectory openrefine...\nTotal bytes read: 154163200 (148MiB, 87MiB/s)\n\nDownload OpenRefine client...\nopenrefine-client_0-3-10_linux                              100%[=========================================================================================================================================\u003e]   4,25M  9,17MB/s    in 0,5s    \n\nInput directory:         /home/felix/git/openrefine-batch/examples/powerhouse-museum/input\nInput files:             phm-collection.tsv\nInput format:            --format=tsv\nInput options:           --processQuotes=false --guessCellValueTypes=true\nConfig directory:        /home/felix/git/openrefine-batch/examples/powerhouse-museum/config\nTransformation rules:    phm-transform.json\nCross directory:         /dev/null\nCross projects:          \nOpenRefine heap space:   2048M\nOpenRefine port:         3333\nOpenRefine workspace:    /home/felix/git/openrefine-batch/examples/powerhouse-museum/output\nExport to workspace:     true\nExport format:           tsv\nTemplating options:      \nrestart after file:      false\nrestart after transform: false\n\n=== 1. Launch OpenRefine ===\n\nstarting time: Di 9. Nov 22:37:25 CET 2021\n\nUsing refine.ini for configuration\nYou have 15913M of free memory.\nYour current configuration is set to use 2048M of memory.\nOpenRefine can run better when given more memory. Read our FAQ on how to allocate more memory here:\nhttps://github.com/OpenRefine/OpenRefine/wiki/FAQ-Allocate-More-Memory\n/usr/bin/java -cp server/classes:server/target/lib/* -Drefine.headless=true -Xms2048M -Xmx2048M -Drefine.memory=2048M -Drefine.max_form_content_size=1048576 -Drefine.verbosity=info -Dpython.path=main/webapp/WEB-INF/lib/jython -Dpython.cachedir=/home/felix/.local/share/google/refine/cachedir -Drefine.data_dir=/home/felix/git/openrefine-batch/examples/powerhouse-museum/output -Drefine.webapp=main/webapp -Drefine.port=3333 -Drefine.interface=127.0.0.1 -Drefine.host=127.0.0.1 -Drefine.autosave=1440 com.google.refine.Refine\nStarting OpenRefine at 'http://127.0.0.1:3333/'\n\nlog4j:WARN No appenders could be found for logger (org.eclipse.jetty.util.log).\nlog4j:WARN Please initialize the log4j system properly.\nlog4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.\nSLF4J: Class path contains multiple SLF4J bindings.\nSLF4J: Found binding in [jar:file:/home/felix/git/openrefine-batch/openrefine/webapp/WEB-INF/lib/slf4j-log4j12-1.7.30.jar!/org/slf4j/impl/StaticLoggerBinder.class]\nSLF4J: Found binding in [jar:file:/home/felix/git/openrefine-batch/openrefine/server/target/lib/slf4j-log4j12-1.7.30.jar!/org/slf4j/impl/StaticLoggerBinder.class]\nSLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.\nSLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]\n22:37:28.211 [                   refine] Starting OpenRefine 3.5.0 [d4209a2]... (0ms)\n22:37:28.213 [                   refine] initializing FileProjectManager with dir (2ms)\n22:37:28.213 [                   refine] /home/felix/git/openrefine-batch/examples/powerhouse-museum/output (0ms)\n22:37:28.223 [       FileProjectManager] Failed to load workspace from any attempted alternatives. (10ms)\n\n=== 2. Import all files ===\n\nstarting time: Di 9. Nov 22:37:33 CET 2021\n\nimport phm-collection.tsv...\n22:37:33.804 [                   refine] GET /command/core/get-csrf-token (5581ms)\n22:37:33.872 [                   refine] POST /command/core/create-project-from-upload (68ms)\n22:37:44.653 [                   refine] GET /command/core/get-models (10781ms)\n22:37:44.790 [                   refine] POST /command/core/get-rows (137ms)\nid: 2252508879578\nrows: 75814\n STARTED     ELAPSED %MEM %CPU   RSS\n22:37:25       00:19 10.2  202 1670620\n\n=== 3. Prepare transform \u0026 export ===\n\nstarting time: Di 9. Nov 22:37:44 CET 2021\n\nget project ids...\n22:37:45.112 [                   refine] GET /command/core/get-csrf-token (322ms)\n22:37:45.115 [                   refine] GET /command/core/get-all-project-metadata (3ms)\n 2252508879578: phm-collection\n\n=== 4. Transform phm-collection ===\n\nstarting time: Di 9. Nov 22:37:45 CET 2021\n\ntransform phm-transform.json...\n22:37:45.303 [                   refine] GET /command/core/get-csrf-token (188ms)\n22:37:45.308 [                   refine] GET /command/core/get-models (5ms)\n22:37:45.324 [                   refine] POST /command/core/apply-operations (16ms)\nFile /home/felix/git/openrefine-batch/examples/powerhouse-museum/config/phm-transform.json has been successfully applied to project 2252508879578\n STARTED     ELAPSED %MEM %CPU   RSS\n22:37:25       00:34 11.9  175 1940600\n\n\n=== 5. Export phm-collection ===\n\nstarting time: Di 9. Nov 22:37:59 CET 2021\n\nexport to file phm-collection.tsv...\n22:37:59.944 [                   refine] GET /command/core/get-csrf-token (14620ms)\n22:37:59.947 [                   refine] GET /command/core/get-models (3ms)\n22:37:59.951 [                   refine] GET /command/core/get-all-project-metadata (4ms)\n22:37:59.954 [                   refine] POST /command/core/export-rows/phm-collection.tsv (3ms)\nExport to file /home/felix/git/openrefine-batch/examples/powerhouse-museum/output/phm-collection.tsv complete\n STARTED     ELAPSED %MEM %CPU   RSS\n22:37:25       00:38 12.4  181 2021388\n\n\noutput (number of lines / size in bytes):\n   75728 59431272 /home/felix/git/openrefine-batch/examples/powerhouse-museum/output/phm-collection.tsv\n\ncleanup...\n22:38:06.850 [           ProjectManager] Saving all modified projects ... (6896ms)\n22:38:10.014 [        project_utilities] Saved project '2252508879578' (3164ms)\n\n=== Statistics ===\n\nstarting time and run time of each step:\n                      Start process Di 9. Nov 22:37:25 CET 2021 (00:00:00)\n                  Launch OpenRefine Di 9. Nov 22:37:25 CET 2021 (00:00:08)\n                   Import all files Di 9. Nov 22:37:33 CET 2021 (00:00:11)\n         Prepare transform \u0026 export Di 9. Nov 22:37:44 CET 2021 (00:00:01)\n           Transform phm-collection Di 9. Nov 22:37:45 CET 2021 (00:00:14)\n              Export phm-collection Di 9. Nov 22:37:59 CET 2021 (00:00:11)\n                        End process Di 9. Nov 22:38:10 CET 2021 (00:00:00)\n\ntotal run time: 00:00:45 (hh:mm:ss)\nhighest memory load: 1974 MB\n```\n\n### Docker\n\nA variation of the shell script orchestrates a [docker container for OpenRefine](https://hub.docker.com/r/felixlohmeier/openrefine/) (server) and a [docker container for the python client](https://hub.docker.com/r/felixlohmeier/openrefine-client/) instead of native applications.\n\n**Install**\n\n1. Install [Docker](https://docs.docker.com/engine/installation/#on-linux)\n  * **a)** [configure Docker to start on boot](https://docs.docker.com/engine/installation/linux/linux-postinstall/#configure-docker-to-start-on-boot)\n  * or **b)** start Docker on demand each time you use the script: `sudo systemctl start docker`\n2. Download the script and grant file permissions to execute:\n```\nwget https://github.com/felixlohmeier/openrefine-batch/raw/master/openrefine-batch-docker.sh\nchmod +x openrefine-batch-docker.sh\n```\n\n**Usage**\n\n```\nmkdir input\ncp INPUTFILES input/\nmkdir config\ncp CONFIGFILES config/\n./openrefine-batch-docker.sh -a input/ -b config/ -c OUTPUT/\n```\n\nThe script may ask you for sudo privileges. Why `sudo`? Non-root users can only access the Unix socket of the Docker daemon by using `sudo`. If you created a Docker group in [Post-installation steps for Linux](https://docs.docker.com/engine/installation/linux/linux-postinstall/) then you may call the script without `sudo`.\n\n**Example**\n\n[Example Powerhouse Museum](examples/powerhouse-museum)\n\ndownload example data\n\n```\nwget https://github.com/opencultureconsulting/openrefine-batch/archive/master.zip\nunzip master.zip openrefine-batch-master/examples/*\nmv openrefine-batch-master/examples .\nrm -f master.zip\n```\n\nexecute openrefine-batch-docker.sh\n\n```\n./openrefine-batch-docker.sh \\\n-a examples/powerhouse-museum/input/ \\\n-b examples/powerhouse-museum/config/ \\\n-c examples/powerhouse-museum/output/ \\\n-f tsv \\\n-i processQuotes=false \\\n-i guessCellValueTypes=true \\\n-RX\n```\n\n### Licensing\n\nMIT License\n\nCopyright (c) 2017 Felix Lohmeier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopencultureconsulting%2Fopenrefine-batch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopencultureconsulting%2Fopenrefine-batch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopencultureconsulting%2Fopenrefine-batch/lists"}