From d66b75671dfa38d6db62080c8a273e23402fd9bb Mon Sep 17 00:00:00 2001 From: prance Date: Sun, 30 Jan 2022 23:08:52 +0100 Subject: [PATCH] add OpenRefine --- OpenRefine/.gitattributes | 22 + OpenRefine/.gitignore | 72 + OpenRefine/CODE_OF_CONDUCT.md | 82 + OpenRefine/CONTRIBUTING.md | 62 + OpenRefine/Dockerfile | 19 + OpenRefine/GOVERNANCE.md | 128 + OpenRefine/IDEs/eclipse/README.txt | 29 + .../IDEs/eclipse/Refine-codetemplates.xml | 62 + OpenRefine/IDEs/eclipse/Refine.style.xml | 390 + OpenRefine/LICENSE.txt | 11 + OpenRefine/README.md | 65 + OpenRefine/SECURITY.md | 18 + OpenRefine/appveyor.yml | 63 + OpenRefine/benchmark/pom.xml | 159 + .../benchmark/ToNumberBenchmark.java | 94 + OpenRefine/conf/openrefine.l4j.ini | 13 + OpenRefine/conf/pmd.rules.xml | 32 + OpenRefine/docs/.gitignore | 24 + OpenRefine/docs/.node-version | 1 + OpenRefine/docs/README.md | 106 + OpenRefine/docs/crowdin.yml | 16 + OpenRefine/docs/docs/index.md | 25 + OpenRefine/docs/docs/manual/cellediting.md | 165 + OpenRefine/docs/docs/manual/columnediting.md | 124 + OpenRefine/docs/docs/manual/exploring.md | 116 + OpenRefine/docs/docs/manual/exporting.md | 134 + OpenRefine/docs/docs/manual/expressions.md | 208 + OpenRefine/docs/docs/manual/facets.md | 329 + OpenRefine/docs/docs/manual/grel.md | 154 + OpenRefine/docs/docs/manual/grelfunctions.md | 535 + OpenRefine/docs/docs/manual/installing.md | 425 + OpenRefine/docs/docs/manual/jythonclojure.md | 76 + OpenRefine/docs/docs/manual/reconciling.md | 242 + OpenRefine/docs/docs/manual/running.md | 509 + OpenRefine/docs/docs/manual/sortview.md | 41 + OpenRefine/docs/docs/manual/starting.md | 194 + OpenRefine/docs/docs/manual/transforming.md | 34 + OpenRefine/docs/docs/manual/transposing.md | 234 + .../docs/docs/manual/troubleshooting.md | 31 + .../docs/manual/wikibase/advanced-schemas.md | 72 + .../docs/manual/wikibase/configuration.md | 149 + .../docs/docs/manual/wikibase/new-entities.md | 104 + .../docs/docs/manual/wikibase/overview.md | 134 + .../docs/manual/wikibase/quality-assurance.md | 48 + .../docs/docs/manual/wikibase/reconciling.md | 45 + .../docs/manual/wikibase/schema-alignment.md | 253 + .../docs/docs/manual/wikibase/uploading.md | 48 + .../docs/technical-reference/architecture.md | 283 + .../technical-reference/build-test-run.md | 283 + .../docs/technical-reference/contributing.md | 70 + .../development-roadmap.md | 29 + .../technical-reference/functional-tests.md | 241 + .../homebrew-cask-process.md | 5 + .../maintainer-guidelines.md | 89 + .../migrating-older-extensions.md | 169 + .../technical-reference/openrefine-api.md | 285 + .../technical-reference/reconciliation-api.md | 24 + .../technical-reference-index.md | 7 + .../technical-reference/translating-docs.md | 19 + .../technical-reference/translating-ui.md | 105 + .../version-release-process.md | 51 + .../technical-reference/writing-extensions.md | 326 + OpenRefine/docs/docusaurus.config.js | 129 + OpenRefine/docs/netlify.toml | 9 + OpenRefine/docs/package.json | 25 + OpenRefine/docs/sidebars.js | 53 + OpenRefine/docs/src/css/custom.css | 87 + OpenRefine/docs/src/theme/Footer/Footer.js | 108 + OpenRefine/docs/static/css/custom.css | 2 + OpenRefine/docs/static/img/cluster.png | Bin 0 -> 52046 bytes OpenRefine/docs/static/img/columnjoin.png | Bin 0 -> 27571 bytes .../docs/static/img/columnreconciled.png | Bin 0 -> 27385 bytes OpenRefine/docs/static/img/columnsplit.png | Bin 0 -> 14243 bytes .../static/img/custom-tabular-exporter.png | Bin 0 -> 31746 bytes .../static/img/custom-tabular-exporter2.png | Bin 0 -> 14785 bytes OpenRefine/docs/static/img/dates.png | Bin 0 -> 19303 bytes .../docs/static/img/eclipse-debug-config.png | Bin 0 -> 49671 bytes .../docs/static/img/eclipse-exec-config.png | Bin 0 -> 83776 bytes .../img/eclipse-import-maven-project-1.png | Bin 0 -> 32942 bytes .../img/eclipse-import-maven-project-2.png | Bin 0 -> 57614 bytes OpenRefine/docs/static/img/env.png | Bin 0 -> 48149 bytes OpenRefine/docs/static/img/error.png | Bin 0 -> 10132 bytes OpenRefine/docs/static/img/export-menu.png | Bin 0 -> 12993 bytes .../docs/static/img/expression-editor.png | Bin 0 -> 16230 bytes OpenRefine/docs/static/img/facetfilter.png | Bin 0 -> 14301 bytes .../docs/static/img/failed-visual-test.png | Bin 0 -> 34013 bytes OpenRefine/docs/static/img/fetchingURLs.png | Bin 0 -> 48979 bytes OpenRefine/docs/static/img/goto.png | Bin 0 -> 18361 bytes OpenRefine/docs/static/img/history.png | Bin 0 -> 20196 bytes OpenRefine/docs/static/img/intellij-maven.png | Bin 0 -> 42942 bytes .../static/img/intellij-module-settings.png | Bin 0 -> 65333 bytes .../img/intellij-open-module-settings.png | Bin 0 -> 78009 bytes .../docs/static/img/intellij-setup-1.png | Bin 0 -> 21858 bytes OpenRefine/docs/static/img/javahome.png | Bin 0 -> 36817 bytes OpenRefine/docs/static/img/null.png | Bin 0 -> 2094 bytes OpenRefine/docs/static/img/numericfacet.png | Bin 0 -> 3497 bytes .../docs/static/img/numericlogfacet.png | Bin 0 -> 5310 bytes .../docs/static/img/openrefine_logo.png | Bin 0 -> 5416 bytes OpenRefine/docs/static/img/projectscreen.png | Bin 0 -> 43634 bytes .../docs/static/img/reconcile-ambiguous.gif | Bin 0 -> 88589 bytes .../docs/static/img/reconcile-by-type.png | Bin 0 -> 20606 bytes .../static/img/reconcile-with-property.png | Bin 0 -> 23650 bytes OpenRefine/docs/static/img/reconcileGND.png | Bin 0 -> 17458 bytes .../docs/static/img/reconcileIDerror.png | Bin 0 -> 29855 bytes OpenRefine/docs/static/img/reconcileParis.gif | Bin 0 -> 161961 bytes .../docs/static/img/reconcileelements.gif | Bin 0 -> 243942 bytes OpenRefine/docs/static/img/reconcilehover.png | Bin 0 -> 67374 bytes .../docs/static/img/reconcilewindow.png | Bin 0 -> 19124 bytes .../docs/static/img/reconcilewindow2.png | Bin 0 -> 25699 bytes OpenRefine/docs/static/img/scatterplot.png | Bin 0 -> 5943 bytes OpenRefine/docs/static/img/sort.png | Bin 0 -> 10893 bytes OpenRefine/docs/static/img/sort2.png | Bin 0 -> 62508 bytes OpenRefine/docs/static/img/sortPermanent.png | Bin 0 -> 23003 bytes OpenRefine/docs/static/img/sql-exporter.png | Bin 0 -> 30379 bytes OpenRefine/docs/static/img/sql-exporter2.png | Bin 0 -> 11149 bytes .../docs/static/img/templating-exporter.png | Bin 0 -> 43498 bytes OpenRefine/docs/static/img/timelinefacet.png | Bin 0 -> 4290 bytes OpenRefine/docs/static/img/transpose1.png | Bin 0 -> 23886 bytes OpenRefine/docs/static/img/transpose2.png | Bin 0 -> 13029 bytes OpenRefine/docs/static/img/unicodefacet.png | Bin 0 -> 2892 bytes .../img/visual-test-cypress-failure.png | Bin 0 -> 68003 bytes OpenRefine/docs/static/img/wikidata-login.png | Bin 0 -> 11745 bytes .../docs/static/img/wikidata-schema.png | Bin 0 -> 39416 bytes OpenRefine/docs/static/img/wikidata-terms.png | Bin 0 -> 24677 bytes .../docs/static/img/wikidata-terms2.png | Bin 0 -> 7336 bytes .../docs/static/img/wikidata-translated.png | Bin 0 -> 7820 bytes OpenRefine/docs/static/img/yeardata.png | Bin 0 -> 21833 bytes OpenRefine/docs/static/js/fix-location.js | 8 + .../docs/versioned_docs/version-3.4/index.md | 25 + .../version-3.4/manual/cellediting.md | 165 + .../version-3.4/manual/columnediting.md | 124 + .../version-3.4/manual/exploring.md | 116 + .../version-3.4/manual/exporting.md | 134 + .../version-3.4/manual/expressions.md | 208 + .../version-3.4/manual/facets.md | 325 + .../versioned_docs/version-3.4/manual/grel.md | 154 + .../version-3.4/manual/grelfunctions.md | 531 + .../version-3.4/manual/installing.md | 425 + .../version-3.4/manual/jythonclojure.md | 76 + .../version-3.4/manual/reconciling.md | 247 + .../version-3.4/manual/running.md | 506 + .../version-3.4/manual/sortview.md | 35 + .../version-3.4/manual/starting.md | 194 + .../version-3.4/manual/transforming.md | 34 + .../version-3.4/manual/transposing.md | 234 + .../version-3.4/manual/troubleshooting.md | 31 + .../version-3.4/manual/wikidata.md | 190 + .../technical-reference/architecture.md | 283 + .../technical-reference/build-test-run.md | 270 + .../technical-reference/contributing.md | 69 + .../technical-reference/data-extension-api.md | 261 + .../development-roadmap.md | 29 + .../technical-reference/functional-tests.md | 239 + .../homebrew-cask-process.md | 29 + .../migrating-older-extensions.md | 169 + .../technical-reference/openrefine-api.md | 281 + .../technical-reference/reconciliation-api.md | 259 + .../technical-reference/suggest-api.md | 101 + .../technical-reference-index.md | 7 + .../technical-reference/translating.md | 105 + .../version-release-process.md | 5 + .../technical-reference/writing-extensions.md | 326 + .../docs/versioned_docs/version-3.5/index.md | 25 + .../version-3.5/manual/cellediting.md | 165 + .../version-3.5/manual/columnediting.md | 124 + .../version-3.5/manual/exploring.md | 116 + .../version-3.5/manual/exporting.md | 134 + .../version-3.5/manual/expressions.md | 208 + .../version-3.5/manual/facets.md | 329 + .../versioned_docs/version-3.5/manual/grel.md | 154 + .../version-3.5/manual/grelfunctions.md | 535 + .../version-3.5/manual/installing.md | 425 + .../version-3.5/manual/jythonclojure.md | 76 + .../version-3.5/manual/reconciling.md | 242 + .../version-3.5/manual/running.md | 509 + .../version-3.5/manual/sortview.md | 41 + .../version-3.5/manual/starting.md | 194 + .../version-3.5/manual/transforming.md | 34 + .../version-3.5/manual/transposing.md | 234 + .../version-3.5/manual/troubleshooting.md | 31 + .../manual/wikibase/advanced-schemas.md | 72 + .../manual/wikibase/configuration.md | 149 + .../manual/wikibase/new-entities.md | 104 + .../version-3.5/manual/wikibase/overview.md | 134 + .../manual/wikibase/quality-assurance.md | 48 + .../manual/wikibase/reconciling.md | 45 + .../manual/wikibase/schema-alignment.md | 253 + .../version-3.5/manual/wikibase/uploading.md | 48 + .../technical-reference/architecture.md | 283 + .../technical-reference/build-test-run.md | 283 + .../technical-reference/contributing.md | 70 + .../development-roadmap.md | 29 + .../technical-reference/functional-tests.md | 241 + .../homebrew-cask-process.md | 5 + .../maintainer-guidelines.md | 89 + .../migrating-older-extensions.md | 169 + .../technical-reference/openrefine-api.md | 285 + .../technical-reference/reconciliation-api.md | 24 + .../technical-reference-index.md | 7 + .../technical-reference/translating-docs.md | 19 + .../technical-reference/translating-ui.md | 105 + .../version-release-process.md | 51 + .../technical-reference/writing-extensions.md | 326 + .../version-3.4-sidebars.json | 186 + .../version-3.5-sidebars.json | 217 + OpenRefine/docs/versions.json | 4 + OpenRefine/docs/yarn.lock | 9509 + OpenRefine/extensions/database/.eclipse-pmd | 4 + OpenRefine/extensions/database/.eslintrc.json | 28 + OpenRefine/extensions/database/.travis.yml | 24 + OpenRefine/extensions/database/README.md | 9 + .../database/licenses/jdbc-client.LICENSE.txt | 188 + .../database/module/MOD-INF/.gitignore | 1 + .../database/module/MOD-INF/controller.js | 146 + .../module/MOD-INF/dbextension.properties | 3 + .../database/module/MOD-INF/module.properties | 7 + .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../module/images/more-option-horiz-16.png | Bin 0 -> 221 bytes .../module/images/more_option-vert-16.png | Bin 0 -> 220 bytes .../extensions/database/module/index.vt | 20 + .../database/module/langs/translation-bn.json | 4 + .../database/module/langs/translation-cs.json | 64 + .../database/module/langs/translation-en.json | 66 + .../module/langs/translation-en_GB.json | 53 + .../database/module/langs/translation-eu.json | 1 + .../database/module/langs/translation-fr.json | 65 + .../database/module/langs/translation-he.json | 65 + .../database/module/langs/translation-id.json | 64 + .../database/module/langs/translation-it.json | 64 + .../database/module/langs/translation-jp.json | 64 + .../database/module/langs/translation-ko.json | 49 + .../database/module/langs/translation-ml.json | 15 + .../module/langs/translation-nb_NO.json | 51 + .../database/module/langs/translation-pl.json | 64 + .../database/module/langs/translation-pt.json | 64 + .../module/langs/translation-pt_BR.json | 63 + .../database/module/langs/translation-sv.json | 59 + .../database/module/langs/translation-tr.json | 65 + .../module/langs/translation-zh_Hans.json | 21 + .../extensions/database/module/macros.vm | 14 + .../module/scripts/database-extension.js | 168 + .../index/database-import-controller.js | 399 + .../scripts/index/database-import-form.html | 142 + .../scripts/index/database-parsing-panel.html | 58 + .../scripts/index/database-source-ui.js | 528 + .../scripts/index/jquery.contextMenu.min.js | 2 + .../scripts/index/jquery.ui.position.min.js | 6 + .../scripts/project/database-exporters.js | 49 + .../database/module/styles/bootstrap.css | 1701 + .../module/styles/database-import.less | 143 + .../module/styles/jquery.contextMenu.css | 292 + .../database/module/styles/pure.css | 1549 + .../database/module/styles/theme.less | 30 + OpenRefine/extensions/database/pom.xml | 150 + .../database/DBQueryResultImportReader.java | 287 + .../database/DBQueryResultPreviewReader.java | 270 + .../database/DatabaseColumnType.java | 43 + .../database/DatabaseConfiguration.java | 131 + .../database/DatabaseImportController.java | 490 + .../database/DatabaseModuleImpl.java | 133 + .../extension/database/DatabaseService.java | 156 + .../database/DatabaseServiceException.java | 90 + .../extension/database/DatabaseUtils.java | 389 + .../refine/extension/database/SQLType.java | 101 + .../database/SavedConnectionContainer.java | 58 + .../database/SimpleTextEncryptor.java | 76 + .../database/cmd/ConnectCommand.java | 109 + .../database/cmd/DatabaseCommand.java | 115 + .../database/cmd/ExecuteQueryCommand.java | 120 + .../database/cmd/SavedConnectionCommand.java | 358 + .../database/cmd/TestConnectCommand.java | 109 + .../database/cmd/TestQueryCommand.java | 120 + .../mariadb/MariaDBConnectionManager.java | 186 + .../mariadb/MariaDBDatabaseService.java | 245 + .../database/model/DatabaseColumn.java | 109 + .../database/model/DatabaseInfo.java | 135 + .../database/model/DatabaseQueryInfo.java | 67 + .../extension/database/model/DatabaseRow.java | 62 + .../database/model/DatabaseTable.java | 73 + .../mysql/MySQLConnectionManager.java | 183 + .../database/mysql/MySQLDatabaseService.java | 250 + .../pgsql/PgSQLConnectionManager.java | 185 + .../database/pgsql/PgSQLDatabaseService.java | 246 + .../sqlite/SQLiteConnectionManager.java | 140 + .../sqlite/SQLiteDatabaseService.java | 229 + .../database/tests/conf/appveyor_tests.xml | 60 + .../tests/conf/github_actions_tests.xml | 55 + .../database/tests/conf/test-mariadb.sql | 18 + .../database/tests/conf/test-mysql.sql | 17 + .../database/tests/conf/test-pgsql.sql | 17 + .../database/tests/conf/test-sqlite.sql | 15 + .../extensions/database/tests/conf/tests.xml | 52 + .../database/tests/log4j-test.properties | 5 + .../database/DBExtensionTestUtils.java | 439 + .../extension/database/DBExtensionTests.java | 72 + .../DatabaseImportControllerTest.java | 247 + .../database/DatabaseServiceTest.java | 149 + .../database/InitMariaDBTestDatabase.java | 44 + .../database/InitMySQLTestDatabase.java | 44 + .../database/InitPostgresTestDatabase.java | 43 + .../database/InitSQLiteTestDatabase.java | 33 + .../database/SimpleTextEncryptorTest.java | 29 + .../database/cmd/ConnectCommandTest.java | 110 + .../database/cmd/ExecuteQueryCommandTest.java | 110 + .../cmd/SavedConnectionCommandTest.java | 337 + .../database/cmd/TestConnectCommandTest.java | 109 + .../database/cmd/TestQueryCommandTest.java | 112 + .../mariadb/MariaDBConnectionManagerTest.java | 73 + .../mariadb/MariaDBDatabaseServiceTest.java | 130 + .../mysql/MySQLConnectionManagerTest.java | 75 + .../mysql/MySQLDatabaseServiceTest.java | 129 + .../pgsql/PgSQLConnectionManagerTest.java | 76 + .../pgsql/PgSQLDatabaseServiceTest.java | 131 + .../sqlite/SQLiteConnectionManagerTest.java | 99 + .../sqlite/SQLiteDatabaseServiceTest.java | 160 + .../database/stub/RefineDbServletStub.java | 97 + OpenRefine/extensions/gdata/LICENSE.txt | 75 + OpenRefine/extensions/gdata/README.txt | 23 + .../gdata/module/MOD-INF/controller.js | 130 + .../gdata/module/MOD-INF/module.properties | 4 + .../extensions/gdata/module/authorize.vt | 46 + .../extensions/gdata/module/authorized.vt | 62 + OpenRefine/extensions/gdata/module/index.vt | 22 + .../gdata/module/langs/translation-bn.json | 25 + .../gdata/module/langs/translation-bn_IN.json | 1 + .../gdata/module/langs/translation-cs.json | 47 + .../gdata/module/langs/translation-en.json | 48 + .../gdata/module/langs/translation-en_GB.json | 6 + .../gdata/module/langs/translation-es.json | 51 + .../gdata/module/langs/translation-fr.json | 53 + .../gdata/module/langs/translation-he.json | 52 + .../gdata/module/langs/translation-it.json | 50 + .../gdata/module/langs/translation-jp.json | 52 + .../gdata/module/langs/translation-ko.json | 45 + .../gdata/module/langs/translation-nb_NO.json | 49 + .../gdata/module/langs/translation-pl.json | 18 + .../gdata/module/langs/translation-pt.json | 51 + .../gdata/module/langs/translation-pt_BR.json | 49 + .../gdata/module/langs/translation-pt_PT.json | 51 + .../gdata/module/langs/translation-sv.json | 45 + OpenRefine/extensions/gdata/module/macros.vm | 14 + .../gdata/module/scripts/gdata-extension.js | 63 + .../scripts/index/gdata-parsing-panel.html | 56 + .../module/scripts/index/gdata-source-ui.js | 197 + .../scripts/index/import-from-gdata-form.html | 30 + .../scripts/index/importing-controller.js | 453 + .../gdata/module/scripts/project/exporters.js | 177 + .../module/styles/importing-controller.less | 110 + .../module/styles/project-injection.less | 38 + .../extensions/gdata/module/styles/theme.less | 34 + OpenRefine/extensions/gdata/pom.xml | 115 + .../extension/gdata/DeAuthorizeCommand.java | 75 + .../refine/extension/gdata/GDataImporter.java | 221 + .../gdata/GDataImportingController.java | 351 + .../extension/gdata/GoogleAPIExtension.java | 253 + .../gdata/SpreadsheetSerializer.java | 163 + .../refine/extension/gdata/TokenCookie.java | 28 + .../refine/extension/gdata/UploadCommand.java | 220 + .../extension/gdata/logo-openrefine-550.png | Bin 0 -> 58994 bytes .../extensions/gdata/tests/conf/tests.xml | 14 + .../gdata/GoogleAPIExtensionTest.java | 38 + .../gdata/SpreadsheetSerializerTests.java | 121 + .../extension/gdata/UploadCommandTest.java | 66 + OpenRefine/extensions/jython/.gitignore | 4 + .../jython/module/MOD-INF/controller.js | 52 + .../jython/module/MOD-INF/module.properties | 4 + OpenRefine/extensions/jython/pom.xml | 90 + .../google/refine/jython/JythonEvaluable.java | 178 + .../refine/jython/JythonHasFieldsWrapper.java | 78 + .../refine/jython/JythonObjectWrapper.java | 51 + .../extensions/jython/tests/conf/tests.xml | 14 + .../refine/jython/JythonAttributeTest.java | 51 + .../refine/jython/JythonEvaluableTest.java | 83 + .../jython/tests/src/tests.log4j.properties | 4 + .../pc-axis/module/MOD-INF/controller.js | 59 + .../pc-axis/module/MOD-INF/module.properties | 4 + .../pc-axis/module/langs/translation-en.json | 3 + .../module/scripts/pc-axis-parser-ui.html | 37 + .../module/scripts/pc-axis-parser-ui.js | 189 + OpenRefine/extensions/pc-axis/pom.xml | 79 + .../google/refine/pcaxis/PCAxisImporter.java | 93 + .../refine/pcaxis/PCAxisTableDataReader.java | 273 + OpenRefine/extensions/phonetic/.gitignore | 1 + .../phonetic/module/MOD-INF/controller.js | 60 + .../phonetic/module/MOD-INF/module.properties | 4 + .../phonetic/module/langs/translation-en.json | 4 + .../extensions/phonetic/module/macros.vm | 14 + .../phonetic/module/scripts/load-language.js | 19 + OpenRefine/extensions/phonetic/pom.xml | 84 + .../phonetic/keyers/BeiderMorseKeyer.java | 32 + .../phonetic/keyers/DaitchMokotoffKeyer.java | 15 + .../extensions/phonetic/tests/conf/tests.xml | 14 + .../phonetic/keyers/BeiderMorseKeyerTest.java | 29 + .../keyers/DaitchMokotoffKeyerTest.java | 28 + OpenRefine/extensions/pom.xml | 101 + OpenRefine/extensions/sample/.gitignore | 1 + .../sample/module/MOD-INF/controller.js | 83 + .../sample/module/MOD-INF/module.properties | 4 + OpenRefine/extensions/sample/module/index.vt | 23 + OpenRefine/extensions/sample/module/macros.vm | 14 + .../module/scripts/project-injection.js | 36 + .../module/styles/project-injection.less | 38 + OpenRefine/extensions/sample/pom.xml | 73 + .../refine/sampleExtension/SampleUtil.java | 8 + OpenRefine/extensions/wikidata/.gitignore | 3 + OpenRefine/extensions/wikidata/credits.txt | 32 + .../wikidata/module/MOD-INF/controller.js | 92 + .../wikidata/module/MOD-INF/module.properties | 3 + .../wikidata/module/images/Critical.png | Bin 0 -> 2260 bytes .../wikidata/module/images/Critical.svg | 269 + .../wikidata/module/images/Important.png | Bin 0 -> 2567 bytes .../wikidata/module/images/Important.svg | 269 + .../wikidata/module/images/Information.png | Bin 0 -> 4297 bytes .../wikidata/module/images/Information.svg | 252 + .../wikidata/module/images/Warning.png | Bin 0 -> 3836 bytes .../wikidata/module/images/Warning.svg | 348 + .../wikidata/module/images/Wikibase_logo.png | Bin 0 -> 81729 bytes .../module/images/Wikidata-logo-en.svg | 7 + .../wikidata/module/images/close-map.png | Bin 0 -> 1022 bytes .../wikidata/module/images/wikidata.png | Bin 0 -> 24431 bytes .../wikidata/module/langs/translation-bn.json | 50 + .../wikidata/module/langs/translation-cs.json | 107 + .../wikidata/module/langs/translation-en.json | 229 + .../module/langs/translation-en_GB.json | 186 + .../wikidata/module/langs/translation-es.json | 228 + .../wikidata/module/langs/translation-fi.json | 117 + .../wikidata/module/langs/translation-fr.json | 224 + .../wikidata/module/langs/translation-he.json | 60 + .../wikidata/module/langs/translation-id.json | 68 + .../wikidata/module/langs/translation-it.json | 157 + .../wikidata/module/langs/translation-jp.json | 257 + .../wikidata/module/langs/translation-ko.json | 87 + .../wikidata/module/langs/translation-ml.json | 12 + .../module/langs/translation-nb_NO.json | 172 + .../wikidata/module/langs/translation-nl.json | 95 + .../wikidata/module/langs/translation-pl.json | 61 + .../wikidata/module/langs/translation-pt.json | 14 + .../module/langs/translation-pt_BR.json | 14 + .../wikidata/module/langs/translation-sv.json | 158 + .../wikidata/module/scripts/ajv.min.js | 3 + .../wikidata/module/scripts/bettersuggest.js | 22 + .../scripts/dialogs/add-wikibase-dialog.html | 21 + .../scripts/dialogs/import-schema-dialog.html | 13 + .../scripts/dialogs/import-schema-dialog.js | 73 + .../scripts/dialogs/logged-in-dialog.html | 23 + .../scripts/dialogs/manage-account-dialog.js | 236 + .../owner-only-consumer-login-dialog.html | 53 + .../dialogs/password-login-dialog.html | 47 + .../scripts/dialogs/perform-edits-dialog.html | 36 + .../scripts/dialogs/perform-edits-dialog.js | 145 + .../scripts/dialogs/wikibase-dialog.html | 18 + .../module/scripts/dialogs/wikibase-dialog.js | 145 + .../wikidata/module/scripts/issues-tab.html | 5 + .../module/scripts/jquery.uls.data.js | 11 + .../wikidata/module/scripts/langsuggest.js | 126 + .../module/scripts/menu-bar-extension.js | 153 + .../wikidata/module/scripts/preview-tab.html | 6 + .../module/scripts/previewrenderer.js | 262 + .../module/scripts/schema-alignment-tab.html | 17 + .../module/scripts/schema-alignment.js | 1407 + .../module/scripts/warningsrenderer.js | 75 + .../module/scripts/wikibase-manager.js | 327 + .../scripts/wikibase-manifest-schema-v1.js | 126 + .../scripts/wikibase-manifest-schema-v2.js | 142 + .../module/scripts/wikibase-suggest.js | 142 + .../scripts/wikidata-extension-manager.js | 6 + .../module/scripts/wikidata-manifest-v1.0.js | 92 + .../styles/dialogs/add-wikibase-dialog.less | 19 + .../styles/dialogs/import-schema-dialog.less | 11 + .../styles/dialogs/manage-account-dialog.less | 89 + .../module/styles/dialogs/perform-edits.less | 61 + .../styles/dialogs/wikibase-dialog.less | 53 + .../module/styles/schema-alignment.less | 567 + .../wikidata/module/styles/theme.less | 34 + OpenRefine/extensions/wikidata/pom.xml | 137 + .../wikidata/commands/CommandUtilities.java | 36 + .../wikidata/commands/ConnectionManager.java | 215 + .../wikidata/commands/LoginCommand.java | 291 + .../commands/PerformWikibaseEditsCommand.java | 47 + .../wikidata/commands/PreviewResults.java | 68 + .../PreviewWikibaseSchemaCommand.java | 131 + .../commands/SaveWikibaseSchemaCommand.java | 80 + .../wikidata/editing/EditBatchProcessor.java | 284 + .../wikidata/editing/NewItemLibrary.java | 179 + .../wikidata/editing/ReconEntityRewriter.java | 183 + .../wikidata/exporters/QSSnakPrinter.java | 52 + .../wikidata/exporters/QSValuePrinter.java | 105 + .../exporters/QuickStatementsExporter.java | 200 + .../wikidata/exporters/SchemaExporter.java | 30 + .../wikidata/manifests/Manifest.java | 104 + .../wikidata/manifests/ManifestException.java | 12 + .../wikidata/manifests/ManifestParser.java | 49 + .../wikidata/manifests/ManifestV1.java | 133 + .../wikidata/manifests/ManifestV2.java | 162 + .../PerformWikibaseEditsOperation.java | 273 + .../SaveWikibaseSchemaOperation.java | 142 + .../openrefine/wikidata/qa/Constraint.java | 52 + .../wikidata/qa/ConstraintFetcher.java | 92 + .../openrefine/wikidata/qa/EditInspector.java | 157 + .../org/openrefine/wikidata/qa/QAWarning.java | 165 + .../wikidata/qa/QAWarningStore.java | 99 + .../wikidata/qa/SchemaPropertyExtractor.java | 52 + .../qa/scrutinizers/CalendarScrutinizer.java | 35 + .../CommonDescriptionScrutinizer.java | 64 + .../ConflictsWithScrutinizer.java | 112 + .../scrutinizers/DescriptionScrutinizer.java | 33 + .../DifferenceWithinRangeScrutinizer.java | 119 + .../DistinctValuesScrutinizer.java | 87 + .../qa/scrutinizers/EditScrutinizer.java | 166 + .../EnglishDescriptionScrutinizer.java | 78 + .../scrutinizers/EntityTypeScrutinizer.java | 49 + .../qa/scrutinizers/FormatScrutinizer.java | 144 + .../InverseConstraintScrutinizer.java | 165 + .../scrutinizers/ItemRequiresScrutinizer.java | 118 + .../scrutinizers/MultiValueScrutinizer.java | 59 + .../qa/scrutinizers/NewItemScrutinizer.java | 88 + .../scrutinizers/NoEditsMadeScrutinizer.java | 56 + .../QualifierCompatibilityScrutinizer.java | 168 + .../qa/scrutinizers/QuantityScrutinizer.java | 105 + .../RestrictedPositionScrutinizer.java | 127 + .../RestrictedValuesScrutinizer.java | 85 + .../SelfReferentialScrutinizer.java | 55 + .../scrutinizers/SingleValueScrutinizer.java | 77 + .../qa/scrutinizers/SnakScrutinizer.java | 74 + .../qa/scrutinizers/StatementScrutinizer.java | 55 + .../qa/scrutinizers/UnsourcedScrutinizer.java | 71 + .../UseAsQualifierScrutinizer.java | 100 + .../qa/scrutinizers/ValueScrutinizer.java | 65 + .../scrutinizers/WhitespaceScrutinizer.java | 86 + .../wikidata/schema/ExpressionContext.java | 132 + .../wikidata/schema/WbDateConstant.java | 206 + .../wikidata/schema/WbDateVariable.java | 76 + .../schema/WbEntityIdValueConstant.java | 59 + .../wikidata/schema/WbEntityVariable.java | 104 + .../wikidata/schema/WbExpression.java | 62 + .../wikidata/schema/WbItemConstant.java | 77 + .../wikidata/schema/WbItemDocumentExpr.java | 122 + .../wikidata/schema/WbItemVariable.java | 80 + .../wikidata/schema/WbLanguageConstant.java | 115 + .../wikidata/schema/WbLanguageVariable.java | 76 + .../wikidata/schema/WbLocationConstant.java | 114 + .../wikidata/schema/WbLocationVariable.java | 69 + .../wikidata/schema/WbMonolingualExpr.java | 89 + .../wikidata/schema/WbNameDescExpr.java | 118 + .../wikidata/schema/WbPropConstant.java | 89 + .../wikidata/schema/WbQuantityExpr.java | 110 + .../wikidata/schema/WbReferenceExpr.java | 97 + .../wikidata/schema/WbSnakExpr.java | 91 + .../wikidata/schema/WbStatementExpr.java | 160 + .../wikidata/schema/WbStatementGroupExpr.java | 99 + .../wikidata/schema/WbStringConstant.java | 67 + .../wikidata/schema/WbStringVariable.java | 73 + .../wikidata/schema/WbVariableExpr.java | 124 + .../wikidata/schema/WikibaseSchema.java | 236 + .../FullyPropertySerializingValueSnak.java | 29 + .../entityvalues/PrefetchedEntityIdValue.java | 64 + .../entityvalues/ReconEntityIdValue.java | 173 + .../schema/entityvalues/ReconItemIdValue.java | 46 + .../entityvalues/ReconMediaInfoIdValue.java | 46 + .../entityvalues/ReconPropertyIdValue.java | 45 + .../entityvalues/SuggestedEntityIdValue.java | 135 + .../entityvalues/SuggestedFormIdValue.java | 32 + .../entityvalues/SuggestedItemIdValue.java | 39 + .../entityvalues/SuggestedLexemeIdValue.java | 15 + .../SuggestedMediaInfoIdValue.java | 45 + .../SuggestedPropertyIdValue.java | 44 + .../entityvalues/SuggestedSenseIdValue.java | 35 + .../exceptions/InvalidSchemaException.java | 29 + .../NewItemNotCreatedYetException.java | 19 + .../SkipSchemaExpressionException.java | 29 + .../updates/TermedStatementEntityUpdate.java | 485 + .../TermedStatementEntityUpdateBuilder.java | 233 + .../ImpossibleSchedulingException.java | 30 + .../updates/scheduler/PointerExtractor.java | 169 + .../QuickStatementsUpdateScheduler.java | 144 + .../updates/scheduler/UpdateScheduler.java | 53 + .../updates/scheduler/UpdateSequence.java | 84 + .../scheduler/WikibaseAPIUpdateScheduler.java | 138 + .../wikidata/utils/EntityCache.java | 124 + .../wikidata/utils/LanguageCodeStore.java | 573 + .../openrefine/wikidata/utils/SnakUtils.java | 42 + .../wikidata/utils/StatementGroupJson.java | 42 + .../extensions/wikidata/tests/conf/tests.xml | 14 + .../data/entitycache/entitycache-P2427.json | 1 + .../data/entitycache/entitycache-P25.json | 1 + .../data/entitycache/entitycache-P31.json | 1 + .../data/entitycache/entitycache-P361.json | 1 + .../data/entitycache/entitycache-P571.json | 1 + .../data/entitycache/entitycache-P580.json | 1 + .../data/entitycache/entitycache-P6.json | 1 + .../data/entitycache/entitycache-P813.json | 1 + .../data/entitycache/entitycache-P854.json | 1 + .../wikidata-monolingualtext-langcode.json | 1 + .../data/manifest/commons-manifest-v2.0.json | 46 + ...-v1.0-missing-property-constraint-pid.json | 91 + ...ata-manifest-v1.0-without-constraints.json | 26 + .../data/manifest/wikidata-manifest-v1.0.json | 92 + .../tests/data/operations/perform-edits.json | 11 + .../tests/data/operations/save-schema.json | 36 + .../data/schema/history_of_medicine.json | 1 + .../history_of_medicine_normalized.json | 1 + .../wikidata/tests/data/schema/inception.json | 1 + .../wikidata/tests/data/schema/roarmap.json | 1 + .../tests/data/updates/statement_groups.json | 83 + .../wikidata/commands/CommandTest.java | 72 + .../commands/ConnectionManagerTests.java | 63 + .../wikidata/commands/LoginCommandTest.java | 538 + .../PreviewWikibaseSchemaCommandTest.java | 96 + .../SaveWikibaseSchemaCommandTest.java | 82 + .../wikidata/commands/SchemaCommandTest.java | 59 + .../editing/EditBatchProcessorTest.java | 234 + .../wikidata/editing/NewItemLibraryTest.java | 100 + .../editing/ReconEntityRewriterTest.java | 162 + .../wikidata/exporters/QSSnakPrinterTest.java | 41 + .../exporters/QSValuePrinterTest.java | 137 + .../QuickStatementsExporterTest.java | 206 + .../exporters/SchemaExporterTest.java | 31 + .../wikidata/manifests/ManifestTest.java | 109 + .../wikidata/operations/OperationTest.java | 96 + .../PerformWikibaseEditsOperationTest.java | 86 + .../SaveWikibaseSchemaOperationTest.java | 81 + .../wikidata/qa/ConstraintTest.java | 71 + .../wikidata/qa/EditInspectorTest.java | 39 + .../wikidata/qa/QAWarningStoreTest.java | 68 + .../openrefine/wikidata/qa/QAWarningTest.java | 66 + .../qa/SchemaPropertyExtractorTest.java | 52 + .../scrutinizers/CalendarScrutinizerTest.java | 39 + .../CommonDescriptionScrutinizerTest.java | 75 + .../ConflictsWithScrutinizerTest.java | 195 + .../DifferenceWithinScrutinizerTest.java | 104 + .../DistinctValuesScrutinizerTest.java | 104 + .../EnglishDescriptionScrutinizerTest.java | 68 + .../EntityTypeScrutinizerTest.java | 89 + .../scrutinizers/FormatScrutinizerTest.java | 141 + .../InverseConstraintScrutinizerTest.java | 127 + .../ItemRequiresScrutinizerTest.java | 151 + .../MultiValueScrutinizerTest.java | 97 + .../scrutinizers/NewItemScrutinizerTest.java | 86 + .../NoEditsMadeScrutinizerTest.java | 55 + ...QualifierCompatibilityScrutinizerTest.java | 147 + .../scrutinizers/QuantityScrutinizerTest.java | 250 + .../RestrictedPositionScrutinizerTest.java | 139 + .../RestrictedValuesScrutinizerTest.java | 124 + .../qa/scrutinizers/ScrutinizerTest.java | 154 + .../SelfReferentialScrutinizerTest.java | 51 + .../SingleValueScrutinizerTest.java | 95 + .../qa/scrutinizers/SnakScrutinizerTest.java | 64 + .../StatementScrutinizerTest.java | 40 + .../UnsourcedScrutinizerTest.java | 104 + .../UseAsQualifierScrutinizerTest.java | 103 + .../qa/scrutinizers/ValueScrutinizerTest.java | 49 + .../WhitespaceScrutinizerTest.java | 66 + .../schema/ExpressionContextTest.java | 65 + .../wikidata/schema/WbDateConstantTest.java | 164 + .../wikidata/schema/WbDateVariableTest.java | 95 + .../schema/WbEntityIdValueConstantTest.java | 25 + .../wikidata/schema/WbEntityVariableTest.java | 129 + .../wikidata/schema/WbExpressionTest.java | 153 + .../wikidata/schema/WbItemConstantTest.java | 46 + .../schema/WbItemDocumentExprTest.java | 107 + .../wikidata/schema/WbItemVariableTest.java | 104 + .../schema/WbLanguageConstantTest.java | 63 + .../schema/WbLanguageVariableTest.java | 63 + .../schema/WbLocationConstantTest.java | 93 + .../schema/WbLocationVariableTest.java | 83 + .../schema/WbMonolingualExprTest.java | 71 + .../wikidata/schema/WbNameDescExprTest.java | 99 + .../wikidata/schema/WbPropConstantTest.java | 46 + .../wikidata/schema/WbQuantityExprTest.java | 96 + .../wikidata/schema/WbReferenceExprTest.java | 89 + .../wikidata/schema/WbSnakExprTest.java | 59 + .../wikidata/schema/WbStatementExprTest.java | 173 + .../schema/WbStatementGroupExprTest.java | 101 + .../wikidata/schema/WbStringConstantTest.java | 33 + .../wikidata/schema/WbStringVariableTest.java | 111 + .../wikidata/schema/WbVariableTest.java | 98 + .../wikidata/schema/WikibaseSchemaTest.java | 171 + .../entityvalues/ReconEntityIdValueTest.java | 128 + .../SuggestedEntityIdValueTest.java | 30 + .../testing/JacksonSerializationTest.java | 71 + .../wikidata/testing/TestingData.java | 186 + .../wikidata/testing/WikidataRefineTest.java | 65 + .../wikidata/updates/ItemUpdateTest.java | 278 + .../scheduler/PointerExtractorTest.java | 115 + .../QuickStatementsUpdateSchedulerTest.java | 78 + .../scheduler/UpdateSchedulerTest.java | 108 + .../WikibaseAPIUpdateSchedulerTest.java | 75 + .../wikidata/utils/EntityCacheStub.java | 48 + .../wikidata/utils/EntityCacheTests.java | 88 + .../wikidata/utils/SnakUtilsTests.java | 40 + .../wikidata/tests/src/tests.log4j.properties | 4 + OpenRefine/graphics/big-check.psd | Bin 0 -> 29638 bytes OpenRefine/graphics/checks-map.psd | Bin 0 -> 35155 bytes OpenRefine/graphics/cop.psd | Bin 0 -> 349803 bytes .../dmg_background/dmg_background.png | Bin 0 -> 7337 bytes .../dmg_background/dmg_background.psd | Bin 0 -> 99760 bytes OpenRefine/graphics/edit-map.psd | Bin 0 -> 178118 bytes .../graphics/icon/open-refine-320px.png | Bin 0 -> 5946 bytes OpenRefine/graphics/icon/openrefine.icns | Bin 0 -> 43596 bytes OpenRefine/graphics/icon/openrefine.ico | Bin 0 -> 9527 bytes OpenRefine/graphics/menu-dropdown.psd | Bin 0 -> 33413 bytes OpenRefine/graphics/path-delimiter.psd | Bin 0 -> 49490 bytes OpenRefine/graphics/row-groups.png | Bin 0 -> 11946 bytes OpenRefine/graphics/slider-brackets.psd | Bin 0 -> 33998 bytes OpenRefine/graphics/small-checks.psd | Bin 0 -> 29910 bytes OpenRefine/graphics/star-flag-map.psd | Bin 0 -> 39103 bytes OpenRefine/graphics/star.psd | Bin 0 -> 157778 bytes OpenRefine/main/IDEs/eclipse/README.txt | 31 + OpenRefine/main/pom.xml | 384 + .../refine/ClientSideResourceManager.java | 124 + .../src/com/google/refine/HttpResponder.java | 43 + .../com/google/refine/LookupCacheManager.java | 136 + .../src/com/google/refine/ProjectManager.java | 615 + .../com/google/refine/ProjectMetadata.java | 376 + .../src/com/google/refine/RefineServlet.java | 399 + .../refine/browsing/DecoratedValue.java | 68 + .../com/google/refine/browsing/Engine.java | 202 + .../google/refine/browsing/EngineConfig.java | 76 + .../refine/browsing/FilteredRecords.java | 51 + .../google/refine/browsing/FilteredRows.java | 52 + .../google/refine/browsing/RecordFilter.java | 45 + .../google/refine/browsing/RecordVisitor.java | 52 + .../com/google/refine/browsing/RowFilter.java | 45 + .../google/refine/browsing/RowVisitor.java | 70 + .../google/refine/browsing/facets/Facet.java | 53 + .../refine/browsing/facets/FacetConfig.java | 68 + .../browsing/facets/FacetConfigResolver.java | 61 + .../refine/browsing/facets/ListFacet.java | 355 + .../browsing/facets/NominalFacetChoice.java | 54 + .../refine/browsing/facets/RangeFacet.java | 395 + .../facets/ScatterplotDrawingRowVisitor.java | 164 + .../browsing/facets/ScatterplotFacet.java | 579 + .../browsing/facets/TextSearchFacet.java | 190 + .../browsing/facets/TimeRangeFacet.java | 343 + .../browsing/filters/AllRowsRecordFilter.java | 57 + .../browsing/filters/AnyRowRecordFilter.java | 57 + ...lExpressionsNumberComparisonRowFilter.java | 119 + .../filters/ExpressionEqualRowFilter.java | 189 + .../ExpressionNumberComparisonRowFilter.java | 131 + .../ExpressionStringComparisonRowFilter.java | 108 + .../ExpressionTimeComparisonRowFilter.java | 87 + .../util/ConjunctiveFilteredRecords.java | 82 + .../util/ConjunctiveFilteredRows.java | 87 + .../util/ExpressionBasedRowEvaluable.java | 67 + .../util/ExpressionNominalValueGrouper.java | 246 + .../util/ExpressionNumericValueBinner.java | 181 + .../util/ExpressionTimeValueBinner.java | 179 + .../util/FilteredRecordsAsFilteredRows.java | 53 + .../refine/browsing/util/NumericBinIndex.java | 272 + .../browsing/util/NumericBinRecordIndex.java | 71 + .../browsing/util/NumericBinRowIndex.java | 66 + .../refine/browsing/util/RowEvaluable.java | 43 + .../util/RowVisitorAsRecordVisitor.java | 67 + .../refine/browsing/util/TimeBinIndex.java | 253 + .../browsing/util/TimeBinRecordIndex.java | 71 + .../refine/browsing/util/TimeBinRowIndex.java | 65 + .../refine/clustering/ClusteredEntry.java | 53 + .../google/refine/clustering/Clusterer.java | 57 + .../refine/clustering/ClustererConfig.java | 76 + .../clustering/binning/BinningClusterer.java | 252 + .../binning/ColognePhoneticKeyer.java | 51 + .../binning/DoubleMetaphoneKeyer.java | 52 + .../clustering/binning/FingerprintKeyer.java | 145 + .../refine/clustering/binning/Keyer.java | 45 + .../clustering/binning/KeyerFactory.java | 83 + .../refine/clustering/binning/Metaphone3.java | 7460 + .../clustering/binning/Metaphone3Keyer.java | 51 + .../clustering/binning/MetaphoneKeyer.java | 52 + .../binning/NGramFingerprintKeyer.java | 91 + .../clustering/binning/SoundexKeyer.java | 51 + .../clustering/knn/DistanceFactory.java | 93 + .../clustering/knn/SimilarityDistance.java | 44 + .../refine/clustering/knn/VicinoDistance.java | 50 + .../refine/clustering/knn/kNNClusterer.java | 275 + .../refine/commands/CSRFTokenFactory.java | 94 + .../com/google/refine/commands/Command.java | 412 + .../commands/EngineDependentCommand.java | 92 + .../commands/GetAllPreferencesCommand.java | 74 + .../refine/commands/GetCSRFTokenCommand.java | 18 + .../refine/commands/GetPreferenceCommand.java | 73 + .../refine/commands/GetVersionCommand.java | 71 + .../refine/commands/HttpHeadersSupport.java | 84 + .../google/refine/commands/HttpUtilities.java | 189 + .../commands/OpenWorkspaceDirCommand.java | 80 + .../refine/commands/SetPreferenceCommand.java | 77 + .../browsing/ComputeClustersCommand.java | 81 + .../browsing/ComputeFacetsCommand.java | 67 + ...lusteringFunctionsAndDistancesCommand.java | 62 + .../browsing/GetScatterplotCommand.java | 244 + .../commands/cell/BlankDownCommand.java | 56 + .../commands/cell/EditOneCellCommand.java | 189 + .../refine/commands/cell/FillDownCommand.java | 56 + .../cell/JoinMultiValueCellsCommand.java | 73 + .../cell/KeyValueColumnizeCommand.java | 75 + .../refine/commands/cell/MassEditCommand.java | 65 + .../cell/SplitMultiValueCellsCommand.java | 92 + .../commands/cell/TextTransformCommand.java | 70 + .../cell/TransposeColumnsIntoRowsCommand.java | 92 + .../cell/TransposeRowsIntoColumnsCommand.java | 74 + .../AddColumnByFetchingURLsCommand.java | 78 + .../commands/column/AddColumnCommand.java | 66 + .../column/GetColumnsInfoCommand.java | 119 + .../commands/column/MoveColumnCommand.java | 72 + .../commands/column/RemoveColumnCommand.java | 71 + .../commands/column/RenameColumnCommand.java | 72 + .../column/ReorderColumnsCommand.java | 58 + .../commands/column/SplitColumnCommand.java | 81 + .../expr/GetExpressionHistoryCommand.java | 101 + .../GetExpressionLanguageInfoCommand.java | 74 + .../expr/GetStarredExpressionsCommand.java | 78 + .../commands/expr/LogExpressionCommand.java | 75 + .../expr/PreviewExpressionCommand.java | 272 + .../expr/ToggleStarredExpressionCommand.java | 67 + .../history/ApplyOperationsCommand.java | 97 + .../history/CancelProcessesCommand.java | 72 + .../commands/history/GetHistoryCommand.java | 54 + .../history/GetOperationsCommand.java | 93 + .../commands/history/GetProcessesCommand.java | 59 + .../commands/history/UndoRedoCommand.java | 81 + .../importing/CancelImportingJobCommand.java | 68 + .../importing/CreateImportingJobCommand.java | 66 + .../GetImportingConfigurationCommand.java | 62 + .../GetImportingJobStatusCommand.java | 84 + .../importing/ImportingControllerCommand.java | 107 + .../commands/lang/GetLanguagesCommand.java | 106 + .../commands/lang/LoadLanguageCommand.java | 165 + .../project/CreateProjectCommand.java | 182 + .../project/DeleteProjectCommand.java | 84 + .../project/ExportProjectCommand.java | 74 + .../commands/project/ExportRowsCommand.java | 149 + .../commands/project/GetModelsCommand.java | 140 + .../project/GetProjectMetadataCommand.java | 61 + .../project/ImportProjectCommand.java | 170 + .../project/RenameProjectCommand.java | 65 + .../project/SetProjectMetadataCommand.java | 73 + .../project/SetProjectTagsCommand.java | 106 + .../commands/recon/ExtendDataCommand.java | 70 + .../recon/GuessTypesOfColumnCommand.java | 253 + .../recon/PreviewExtendDataCommand.java | 184 + .../recon/ReconClearOneCellCommand.java | 187 + .../recon/ReconClearSimilarCellsCommand.java | 59 + .../recon/ReconCopyAcrossColumnsCommand.java | 57 + .../recon/ReconDiscardJudgmentsCommand.java | 54 + .../recon/ReconJudgeOneCellCommand.java | 260 + .../recon/ReconJudgeSimilarCellsCommand.java | 81 + .../recon/ReconMarkNewTopicsCommand.java | 56 + .../ReconMatchBestCandidatesCommand.java | 54 + .../recon/ReconMatchSpecificTopicCommand.java | 65 + .../ReconUseValuesAsIdentifiersCommand.java | 52 + .../commands/recon/ReconcileCommand.java | 56 + .../commands/row/AnnotateOneRowCommand.java | 159 + .../commands/row/AnnotateRowsCommand.java | 66 + .../commands/row/DenormalizeCommand.java | 69 + .../refine/commands/row/GetRowsCommand.java | 292 + .../commands/row/RemoveRowsCommand.java | 52 + .../commands/row/ReorderRowsCommand.java | 67 + .../GetAllProjectMetadataCommand.java | 73 + .../workspace/GetAllProjectTagsCommand.java | 61 + .../google/refine/exporters/CsvExporter.java | 138 + .../CustomizableTabularExporterUtilities.java | 428 + .../com/google/refine/exporters/Exporter.java | 42 + .../refine/exporters/ExporterRegistry.java | 68 + .../refine/exporters/HtmlTableExporter.java | 127 + .../google/refine/exporters/OdsExporter.java | 126 + .../refine/exporters/StreamExporter.java | 48 + .../refine/exporters/TabularSerializer.java | 59 + .../refine/exporters/TemplatingExporter.java | 146 + .../google/refine/exporters/UrlExporter.java | 49 + .../refine/exporters/WriterExporter.java | 48 + .../google/refine/exporters/XlsExporter.java | 164 + .../exporters/sql/SqlCreateBuilder.java | 171 + .../google/refine/exporters/sql/SqlData.java | 77 + .../refine/exporters/sql/SqlExporter.java | 170 + .../exporters/sql/SqlExporterException.java | 42 + .../exporters/sql/SqlInsertBuilder.java | 259 + .../src/com/google/refine/expr/Binder.java | 46 + .../src/com/google/refine/expr/CellTuple.java | 70 + .../src/com/google/refine/expr/EvalError.java | 72 + .../src/com/google/refine/expr/Evaluable.java | 49 + .../google/refine/expr/ExpressionUtils.java | 176 + .../src/com/google/refine/expr/HasFields.java | 46 + .../com/google/refine/expr/HasFieldsList.java | 47 + .../google/refine/expr/HasFieldsListImpl.java | 80 + .../refine/expr/LanguageSpecificParser.java | 38 + .../com/google/refine/expr/MetaParser.java | 181 + .../google/refine/expr/ParsingException.java | 49 + .../com/google/refine/expr/WrappedCell.java | 61 + .../com/google/refine/expr/WrappedRow.java | 140 + .../refine/expr/functions/Coalesce.java | 75 + .../google/refine/expr/functions/Cross.java | 113 + .../refine/expr/functions/FacetCount.java | 100 + .../com/google/refine/expr/functions/Get.java | 171 + .../refine/expr/functions/HasField.java | 76 + .../google/refine/expr/functions/Jsonize.java | 75 + .../google/refine/expr/functions/Length.java | 85 + .../google/refine/expr/functions/Slice.java | 140 + .../google/refine/expr/functions/ToDate.java | 220 + .../refine/expr/functions/ToNumber.java | 90 + .../refine/expr/functions/ToString.java | 85 + .../google/refine/expr/functions/Type.java | 87 + .../expr/functions/arrays/ArgsToArray.java | 61 + .../refine/expr/functions/arrays/InArray.java | 89 + .../refine/expr/functions/arrays/Join.java | 110 + .../refine/expr/functions/arrays/Reverse.java | 96 + .../refine/expr/functions/arrays/Sort.java | 100 + .../refine/expr/functions/arrays/Uniques.java | 88 + .../refine/expr/functions/booleans/And.java | 71 + .../refine/expr/functions/booleans/Not.java | 71 + .../refine/expr/functions/booleans/Or.java | 71 + .../refine/expr/functions/booleans/Xor.java | 58 + .../refine/expr/functions/date/DatePart.java | 154 + .../refine/expr/functions/date/Inc.java | 101 + .../refine/expr/functions/date/Now.java | 61 + .../refine/expr/functions/html/InnerHtml.java | 77 + .../refine/expr/functions/html/ParseHtml.java | 73 + .../refine/expr/functions/math/ACos.java | 66 + .../refine/expr/functions/math/ASin.java | 66 + .../refine/expr/functions/math/ATan.java | 66 + .../refine/expr/functions/math/ATan2.java | 67 + .../refine/expr/functions/math/Abs.java | 66 + .../refine/expr/functions/math/Ceil.java | 66 + .../refine/expr/functions/math/Combin.java | 100 + .../refine/expr/functions/math/Cos.java | 66 + .../refine/expr/functions/math/Cosh.java | 66 + .../refine/expr/functions/math/Degrees.java | 66 + .../refine/expr/functions/math/Even.java | 71 + .../refine/expr/functions/math/Exp.java | 64 + .../refine/expr/functions/math/Fact.java | 66 + .../refine/expr/functions/math/FactN.java | 93 + .../refine/expr/functions/math/Floor.java | 67 + .../math/GreatestCommonDenominator.java | 71 + .../functions/math/LeastCommonMultiple.java | 83 + .../google/refine/expr/functions/math/Ln.java | 66 + .../refine/expr/functions/math/Log.java | 66 + .../refine/expr/functions/math/Max.java | 70 + .../refine/expr/functions/math/Min.java | 70 + .../refine/expr/functions/math/Mod.java | 71 + .../expr/functions/math/Multinomial.java | 76 + .../refine/expr/functions/math/Odd.java | 71 + .../refine/expr/functions/math/Pow.java | 67 + .../refine/expr/functions/math/Quotient.java | 67 + .../refine/expr/functions/math/Radians.java | 66 + .../expr/functions/math/RandomNumber.java | 71 + .../refine/expr/functions/math/Round.java | 66 + .../refine/expr/functions/math/Sin.java | 66 + .../refine/expr/functions/math/Sinh.java | 66 + .../refine/expr/functions/math/Sum.java | 95 + .../refine/expr/functions/math/Tan.java | 66 + .../refine/expr/functions/math/Tanh.java | 66 + .../refine/expr/functions/strings/Chomp.java | 70 + .../expr/functions/strings/Contains.java | 77 + .../refine/expr/functions/strings/Diff.java | 114 + .../expr/functions/strings/EndsWith.java | 70 + .../refine/expr/functions/strings/Escape.java | 99 + .../refine/expr/functions/strings/Find.java | 85 + .../expr/functions/strings/Fingerprint.java | 70 + .../expr/functions/strings/IndexOf.java | 70 + .../expr/functions/strings/LastIndexOf.java | 71 + .../refine/expr/functions/strings/MD5.java | 70 + .../refine/expr/functions/strings/Match.java | 91 + .../refine/expr/functions/strings/NGram.java | 93 + .../functions/strings/NGramFingerprint.java | 89 + .../expr/functions/strings/ParseJson.java | 76 + .../expr/functions/strings/Partition.java | 115 + .../expr/functions/strings/Phonetic.java | 116 + .../expr/functions/strings/RPartition.java | 116 + .../refine/expr/functions/strings/Range.java | 335 + .../expr/functions/strings/Reinterpret.java | 112 + .../expr/functions/strings/Replace.java | 80 + .../expr/functions/strings/ReplaceChars.java | 75 + .../refine/expr/functions/strings/SHA1.java | 70 + .../expr/functions/strings/SmartSplit.java | 117 + .../refine/expr/functions/strings/Split.java | 90 + .../functions/strings/SplitByCharType.java | 72 + .../functions/strings/SplitByLengths.java | 84 + .../expr/functions/strings/StartsWith.java | 69 + .../expr/functions/strings/ToLowercase.java | 67 + .../expr/functions/strings/ToTitlecase.java | 79 + .../expr/functions/strings/ToUppercase.java | 67 + .../refine/expr/functions/strings/Trim.java | 68 + .../expr/functions/strings/Unescape.java | 90 + .../expr/functions/strings/Unicode.java | 70 + .../expr/functions/strings/UnicodeType.java | 107 + .../refine/expr/functions/xml/InnerXml.java | 86 + .../refine/expr/functions/xml/OwnText.java | 77 + .../refine/expr/functions/xml/Parent.java | 83 + .../refine/expr/functions/xml/ParseXml.java | 85 + .../refine/expr/functions/xml/ScriptText.java | 87 + .../refine/expr/functions/xml/SelectXml.java | 79 + .../refine/expr/functions/xml/WholeText.java | 76 + .../refine/expr/functions/xml/XmlAttr.java | 79 + .../refine/expr/functions/xml/XmlText.java | 78 + .../refine/expr/util/CalendarParser.java | 1988 + .../expr/util/CalendarParserException.java | 57 + .../refine/expr/util/JsonValueConverter.java | 89 + .../src/com/google/refine/grel/Control.java | 64 + .../refine/grel/ControlFunctionRegistry.java | 340 + .../src/com/google/refine/grel/Function.java | 60 + .../src/com/google/refine/grel/Parser.java | 332 + .../src/com/google/refine/grel/Scanner.java | 347 + .../refine/grel/ast/ControlCallExpr.java | 76 + .../refine/grel/ast/FieldAccessorExpr.java | 80 + .../refine/grel/ast/FunctionCallExpr.java | 88 + .../google/refine/grel/ast/LiteralExpr.java | 60 + .../refine/grel/ast/OperatorCallExpr.java | 163 + .../google/refine/grel/ast/VariableExpr.java | 63 + .../google/refine/grel/controls/Filter.java | 158 + .../google/refine/grel/controls/ForEach.java | 170 + .../refine/grel/controls/ForEachIndex.java | 160 + .../refine/grel/controls/ForNonBlank.java | 99 + .../google/refine/grel/controls/ForRange.java | 145 + .../com/google/refine/grel/controls/If.java | 79 + .../google/refine/grel/controls/IsBlank.java | 48 + .../refine/grel/controls/IsEmptyString.java | 40 + .../google/refine/grel/controls/IsError.java | 48 + .../refine/grel/controls/IsNonBlank.java | 48 + .../refine/grel/controls/IsNotNull.java | 46 + .../google/refine/grel/controls/IsNull.java | 46 + .../refine/grel/controls/IsNumeric.java | 54 + .../google/refine/grel/controls/IsTest.java | 74 + .../com/google/refine/grel/controls/With.java | 95 + .../src/com/google/refine/history/Change.java | 55 + .../google/refine/history/ChangeSequence.java | 99 + .../com/google/refine/history/History.java | 303 + .../google/refine/history/HistoryEntry.java | 185 + .../refine/history/HistoryEntryManager.java | 45 + .../google/refine/history/HistoryProcess.java | 115 + .../refine/importers/BinaryFormatGuesser.java | 42 + .../refine/importers/ExcelImporter.java | 270 + .../refine/importers/FixedWidthImporter.java | 250 + .../refine/importers/ImportException.java | 46 + .../refine/importers/ImporterUtilities.java | 252 + .../refine/importers/ImportingParserBase.java | 249 + .../google/refine/importers/JsonImporter.java | 389 + .../importers/LineBasedFormatGuesser.java | 47 + .../refine/importers/LineBasedImporter.java | 134 + .../google/refine/importers/MarcImporter.java | 105 + .../google/refine/importers/OdsImporter.java | 291 + .../importers/RdfJsonldTripleImporter.java | 43 + .../refine/importers/RdfTripleImporter.java | 169 + .../importers/RdfXmlTripleImporter.java | 43 + .../importers/SeparatorBasedImporter.java | 299 + .../importers/TabularImportingParserBase.java | 217 + .../refine/importers/TextFormatGuesser.java | 147 + .../refine/importers/WikitextImporter.java | 786 + .../google/refine/importers/XmlImporter.java | 354 + .../refine/importers/tree/ImportColumn.java | 58 + .../importers/tree/ImportColumnGroup.java | 60 + .../importers/tree/ImportParameters.java | 56 + .../refine/importers/tree/ImportRecord.java | 101 + .../refine/importers/tree/ImportVertical.java | 48 + .../tree/RecordElementCandidate.java | 43 + .../importers/tree/TreeImportUtilities.java | 234 + .../tree/TreeImportingParserBase.java | 248 + .../refine/importers/tree/TreeReader.java | 69 + .../importers/tree/TreeReaderException.java | 49 + .../importers/tree/XmlImportUtilities.java | 639 + .../importing/DefaultImportingController.java | 313 + .../refine/importing/EncodingGuesser.java | 74 + .../refine/importing/FormatGuesser.java | 40 + .../refine/importing/ImportingController.java | 39 + .../google/refine/importing/ImportingJob.java | 207 + .../refine/importing/ImportingManager.java | 302 + .../refine/importing/ImportingParser.java | 85 + .../refine/importing/ImportingUtilities.java | 1075 + .../google/refine/importing/UrlRewriter.java | 44 + .../refine/io/FileHistoryEntryManager.java | 150 + .../google/refine/io/FileProjectManager.java | 479 + .../refine/io/ProjectMetadataUtilities.java | 172 + .../google/refine/io/ProjectUtilities.java | 166 + .../refine/model/AbstractOperation.java | 85 + .../src/com/google/refine/model/Cell.java | 199 + .../src/com/google/refine/model/Column.java | 233 + .../com/google/refine/model/ColumnGroup.java | 118 + .../com/google/refine/model/ColumnModel.java | 303 + .../google/refine/model/ModelException.java | 58 + .../com/google/refine/model/OverlayModel.java | 49 + .../src/com/google/refine/model/Project.java | 261 + .../src/com/google/refine/model/Recon.java | 417 + .../google/refine/model/ReconCandidate.java | 146 + .../com/google/refine/model/ReconStats.java | 96 + .../com/google/refine/model/ReconType.java | 73 + .../src/com/google/refine/model/Record.java | 50 + .../com/google/refine/model/RecordModel.java | 296 + .../main/src/com/google/refine/model/Row.java | 237 + .../refine/model/changes/CellAtRow.java | 68 + .../model/changes/CellAtRowCellIndex.java | 84 + .../refine/model/changes/CellChange.java | 124 + .../model/changes/ColumnAdditionChange.java | 187 + .../refine/model/changes/ColumnChange.java | 70 + .../model/changes/ColumnMoveChange.java | 136 + .../model/changes/ColumnRemovalChange.java | 191 + .../model/changes/ColumnRenameChange.java | 101 + .../model/changes/ColumnReorderChange.java | 249 + .../model/changes/ColumnSplitChange.java | 422 + .../model/changes/DataExtensionChange.java | 469 + .../refine/model/changes/MassCellChange.java | 168 + .../refine/model/changes/MassChange.java | 119 + .../refine/model/changes/MassReconChange.java | 149 + .../refine/model/changes/MassRowChange.java | 133 + .../model/changes/MassRowColumnChange.java | 202 + .../refine/model/changes/ReconChange.java | 211 + .../refine/model/changes/RowFlagChange.java | 105 + .../model/changes/RowRemovalChange.java | 149 + .../model/changes/RowReorderChange.java | 130 + .../refine/model/changes/RowStarChange.java | 105 + .../model/recon/DataExtensionReconConfig.java | 86 + .../refine/model/recon/ReconConfig.java | 137 + .../model/recon/ReconConfigResolver.java | 60 + .../google/refine/model/recon/ReconJob.java | 49 + .../recon/ReconciledDataExtensionJob.java | 324 + .../model/recon/StandardReconConfig.java | 630 + .../EngineDependentMassCellOperation.java | 101 + .../operations/EngineDependentOperation.java | 60 + .../com/google/refine/operations/OnError.java | 45 + .../refine/operations/OperationRegistry.java | 76 + .../refine/operations/OperationResolver.java | 70 + .../refine/operations/UnknownOperation.java | 62 + .../operations/cell/BlankDownOperation.java | 126 + .../operations/cell/FillDownOperation.java | 124 + .../cell/KeyValueColumnizeOperation.java | 281 + .../operations/cell/MassEditOperation.java | 239 + .../cell/MultiValuedCellJoinOperation.java | 160 + .../cell/MultiValuedCellSplitOperation.java | 260 + .../cell/TextTransformOperation.java | 211 + .../TransposeColumnsIntoRowsOperation.java | 377 + .../TransposeRowsIntoColumnsOperation.java | 148 + ...ColumnAdditionByFetchingURLsOperation.java | 410 + .../column/ColumnAdditionOperation.java | 227 + .../column/ColumnMoveOperation.java | 87 + .../column/ColumnRemovalOperation.java | 80 + .../column/ColumnRenameOperation.java | 87 + .../column/ColumnReorderOperation.java | 75 + .../column/ColumnSplitOperation.java | 358 + .../operations/recon/ExtendDataOperation.java | 301 + .../ReconClearSimilarCellsOperation.java | 135 + .../ReconCopyAcrossColumnsOperation.java | 203 + .../recon/ReconDiscardJudgmentsOperation.java | 164 + .../ReconJudgeSimilarCellsOperation.java | 272 + .../recon/ReconMarkNewTopicsOperation.java | 185 + .../ReconMatchBestCandidatesOperation.java | 156 + .../ReconMatchSpecificTopicOperation.java | 201 + .../operations/recon/ReconOperation.java | 349 + .../ReconUseValuesAsIdentifiersOperation.java | 161 + .../operations/row/DenormalizeOperation.java | 98 + .../operations/row/RowFlagOperation.java | 124 + .../operations/row/RowRemovalOperation.java | 109 + .../operations/row/RowReorderOperation.java | 154 + .../operations/row/RowStarOperation.java | 124 + .../refine/preference/PreferenceStore.java | 137 + .../refine/preference/PreferenceValue.java | 51 + .../com/google/refine/preference/TopList.java | 91 + .../refine/process/LongRunningProcess.java | 100 + .../com/google/refine/process/Process.java | 59 + .../google/refine/process/ProcessManager.java | 155 + .../process/QuickHistoryEntryProcess.java | 99 + .../com/google/refine/sorting/BaseSorter.java | 137 + .../refine/sorting/BooleanCriterion.java | 70 + .../com/google/refine/sorting/Criterion.java | 144 + .../google/refine/sorting/DateCriterion.java | 71 + .../refine/sorting/NumberCriterion.java | 85 + .../google/refine/sorting/SortingConfig.java | 60 + .../refine/sorting/SortingRecordVisitor.java | 98 + .../refine/sorting/SortingRowVisitor.java | 108 + .../refine/sorting/StringCriterion.java | 79 + .../refine/templating/DynamicFragment.java | 44 + .../google/refine/templating/Fragment.java | 38 + .../com/google/refine/templating/Parser.java | 110 + .../refine/templating/StaticFragment.java | 42 + .../google/refine/templating/Template.java | 213 + .../google/refine/util/CookiesUtilities.java | 85 + .../refine/util/GetProjectIDException.java | 53 + .../com/google/refine/util/HttpClient.java | 228 + .../src/com/google/refine/util/IOUtils.java | 78 + .../com/google/refine/util/IndentWriter.java | 107 + .../com/google/refine/util/JSONUtilities.java | 198 + .../src/com/google/refine/util/JsonViews.java | 44 + .../google/refine/util/LookupException.java | 19 + .../google/refine/util/ParsingUtilities.java | 296 + .../util/PatternSyntaxExceptionParser.java | 125 + .../main/src/com/google/refine/util/Pool.java | 156 + .../refine/util/SerializationFilters.java | 181 + .../com/google/refine/util/StringUtils.java | 51 + .../refine/util/TrackingInputStream.java | 90 + OpenRefine/main/tests/cypress/.eslintignore | 4 + OpenRefine/main/tests/cypress/.eslintrc.json | 28 + OpenRefine/main/tests/cypress/.gitignore | 10 + OpenRefine/main/tests/cypress/.prettierignore | 6 + .../main/tests/cypress/.prettierrc.json | 6 + OpenRefine/main/tests/cypress/Readme.md | 6 + .../main/tests/cypress/build-test-matrix.js | 84 + OpenRefine/main/tests/cypress/cypress.json | 12 + .../fixtures/csv-reconcile-species.csv | 31 + .../cypress/fixtures/doaj-article-sample.csv | 1002 + .../cypress/cypress/fixtures/fixtures.js | 11 + .../food-small-csv.openrefine.tar.zip | Bin 0 -> 23919 bytes .../cypress/cypress/fixtures/food.mini.csv | 3 + .../cypress/cypress/fixtures/food.mini.js | 7 + .../cypress/cypress/fixtures/food.small.csv | 200 + .../cypress/cypress/fixtures/food.small.js | 10604 + .../cypress/cypress/fixtures/food.sort.csv | 3 + .../cypress/cypress/fixtures/food.sort.js | 7 + .../fixtures/reconciled-project-automatch.zip | Bin 0 -> 4256 bytes .../reconciled-project-no-automatch.zip | Bin 0 -> 4063 bytes .../cypress/cypress/fixtures/shop.mini.tsv | 6 + .../create-project/create_project.spec.js | 239 + .../create-project/preview_project.spec.js | 255 + .../integration/extensions/wikidata/.gitkeep | 0 .../import-project/import_project.spec.js | 45 + .../language/change_language.spec.js | 19 + .../open-project/filter_projects.spec.js | 39 + .../open-project/list_projects.spec.js | 72 + .../open-project/open_project.spec.js | 9 + .../preferences/change_preference.spec.js | 39 + .../grid/all-column/collapse_all.spec.js | 17 + .../grid/all-column/edit-columns.spec.js | 70 + .../project/grid/all-column/edit-rows.spec.js | 87 + .../project/grid/all-column/flag.spec.js | 24 + .../project/grid/all-column/star.spec.js | 24 + .../project/grid/all-column/view.spec.js | 31 + .../grid/column/edit-cells/blank-down.spec.js | 28 + .../Replace-Smart-quotes-with-ascii.spec.js | 37 + .../collapse-consecutive-whitespace.spec.js | 23 + .../common-transforms/to-date.spec.js | 28 + .../common-transforms/to-empty-string.spec.js | 18 + .../common-transforms/to-lowercase.spec.js | 18 + .../common-transforms/to-null.spec.js | 18 + .../common-transforms/to-number.spec.js | 52 + .../common-transforms/to-text.spec.js | 21 + .../common-transforms/to-titlecase.spec.js | 18 + .../common-transforms/to-uppercase.spec.js | 18 + .../trim-leading-whitespace.spec.js | 21 + .../unescape-html-entities.spec.js | 22 + .../grid/column/edit-cells/fill-down.spec.js | 27 + .../join-multi-valued-cells.spec.js | 31 + .../grid/column/edit-cells/replace.spec.js | 146 + .../split-multi-valued-cells.spec.js | 96 + .../grid/column/edit-cells/transform.spec.js | 70 + .../edit-cells/warning-on-blank-down.spec.js | 56 + .../edit-cells/warning-on-fill-down.spec.js | 56 + .../add_columns_based_on_this_column.spec.js | 61 + .../column/edit-column/join_columns.spec.js | 126 + .../edit-column/rename_remove_column.spec.js | 40 + .../edit-column/reposition_column.spec.js | 53 + .../split_into_several_columns.spec.js | 114 + .../project/grid/column/facet/.gitkeep | 0 .../column/facet/customized-facets/.gitkeep | 0 .../grid/column/facet/facets.numeric.spec.js | 78 + .../project/grid/column/facet/facets.spec.js | 413 + .../column/facet/scatterplot-facet.spec.js | 59 + .../actions/clear_reconciliation_data.spec.js | 23 + .../actions/create_new_item_for_each.spec.js | 30 + .../discard_reconciliation_judgments.spec.js | 37 + .../actions/match_to_best_candidate.spec.js | 41 + .../reconcile/add_entity_identifiers.spec.js | 32 + .../copy_reconciliation_data.spec.js | 46 + .../reconcile/facets/by_judgment.spec.js | 17 + .../use_values_as_identifiers.spec.js | 30 + .../project/grid/column/sort.spec.js | 105 + .../project/grid/column/text_filter.spec.js | 92 + .../project/grid/column/transpose/.gitkeep | 0 .../transpose/cell_accross_columns.spec.js | 122 + .../column/transpose/cells_in_rows.spec.js | 43 + .../grid/column/transpose/columnize.spec.js | 81 + .../project/grid/column/view/.gitkeep | 0 .../project/grid/column/view/collapse.spec.js | 14 + .../grid/column/view/collapse_left.spec.js | 16 + .../grid/column/view/collapse_right.spec.js | 16 + .../grid/column/view/expand-left.spec.js | 26 + .../grid/column/view/expand-right.spec.js | 26 + .../project/grid/misc/expressions.spec.js | 278 + .../project/grid/misc/proper-display.spec.js | 25 + .../project/grid/row/edit_cells.spec.js | 122 + .../grid/viewpanel-header/pagination.spec.js | 80 + .../viewpanel-header/rows_records.spec.js | 156 + .../grid/viewpanel-header/sort.spec.js | 115 + .../project-header/export_project.spec.js | 153 + .../project/project-header/help.spec.js | 12 + .../project/project-header/permalink.spec.js | 12 + .../project-header/project_rename.spec.js | 17 + .../project/undo_redo/apply.spec.js | 46 + .../project/undo_redo/extract.spec.js | 168 + .../project/undo_redo/undo_redo.spec.js | 113 + .../project_metadata.spec.js | 130 + .../importing-data-into-openrefine.spec.js | 50 + .../tutorial/layout-of-openrefine.spec.js | 64 + .../tests/cypress/cypress/plugins/index.js | 27 + .../scatterplot-default.snap.png | Bin 0 -> 14296 bytes .../scatterplot-facet-big-dot.snap.png | Bin 0 -> 4055 bytes .../scatterplot-facet-lin.snap.png | Bin 0 -> 3127 bytes .../scatterplot-facet-log.snap.png | Bin 0 -> 3003 bytes .../scatterplot-facet-regulat-dot.snap.png | Bin 0 -> 2934 bytes .../scatterplot-facet-small-dot.snap.png | Bin 0 -> 2186 bytes .../scatterplot-matrix-big-dot.snap.png | Bin 0 -> 17685 bytes .../scatterplot-matrix-lin.snap.png | Bin 0 -> 14296 bytes .../scatterplot-matrix-log.snap.png | Bin 0 -> 13336 bytes .../scatterplot-matrix-regulat-dot.snap.png | Bin 0 -> 13336 bytes .../scatterplot-matrix-small-dot.snap.png | Bin 0 -> 10601 bytes .../tests/cypress/cypress/support/commands.js | 430 + .../tests/cypress/cypress/support/index.js | 65 + .../cypress/cypress/support/openrefine_api.js | 229 + OpenRefine/main/tests/cypress/package.json | 30 + OpenRefine/main/tests/cypress/yarn.lock | 2057 + .../Colorado-Municipalities-small-xlsx.gz | Bin 0 -> 23156 bytes OpenRefine/main/tests/data/Wpi Data.tsv | 4045 + OpenRefine/main/tests/data/big5.html | 3341 + OpenRefine/main/tests/data/big5.txt | 3 + OpenRefine/main/tests/data/birds.csv | 19724 + .../tests/data/changes/data_extension_2.8.txt | 49 + .../tests/data/changes/data_extension_3.0.txt | 29 + OpenRefine/main/tests/data/dates.xls | Bin 0 -> 8192 bytes OpenRefine/main/tests/data/euc-jp.html | 884 + OpenRefine/main/tests/data/euc-jp.txt | 3 + OpenRefine/main/tests/data/euc-kr.html | 1713 + OpenRefine/main/tests/data/euc-kr.txt | 10 + OpenRefine/main/tests/data/example-latin1.tsv | 3 + .../data/example-linebreaks-in-cells.csv | 7 + .../data/example-linebreaks-in-cells.tsv | 5 + OpenRefine/main/tests/data/example-utf8.tsv | 3 + .../tests/data/example_project_metadata.json | 1 + .../example_project_metadata_save_mode.json | 1 + OpenRefine/main/tests/data/excel95.xls | Bin 0 -> 5632 bytes OpenRefine/main/tests/data/films.ods | Bin 0 -> 14139 bytes OpenRefine/main/tests/data/food.csv | 7414 + OpenRefine/main/tests/data/food.small.csv | 200 + .../main/tests/data/government_contracts.csv | 6423 + OpenRefine/main/tests/data/grid_small.json | 11 + OpenRefine/main/tests/data/jorf.xml | 1002 + .../main/tests/data/json-sample-format-1.json | 13 + .../main/tests/data/movies-condensed.tsv | 21 + OpenRefine/main/tests/data/movies.tsv | 233 + OpenRefine/main/tests/data/movies.zip | Bin 0 -> 6308 bytes .../main/tests/data/nobel-prize-winners.csv | 854 + OpenRefine/main/tests/data/ozone_8hr_dmax.csv | 316836 +++++++++++++++ OpenRefine/main/tests/data/ozone_sites.csv | 132 + OpenRefine/main/tests/data/presidents.tsv | 44 + OpenRefine/main/tests/data/scriblio.mrc | 1 + OpenRefine/main/tests/data/shift_jis.html | 2654 + OpenRefine/main/tests/data/shift_jis.txt | 20 + .../main/tests/data/unsupportedPPMD.zip | Bin 0 -> 10649 bytes .../main/tests/data/xml-sample-format-1.xml | 24 + .../main/tests/data/xml-sample-format-2.xml | 24 + .../main/tests/data/xml-sample-format-3.xml | 24 + .../main/tests/data/xml-sample-format-4.xml | 503 + OpenRefine/main/tests/server/conf/tests.xml | 40 + .../refine/HistoryEntryManagerStub.java | 81 + .../com/google/refine/ProjectManagerStub.java | 107 + .../google/refine/ProjectManagerTests.java | 262 + .../com/google/refine/RefineServletStub.java | 100 + .../com/google/refine/RefineServletTests.java | 307 + .../src/com/google/refine/RefineTest.java | 394 + .../refine/browsing/DecoratedValueTests.java | 45 + .../refine/browsing/EngineConfigTests.java | 86 + .../google/refine/browsing/EngineTests.java | 46 + .../browsing/facets/ListFacetTests.java | 134 + .../facets/NominalFacetChoiceTests.java | 51 + .../browsing/facets/RangeFacetTests.java | 102 + .../facets/ScatterplotFacetTests.java | 118 + .../browsing/facets/TextSearchFacetTests.java | 208 + .../browsing/facets/TimeRangeFacetTests.java | 104 + .../ExpressionNominalValueGrouperTests.java | 207 + .../binning/BinningClustererTests.java | 100 + .../refine/clustering/binning/KeyerTests.java | 178 + .../clustering/knn/kNNClustererTests.java | 90 + .../commands/CSRFTokenFactoryTests.java | 52 + .../google/refine/commands/CommandStub.java | 65 + .../refine/commands/CommandTestBase.java | 43 + .../google/refine/commands/CommandTests.java | 289 + .../commands/EngineDependentCommandTests.java | 38 + .../commands/GetCSRFTokenCommandTest.java | 51 + .../OpenWorkspaceDirCommandTests.java | 23 + .../commands/SetPreferenceCommandTests.java | 23 + ...eringFunctionsAndDistancesCommandTest.java | 78 + .../browsing/ScatterplotDrawCommandTests.java | 147 + .../cell/EditOneCellCommandTests.java | 118 + .../cell/JoinMultiValueCellsCommandTests.java | 25 + .../cell/KeyValueColumnizeCommandTests.java | 25 + .../SplitMultiValueCellsCommandTests.java | 25 + .../TransposeColumnsIntoRowsCommandTests.java | 25 + .../TransposeRowsIntoColumnsCommandTests.java | 25 + .../column/MoveColumnCommandTests.java | 24 + .../column/RemoveColumnCommandTests.java | 24 + .../column/RenameColumnCommandTests.java | 24 + .../expr/ExpressionCommandTestBase.java | 103 + .../GetExpressionHistoryCommandTests.java | 93 + ...GetExpressionLanguageInfoCommandTests.java | 64 + .../GetStarredExpressionsCommandTests.java | 82 + .../expr/LogExpressionCommandTests.java | 50 + .../expr/PreviewExpressionCommandTests.java | 103 + .../ToggleStarredExpressionCommandTests.java | 86 + .../history/ApplyOperationsCommandTests.java | 24 + .../history/CancelProcessesCommandTests.java | 24 + .../history/UndoRedoCommandTests.java | 24 + .../CancelImportingJobCommandTests.java | 24 + .../CreateImportingJobCommandTests.java | 24 + .../ImportingControllerCommandTests.java | 24 + .../lang/LoadLanguageCommandTests.java | 101 + .../project/ImportProjectCommandTests.java | 24 + .../project/RenameProjectCommandTests.java | 24 + .../SetProjectMetadataCommandTests.java | 214 + .../project/SetProjectTagsCommandTests.java | 24 + .../recon/GuessTypesOfColumnCommandTests.java | 155 + .../recon/PreviewExtendDataCommandTests.java | 24 + .../recon/ReconClearOneCellCommandTests.java | 24 + .../recon/ReconJudgeOneCellCommandTest.java | 131 + .../row/AnnotateOneRowCommandTests.java | 24 + .../commands/row/DenormalizeCommandTests.java | 24 + .../commands/row/GetRowsCommandTest.java | 142 + .../util/CancelProcessesCommandTests.java | 259 + .../refine/exporters/CsvExporterTests.java | 266 + .../refine/exporters/HtmlExporterTests.java | 236 + .../exporters/TemplatingExporterTests.java | 281 + .../refine/exporters/TsvExporterTests.java | 220 + .../refine/exporters/XlsExporterTests.java | 266 + .../refine/exporters/XlsxExporterTests.java | 266 + .../exporters/sql/SqlExporterTests.java | 558 + .../google/refine/expr/EvalErrorTests.java | 82 + .../refine/expr/ExpressionUtilsTests.java | 72 + .../refine/expr/functions/CoalesceTests.java | 84 + .../refine/expr/functions/CrossTests.java | 375 + .../expr/functions/FacetCountTests.java | 35 + .../refine/expr/functions/GetTests.java | 83 + .../refine/expr/functions/HasFieldTests.java | 35 + .../refine/expr/functions/JsonizeTests.java | 58 + .../refine/expr/functions/LengthTests.java | 35 + .../refine/expr/functions/SliceTests.java | 35 + .../refine/expr/functions/ToDateTests.java | 111 + .../refine/expr/functions/ToNumberTests.java | 70 + .../refine/expr/functions/ToStringTests.java | 64 + .../refine/expr/functions/TypeTests.java | 83 + .../expr/functions/arrays/InArrayTests.java | 75 + .../expr/functions/arrays/JoinTests.java | 57 + .../expr/functions/arrays/ReverseTests.java | 59 + .../expr/functions/arrays/SortTests.java | 74 + .../expr/functions/arrays/UniquesTests.java | 74 + .../expr/functions/booleans/AndTests.java | 35 + .../expr/functions/booleans/BooleanTests.java | 99 + .../expr/functions/booleans/NotTests.java | 35 + .../expr/functions/booleans/OrTests.java | 35 + .../expr/functions/booleans/XorTests.java | 35 + .../expr/functions/date/DatePartTests.java | 120 + .../refine/expr/functions/date/IncTests.java | 109 + .../refine/expr/functions/date/NowTests.java | 61 + .../expr/functions/html/InnerHtmlTests.java | 35 + .../expr/functions/html/ParseHtmlTests.java | 92 + .../expr/functions/strings/ChompTests.java | 49 + .../expr/functions/strings/ContainsTests.java | 65 + .../expr/functions/strings/DiffTests.java | 125 + .../expr/functions/strings/EndsWithTests.java | 45 + .../expr/functions/strings/EscapeTests.java | 69 + .../expr/functions/strings/FindTests.java | 78 + .../functions/strings/FingerprintTests.java | 84 + .../expr/functions/strings/IndexOfTests.java | 35 + .../functions/strings/LastIndexOfTests.java | 35 + .../expr/functions/strings/MD5Tests.java | 35 + .../expr/functions/strings/MatchTests.java | 35 + .../strings/NGramFingerprintTests.java | 35 + .../expr/functions/strings/NGramTests.java | 35 + .../functions/strings/ParseJsonTests.java | 35 + .../functions/strings/PartitionTests.java | 35 + .../expr/functions/strings/PhoneticTests.java | 51 + .../functions/strings/RPartitionTests.java | 35 + .../expr/functions/strings/RangeTests.java | 318 + .../functions/strings/ReinterpretTests.java | 35 + .../functions/strings/ReplaceCharsTests.java | 35 + .../expr/functions/strings/ReplaceTests.java | 54 + .../expr/functions/strings/SHA1Tests.java | 35 + .../functions/strings/SmartSplitTests.java | 120 + .../strings/SplitByCharTypeTests.java | 35 + .../strings/SplitByLengthsTests.java | 35 + .../expr/functions/strings/SplitTests.java | 46 + .../functions/strings/StartsWithTests.java | 45 + .../functions/strings/ToLowercaseTests.java | 54 + .../functions/strings/ToTitlecaseTests.java | 55 + .../functions/strings/ToUppercaseTests.java | 35 + .../expr/functions/strings/TrimTests.java | 100 + .../expr/functions/strings/UnescapeTests.java | 51 + .../expr/functions/strings/UnicodeTests.java | 35 + .../functions/strings/UnicodeTypeTests.java | 35 + .../expr/functions/xml/InnerXmlTests.java | 35 + .../expr/functions/xml/OwnTextTests.java | 35 + .../expr/functions/xml/ParseXmlTests.java | 83 + .../expr/functions/xml/SelectXmlTests.java | 35 + .../expr/util/JsonValueConverterTests.java | 89 + .../com/google/refine/grel/FunctionTests.java | 153 + .../src/com/google/refine/grel/GrelTests.java | 199 + .../refine/grel/ast/LiteralExprTest.java | 47 + .../refine/grel/controls/FilterTests.java | 41 + .../grel/controls/ForEachIndexTests.java | 41 + .../refine/grel/controls/ForEachTests.java | 109 + .../grel/controls/ForNonBlankTests.java | 41 + .../refine/grel/controls/ForRangeTests.java | 41 + .../google/refine/grel/controls/IfTests.java | 41 + .../refine/grel/controls/IsBlankTests.java | 41 + .../grel/controls/IsEmptyStringTests.java | 41 + .../refine/grel/controls/IsErrorTests.java | 41 + .../refine/grel/controls/IsNonBlankTests.java | 41 + .../refine/grel/controls/IsNotNullTests.java | 41 + .../refine/grel/controls/IsNullTests.java | 41 + .../refine/grel/controls/IsNumericTests.java | 41 + .../refine/grel/controls/WithTests.java | 41 + .../history/FileHistoryEntryManagerTests.java | 40 + .../refine/history/HistoryEntryTests.java | 108 + .../google/refine/history/HistoryTests.java | 145 + .../refine/importers/ExcelImporterTests.java | 442 + .../importers/FixedWidthImporterTests.java | 111 + .../google/refine/importers/ImporterTest.java | 209 + .../importers/ImporterUtilitiesTests.java | 180 + .../refine/importers/JsonImporterTests.java | 669 + .../refine/importers/MarcImporterTests.java | 121 + .../refine/importers/OdsImporterTests.java | 129 + .../importers/RdfTripleImporterTests.java | 362 + .../importers/TextFormatGuesserTests.java | 272 + .../refine/importers/TsvCsvImporterTests.java | 689 + .../importers/WikitextImporterTests.java | 357 + .../importers/XmlImportUtilitiesStub.java | 96 + .../importers/XmlImportUtilitiesTests.java | 696 + .../refine/importers/XmlImporterTests.java | 416 + .../importing/EncodingGuesserTests.java | 66 + .../importing/ImportingManagerTests.java | 51 + .../importing/ImportingUtilitiesTests.java | 329 + .../refine/io/FileProjectManagerTests.java | 95 + .../refine/io/ProjectMetadataTests.java | 76 + .../com/google/refine/model/CacheTests.java | 145 + .../com/google/refine/model/CellTests.java | 174 + .../google/refine/model/ColumnGroupTests.java | 65 + .../google/refine/model/ColumnModelTests.java | 77 + .../com/google/refine/model/ColumnTests.java | 75 + .../com/google/refine/model/ProjectStub.java | 41 + .../refine/model/ReconCandidateTests.java | 55 + .../google/refine/model/ReconStatsTests.java | 41 + .../com/google/refine/model/ReconTests.java | 123 + .../google/refine/model/ReconTypeTest.java | 52 + .../google/refine/model/RecordModelTests.java | 44 + .../src/com/google/refine/model/RowTests.java | 190 + .../changes/DataExtensionChangeTest.java | 93 + .../refine/model/changes/MassChangeTests.java | 78 + .../model/recon/StandardReconConfigTests.java | 544 + .../operations/cell/BlankDownTests.java | 139 + .../refine/operations/cell/FillDownTests.java | 156 + .../cell/JoinMultiValuedCellsTests.java | 124 + .../cell/KeyValueColumnizeTests.java | 244 + .../operations/cell/MassOperationTests.java | 150 + .../cell/SplitMultiValuedCellsTests.java | 254 + .../operations/cell/TransposeTests.java | 63 + ...nAdditionByFetchingURLsOperationTests.java | 364 + .../column/ColumnAdditionOperationTests.java | 55 + .../column/ColumnMoveOperationTests.java | 53 + .../column/ColumnRemovalOperationTests.java | 52 + .../column/ColumnRenameOperationTests.java | 55 + .../column/ColumnReorderOperationTests.java | 96 + .../column/ColumnSplitOperationTests.java | 82 + .../recon/ExtendDataOperationTests.java | 444 + .../ReconClearSimilarCellsOperationTests.java | 55 + .../ReconCopyAcrossColumnsOperationTests.java | 57 + .../ReconDiscardJudgmentsOperationTests.java | 60 + .../ReconJudgeSimilarCellsOperationTests.java | 58 + .../recon/ReconJudgeSimilarCellsTests.java | 124 + .../ReconMarkNewTopicsOperationTests.java | 57 + ...econMatchBestCandidatesOperationTests.java | 59 + ...ReconMatchSpecificTopicOperationTests.java | 68 + .../operations/recon/ReconOperationTests.java | 153 + .../ReconUseValuesAsIdsOperationTests.java | 84 + .../row/DenormalizeOperationTests.java | 51 + .../operations/row/RowFlagOperationTests.java | 54 + .../row/RowRemovalOperationTests.java | 55 + .../row/RowReorderOperationTests.java | 111 + .../operations/row/RowStarOperationTests.java | 54 + .../preference/PreferenceStoreTests.java | 73 + .../refine/preference/TopListTests.java | 63 + .../refine/process/HistoryProcessTests.java | 71 + .../process/LongRunningProcessStub.java | 31 + .../process/LongRunningProcessTests.java | 60 + .../refine/process/ProcessManagerTests.java | 66 + .../QuickHistoryEntryProcessTests.java | 67 + .../refine/sorting/BooleanCriterionTest.java | 50 + .../refine/sorting/DateCriterionTest.java | 50 + .../refine/sorting/NumberCriterionTest.java | 50 + .../refine/sorting/SortingConfigTests.java | 53 + .../refine/util/ParsingUtilitiesTests.java | 144 + .../PatternSyntaxExceptionParserTests.java | 168 + .../google/refine/util/StringUtilsTests.java | 25 + .../src/com/google/refine/util/TestUtils.java | 187 + .../tests/server/src/tests.log4j.properties | 30 + .../main/webapp/WEB-INF/butterfly.properties | 38 + .../main/webapp/WEB-INF/modules.properties | 8 + .../main/webapp/WEB-INF/velocity.properties | 11 + OpenRefine/main/webapp/WEB-INF/web.xml | 61 + .../webapp/licenses/chrome_frame.LICENSE.txt | 27 + .../main/webapp/licenses/datejs.LICENSE.txt | 26 + .../licenses/freebase_suggest.LICENSE.txt | 29 + .../webapp/licenses/imgareaselect.LICENSE.txt | 20 + .../main/webapp/licenses/jquery.LICENSE.txt | 20 + .../licenses/jquery.eventstack.LICENSE.txt | 35 + .../webapp/licenses/jquery.i18n.LICENSE.txt | 21 + .../webapp/licenses/jquery_ui.LICENSE.txt | 25 + .../licenses/simile-ajax.2.3.0.LICENSE.txt | 35 + .../webapp/modules/core/MOD-INF/controller.js | 703 + .../modules/core/MOD-INF/module.properties | 3 + .../main/webapp/modules/core/about.html | 234 + OpenRefine/main/webapp/modules/core/about.js | 9 + OpenRefine/main/webapp/modules/core/error.vt | 53 + .../core/externals/CLDRPluralRuleParser.js | 607 + .../webapp/modules/core/externals/date.js | 104 + .../css/imgareaselect-default.css | 41 + .../imgareaselect/jquery.imgareaselect.js | 718 + .../modules/core/externals/jquery-1.12.4.js | 11008 + .../core/externals/jquery-1.12.4.min.js | 5 + .../core/externals/jquery-migrate-1.4.1.js | 752 + .../externals/jquery-migrate-1.4.1.min.js | 2 + .../ui-lightness/images/animated-overlay.gif | Bin 0 -> 1738 bytes .../ui-bg_diagonals-thick_18_b81900_40x40.png | Bin 0 -> 476 bytes .../ui-bg_diagonals-thick_20_666666_40x40.png | Bin 0 -> 384 bytes .../images/ui-bg_flat_10_000000_40x100.png | Bin 0 -> 205 bytes .../images/ui-bg_glass_100_f6f6f6_1x400.png | Bin 0 -> 324 bytes .../images/ui-bg_glass_100_fdf5ce_1x400.png | Bin 0 -> 406 bytes .../images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 265 bytes .../ui-bg_gloss-wave_35_f6a828_500x100.png | Bin 0 -> 5873 bytes .../ui-bg_highlight-soft_100_eeeeee_1x100.png | Bin 0 -> 342 bytes .../ui-bg_highlight-soft_75_ffe45c_1x100.png | Bin 0 -> 386 bytes .../images/ui-icons_222222_256x240.png | Bin 0 -> 7025 bytes .../images/ui-icons_228ef1_256x240.png | Bin 0 -> 4676 bytes .../images/ui-icons_ef8c08_256x240.png | Bin 0 -> 4676 bytes .../images/ui-icons_ffd27a_256x240.png | Bin 0 -> 4676 bytes .../images/ui-icons_ffffff_256x240.png | Bin 0 -> 6487 bytes .../jquery-ui/css/ui-lightness/jquery-ui.css | 1311 + .../css/ui-lightness/jquery-ui.min.css | 7 + .../jquery-ui/css/ui-lightness/theme.css | 443 + .../core/externals/jquery-ui/jquery-ui.js | 18706 + .../core/externals/jquery-ui/jquery-ui.min.js | 13 + .../externals/jquery.i18n.emitter.bidi.js | 95 + .../core/externals/jquery.i18n.emitter.js | 168 + .../core/externals/jquery.i18n.fallbacks.js | 186 + .../modules/core/externals/jquery.i18n.js | 290 + .../core/externals/jquery.i18n.language.js | 499 + .../externals/jquery.i18n.messagestore.js | 123 + .../core/externals/jquery.i18n.parser.js | 310 + .../modules/core/externals/js.cookie.js | 163 + .../modules/core/externals/languages/bs.js | 22 + .../modules/core/externals/languages/dsb.js | 22 + .../modules/core/externals/languages/fi.js | 49 + .../modules/core/externals/languages/ga.js | 38 + .../modules/core/externals/languages/he.js | 31 + .../modules/core/externals/languages/hsb.js | 21 + .../modules/core/externals/languages/hu.js | 26 + .../modules/core/externals/languages/hy.js | 25 + .../modules/core/externals/languages/la.js | 54 + .../modules/core/externals/languages/ml.js | 98 + .../modules/core/externals/languages/os.js | 75 + .../modules/core/externals/languages/ru.js | 29 + .../modules/core/externals/languages/sl.js | 26 + .../modules/core/externals/languages/uk.js | 39 + .../core/externals/moment-with-locales.min.js | 1 + .../externals/select2/select2-spinner.gif | Bin 0 -> 1849 bytes .../core/externals/select2/select2.css | 704 + .../core/externals/select2/select2.min.js | 18 + .../core/externals/select2/select2.png | Bin 0 -> 613 bytes .../externals/suggest/css/suggest-4_3.css | 577 + .../externals/suggest/css/suggest-4_3.min.css | 36 + .../core/externals/suggest/suggest-4_3a.js | 1974 + .../tablesorter/jquery.tablesorter.js | 2899 + .../tablesorter/jquery.tablesorter.min.js | 1 + .../core/externals/tablesorter/theme.blue.css | 229 + .../modules/core/externals/underscore-min.js | 6 + .../modules/core/externals/underscore-min.map | 1 + .../webapp/modules/core/images/arrow-end.png | Bin 0 -> 142 bytes .../modules/core/images/arrow-start.png | Bin 0 -> 139 bytes .../webapp/modules/core/images/checks-map.png | Bin 0 -> 1127 bytes .../webapp/modules/core/images/close-map.png | Bin 0 -> 1022 bytes .../main/webapp/modules/core/images/close.png | Bin 0 -> 991 bytes .../webapp/modules/core/images/collapsed.png | Bin 0 -> 176 bytes .../main/webapp/modules/core/images/cop.png | Bin 0 -> 64003 bytes .../webapp/modules/core/images/down-arrow.png | Bin 0 -> 971 bytes .../webapp/modules/core/images/edit-map.png | Bin 0 -> 1569 bytes .../main/webapp/modules/core/images/edit.png | Bin 0 -> 15537 bytes .../webapp/modules/core/images/expanded.png | Bin 0 -> 115 bytes .../core/images/facet-resize-handle.png | Bin 0 -> 961 bytes .../webapp/modules/core/images/favicon.png | Bin 0 -> 4842 bytes .../modules/core/images/large-spinner.gif | Bin 0 -> 3208 bytes .../core/images/leftpanel-showhide.png | Bin 0 -> 1279 bytes .../modules/core/images/logo-gem-126.png | Bin 0 -> 1780 bytes .../core/images/logo-openrefine-550.png | Bin 0 -> 58994 bytes .../modules/core/images/menu-dropdown.png | Bin 0 -> 1123 bytes .../modules/core/images/menu-opener.png | Bin 0 -> 337 bytes .../modules/core/images/minimize-map.png | Bin 0 -> 257 bytes .../modules/core/images/right-arrow.png | Bin 0 -> 974 bytes .../modules/core/images/scatterplot-icons.png | Bin 0 -> 1035 bytes .../modules/core/images/slider-handle.png | Bin 0 -> 1002 bytes .../modules/core/images/small-spinner.gif | Bin 0 -> 1849 bytes .../modules/core/images/star-flag-map.png | Bin 0 -> 1997 bytes .../main/webapp/modules/core/images/star.png | Bin 0 -> 1259 bytes .../webapp/modules/core/images/up-arrow.png | Bin 0 -> 976 bytes OpenRefine/main/webapp/modules/core/index.vt | 78 + .../modules/core/langs/translation-ar.json | 256 + .../modules/core/langs/translation-bn.json | 61 + .../modules/core/langs/translation-ceb.json | 679 + .../modules/core/langs/translation-cs.json | 582 + .../modules/core/langs/translation-de.json | 782 + .../modules/core/langs/translation-el.json | 90 + .../modules/core/langs/translation-en.json | 785 + .../modules/core/langs/translation-en_GB.json | 7 + .../modules/core/langs/translation-es.json | 799 + .../modules/core/langs/translation-fil.json | 678 + .../modules/core/langs/translation-fr.json | 788 + .../modules/core/langs/translation-he.json | 760 + .../modules/core/langs/translation-hi.json | 27 + .../modules/core/langs/translation-hu.json | 717 + .../modules/core/langs/translation-id.json | 531 + .../modules/core/langs/translation-it.json | 742 + .../modules/core/langs/translation-iu.json | 1 + .../modules/core/langs/translation-jp.json | 808 + .../modules/core/langs/translation-ko.json | 76 + .../modules/core/langs/translation-ml.json | 3 + .../modules/core/langs/translation-mr.json | 1 + .../modules/core/langs/translation-nb_NO.json | 433 + .../modules/core/langs/translation-nl.json | 461 + .../modules/core/langs/translation-pa.json | 11 + .../modules/core/langs/translation-pl.json | 171 + .../modules/core/langs/translation-pt.json | 753 + .../modules/core/langs/translation-pt_BR.json | 773 + .../modules/core/langs/translation-ro.json | 49 + .../modules/core/langs/translation-ru.json | 693 + .../modules/core/langs/translation-sv.json | 461 + .../modules/core/langs/translation-tl.json | 678 + .../modules/core/langs/translation-uk.json | 20 + .../modules/core/langs/translation-zh.json | 684 + .../core/langs/translation-zh_Hant.json | 50 + OpenRefine/main/webapp/modules/core/macros.vm | 0 .../main/webapp/modules/core/preferences.vt | 53 + .../main/webapp/modules/core/project.vt | 87 + .../scripts/dialogs/clustering-dialog.html | 60 + .../core/scripts/dialogs/clustering-dialog.js | 646 + .../dialogs/column-reordering-dialog.html | 17 + .../dialogs/column-reordering-dialog.js | 88 + .../dialogs/common-transform-dialog.html | 15 + .../dialogs/common-transform-dialog.js | 134 + .../custom-tabular-exporter-dialog.html | 170 + .../dialogs/custom-tabular-exporter-dialog.js | 448 + .../dialogs/export-project-dialog.html | 20 + .../dialogs/expression-column-dialog.html | 34 + .../dialogs/expression-column-dialog.js | 106 + .../dialogs/expression-preview-dialog.html | 35 + .../dialogs/expression-preview-dialog.js | 484 + .../dialogs/extend-data-preview-dialog.js | 439 + .../scripts/dialogs/http-headers-dialog.html | 1 + .../scripts/dialogs/http-headers-dialog.js | 73 + .../scripts/dialogs/scatterplot-dialog.html | 41 + .../scripts/dialogs/scatterplot-dialog.js | 232 + .../scripts/dialogs/sql-exporter-dialog.html | 131 + .../scripts/dialogs/sql-exporter-dialog.js | 477 + .../dialogs/templating-exporter-dialog.html | 31 + .../dialogs/templating-exporter-dialog.js | 180 + .../modules/core/scripts/facets/facet.js | 69 + .../modules/core/scripts/facets/list-facet.js | 736 + .../core/scripts/facets/range-facet.js | 387 + .../core/scripts/facets/scatterplot-facet.js | 362 + .../core/scripts/facets/text-search-facet.js | 213 + .../core/scripts/facets/timerange-facet.js | 414 + .../main/webapp/modules/core/scripts/index.js | 246 + .../index/create-project-error-panel.html | 5 + .../index/create-project-progress-panel.html | 14 + .../create-project-ui-source-selection.html | 14 + .../core/scripts/index/create-project-ui.js | 278 + .../controller.js | 376 + .../file-selection-panel.html | 36 + .../file-selection-panel.js | 361 + .../parsing-panel.html | 35 + .../parsing-panel.js | 210 + .../import-from-clipboard-form.html | 6 + .../import-from-computer-form.html | 5 + .../import-from-web-form.html | 8 + .../default-importing-sources/sources.js | 142 + .../scripts/index/edit-metadata-dialog.js | 148 + .../core/scripts/index/import-project-ui.html | 17 + .../core/scripts/index/import-project-ui.js | 66 + .../core/scripts/index/lang-settings-ui.html | 19 + .../core/scripts/index/lang-settings-ui.js | 57 + .../core/scripts/index/open-project-ui.html | 9 + .../core/scripts/index/open-project-ui.js | 429 + .../parser-interfaces/excel-parser-ui.html | 54 + .../parser-interfaces/excel-parser-ui.js | 262 + .../fixed-width-parser-ui.html | 60 + .../fixed-width-parser-ui.js | 494 + .../json-parser-select-ui.html | 2 + .../parser-interfaces/json-parser-ui.html | 34 + .../index/parser-interfaces/json-parser-ui.js | 299 + .../line-based-parser-ui.html | 52 + .../parser-interfaces/line-based-parser-ui.js | 212 + .../index/parser-interfaces/preview-table.js | 120 + .../rdf-triples-parser-ui.html | 21 + .../rdf-triples-parser-ui.js | 138 + .../separator-based-parser-ui.html | 92 + .../separator-based-parser-ui.js | 297 + .../parser-interfaces/wikitext-parser-ui.html | 44 + .../parser-interfaces/wikitext-parser-ui.js | 240 + .../xml-parser-select-ui.html | 4 + .../parser-interfaces/xml-parser-ui.html | 35 + .../index/parser-interfaces/xml-parser-ui.js | 298 + .../scripts/index/select-encoding-dialog.html | 22 + .../modules/core/scripts/preferences.js | 228 + .../webapp/modules/core/scripts/project.js | 620 + .../core/scripts/project/browsing-engine.js | 311 + .../scripts/project/edit-metadata-dialog.html | 11 + .../modules/core/scripts/project/exporters.js | 173 + .../core/scripts/project/extension-bar.js | 89 + .../scripts/project/history-apply-dialog.html | 14 + .../core/scripts/project/history-entry.html | 1 + .../project/history-extract-dialog.html | 29 + .../core/scripts/project/history-panel.html | 20 + .../core/scripts/project/history-panel.js | 323 + .../core/scripts/project/process-panel.js | 261 + .../core/scripts/project/progress-panel.html | 15 + .../modules/core/scripts/project/scripting.js | 56 + .../core/scripts/project/summary-bar.js | 53 + .../add-namespaced-service-dialog.html | 13 + .../add-standard-service-dialog.html | 13 + .../scripts/reconciliation/recon-dialog.html | 33 + .../scripts/reconciliation/recon-dialog.js | 233 + .../scripts/reconciliation/recon-manager.js | 197 + .../standard-service-panel.html | 38 + .../reconciliation/standard-service-panel.js | 338 + .../webapp/modules/core/scripts/util/ajax.js | 60 + .../core/scripts/util/custom-suggest.js | 162 + .../modules/core/scripts/util/date-time.js | 232 + .../modules/core/scripts/util/dialog.js | 124 + .../webapp/modules/core/scripts/util/dom.js | 128 + .../modules/core/scripts/util/encoding.js | 83 + .../modules/core/scripts/util/filter-lists.js | 66 + .../webapp/modules/core/scripts/util/menu.js | 279 + .../webapp/modules/core/scripts/util/misc.js | 85 + .../scripts/util/select-encoding-dialog.html | 22 + .../webapp/modules/core/scripts/util/sign.js | 137 + .../modules/core/scripts/util/string.js | 62 + .../webapp/modules/core/scripts/util/url.js | 104 + .../add-column-by-fetching-urls-dialog.html | 38 + .../add-column-by-reconciliation.html | 27 + .../views/data-table/add-column-dialog.html | 28 + .../views/data-table/add-q-column-dialog.html | 19 + .../scripts/views/data-table/cell-editor.html | 24 + .../cell-recon-preview-popup-header.html | 5 + .../cell-recon-search-for-match.html | 27 + .../core/scripts/views/data-table/cell-ui.js | 678 + .../views/data-table/column-header-ui.js | 404 + .../views/data-table/column-header.html | 2 + .../scripts/views/data-table/column-join.html | 64 + .../copy-recon-across-columns-dialog.html | 34 + .../views/data-table/data-table-view.js | 1159 + .../extend-data-preview-dialog.html | 26 + .../views/data-table/key-value-columnize.html | 23 + .../views/data-table/menu-edit-cells.js | 755 + .../views/data-table/menu-edit-column.js | 610 + .../scripts/views/data-table/menu-facets.js | 310 + .../views/data-table/menu-reconcile.js | 528 + .../views/data-table/replace-dialog.html | 60 + .../data-table/sorting-criterion-dialog.html | 54 + .../views/data-table/split-column-dialog.html | 59 + .../split-multi-valued-cells-dialog.html | 62 + .../data-table/text-transform-dialog.html | 27 + .../transpose-columns-into-rows.html | 70 + .../data-table/warn-of-pending-sort.html | 17 + .../core/scripts/widgets/histogram-widget.js | 160 + .../core/scripts/widgets/slider-widget.js | 232 + .../webapp/modules/core/styles/common.less | 438 + .../styles/dialogs/clustering-dialog.less | 119 + .../dialogs/column-reordering-dialog.less | 49 + .../custom-tabular-exporter-dialog.less | 73 + .../dialogs/expression-preview-dialog.less | 125 + .../styles/dialogs/scatterplot-dialog.less | 79 + .../styles/dialogs/sql-exporter-dialog.less | 101 + .../webapp/modules/core/styles/index.less | 123 + .../core/styles/index/create-project-ui.less | 146 + .../index/default-importing-controller.less | 40 + ...efault-importing-file-selection-panel.less | 76 + .../default-importing-parsing-panel.less | 92 + .../index/default-importing-sources.less | 43 + .../styles/index/fixed-width-parser-ui.less | 90 + .../core/styles/index/import-project-ui.less | 39 + .../core/styles/index/json-parser-ui.less | 82 + .../core/styles/index/open-project-ui.less | 206 + .../core/styles/index/wikitext-parser-ui.less | 42 + .../core/styles/index/xml-parser-ui.less | 66 + .../core/styles/jquery-ui-overrides.less | 110 + .../webapp/modules/core/styles/project.less | 138 + .../modules/core/styles/project/facets.less | 375 + .../modules/core/styles/project/process.less | 62 + .../modules/core/styles/project/sidebar.less | 261 + .../main/webapp/modules/core/styles/pure.css | 44 + .../extend-data-preview-dialog.less | 85 + .../styles/reconciliation/recon-dialog.less | 127 + .../standard-service-panel.less | 54 + .../webapp/modules/core/styles/theme.less | 118 + .../core/styles/util/custom-suggest.less | 38 + .../modules/core/styles/util/dialog.less | 93 + .../modules/core/styles/util/encoding.less | 50 + .../webapp/modules/core/styles/util/menu.less | 88 + .../core/styles/views/column-join.less | 85 + .../core/styles/views/data-table-view.less | 415 + .../core/styles/widgets/histogram-widget.less | 44 + .../core/styles/widgets/slider-widget.less | 90 + OpenRefine/packaging/butterfly.properties | 38 + OpenRefine/packaging/linux.xml | 84 + OpenRefine/packaging/openrefine.ico | Bin 0 -> 65582 bytes OpenRefine/packaging/pom.xml | 416 + OpenRefine/packaging/test_pom.xml | 23 + OpenRefine/packaging/windows.xml | 102 + OpenRefine/pom.xml | 365 + OpenRefine/refine | 1009 + OpenRefine/refine.bat | 283 + OpenRefine/refine.ini | 35 + OpenRefine/server/IDEs/eclipse/README.txt | 38 + OpenRefine/server/IDEs/netbeans/manifest.mf | 3 + OpenRefine/server/IDEs/netbeans/nbbuild.xml | 74 + .../IDEs/netbeans/nbproject/build-impl.xml | 872 + .../netbeans/nbproject/genfiles.properties | 8 + .../netbeans/nbproject/project.properties | 90 + .../IDEs/netbeans/nbproject/project.xml | 13 + .../lib-local/native/windows/jdatapath.dll | Bin 0 -> 41472 bytes OpenRefine/server/pom.xml | 201 + .../src/com/google/refine/Configurations.java | 73 + .../server/src/com/google/refine/Refine.java | 526 + .../google/refine/ValidateHostHandler.java | 104 + .../google/util/logging/IndentingLayout.java | 173 + .../threads/ThreadPoolExecutorAdapter.java | 122 + OpenRefine/server/src/log4j2.properties | 41 + OpenRefine/settings.xml | 26 + 1929 files changed, 651039 insertions(+) create mode 100644 OpenRefine/.gitattributes create mode 100644 OpenRefine/.gitignore create mode 100644 OpenRefine/CODE_OF_CONDUCT.md create mode 100644 OpenRefine/CONTRIBUTING.md create mode 100644 OpenRefine/Dockerfile create mode 100644 OpenRefine/GOVERNANCE.md create mode 100644 OpenRefine/IDEs/eclipse/README.txt create mode 100644 OpenRefine/IDEs/eclipse/Refine-codetemplates.xml create mode 100644 OpenRefine/IDEs/eclipse/Refine.style.xml create mode 100644 OpenRefine/LICENSE.txt create mode 100644 OpenRefine/README.md create mode 100644 OpenRefine/SECURITY.md create mode 100644 OpenRefine/appveyor.yml create mode 100644 OpenRefine/benchmark/pom.xml create mode 100644 OpenRefine/benchmark/src/main/java/org/openrefine/benchmark/ToNumberBenchmark.java create mode 100644 OpenRefine/conf/openrefine.l4j.ini create mode 100644 OpenRefine/conf/pmd.rules.xml create mode 100644 OpenRefine/docs/.gitignore create mode 100644 OpenRefine/docs/.node-version create mode 100644 OpenRefine/docs/README.md create mode 100644 OpenRefine/docs/crowdin.yml create mode 100644 OpenRefine/docs/docs/index.md create mode 100644 OpenRefine/docs/docs/manual/cellediting.md create mode 100644 OpenRefine/docs/docs/manual/columnediting.md create mode 100644 OpenRefine/docs/docs/manual/exploring.md create mode 100644 OpenRefine/docs/docs/manual/exporting.md create mode 100644 OpenRefine/docs/docs/manual/expressions.md create mode 100644 OpenRefine/docs/docs/manual/facets.md create mode 100644 OpenRefine/docs/docs/manual/grel.md create mode 100644 OpenRefine/docs/docs/manual/grelfunctions.md create mode 100644 OpenRefine/docs/docs/manual/installing.md create mode 100644 OpenRefine/docs/docs/manual/jythonclojure.md create mode 100644 OpenRefine/docs/docs/manual/reconciling.md create mode 100644 OpenRefine/docs/docs/manual/running.md create mode 100644 OpenRefine/docs/docs/manual/sortview.md create mode 100644 OpenRefine/docs/docs/manual/starting.md create mode 100644 OpenRefine/docs/docs/manual/transforming.md create mode 100644 OpenRefine/docs/docs/manual/transposing.md create mode 100644 OpenRefine/docs/docs/manual/troubleshooting.md create mode 100644 OpenRefine/docs/docs/manual/wikibase/advanced-schemas.md create mode 100644 OpenRefine/docs/docs/manual/wikibase/configuration.md create mode 100644 OpenRefine/docs/docs/manual/wikibase/new-entities.md create mode 100644 OpenRefine/docs/docs/manual/wikibase/overview.md create mode 100644 OpenRefine/docs/docs/manual/wikibase/quality-assurance.md create mode 100644 OpenRefine/docs/docs/manual/wikibase/reconciling.md create mode 100644 OpenRefine/docs/docs/manual/wikibase/schema-alignment.md create mode 100644 OpenRefine/docs/docs/manual/wikibase/uploading.md create mode 100644 OpenRefine/docs/docs/technical-reference/architecture.md create mode 100644 OpenRefine/docs/docs/technical-reference/build-test-run.md create mode 100644 OpenRefine/docs/docs/technical-reference/contributing.md create mode 100644 OpenRefine/docs/docs/technical-reference/development-roadmap.md create mode 100644 OpenRefine/docs/docs/technical-reference/functional-tests.md create mode 100644 OpenRefine/docs/docs/technical-reference/homebrew-cask-process.md create mode 100644 OpenRefine/docs/docs/technical-reference/maintainer-guidelines.md create mode 100644 OpenRefine/docs/docs/technical-reference/migrating-older-extensions.md create mode 100644 OpenRefine/docs/docs/technical-reference/openrefine-api.md create mode 100644 OpenRefine/docs/docs/technical-reference/reconciliation-api.md create mode 100644 OpenRefine/docs/docs/technical-reference/technical-reference-index.md create mode 100644 OpenRefine/docs/docs/technical-reference/translating-docs.md create mode 100644 OpenRefine/docs/docs/technical-reference/translating-ui.md create mode 100644 OpenRefine/docs/docs/technical-reference/version-release-process.md create mode 100644 OpenRefine/docs/docs/technical-reference/writing-extensions.md create mode 100644 OpenRefine/docs/docusaurus.config.js create mode 100644 OpenRefine/docs/netlify.toml create mode 100644 OpenRefine/docs/package.json create mode 100644 OpenRefine/docs/sidebars.js create mode 100644 OpenRefine/docs/src/css/custom.css create mode 100644 OpenRefine/docs/src/theme/Footer/Footer.js create mode 100644 OpenRefine/docs/static/css/custom.css create mode 100644 OpenRefine/docs/static/img/cluster.png create mode 100644 OpenRefine/docs/static/img/columnjoin.png create mode 100644 OpenRefine/docs/static/img/columnreconciled.png create mode 100644 OpenRefine/docs/static/img/columnsplit.png create mode 100644 OpenRefine/docs/static/img/custom-tabular-exporter.png create mode 100644 OpenRefine/docs/static/img/custom-tabular-exporter2.png create mode 100644 OpenRefine/docs/static/img/dates.png create mode 100644 OpenRefine/docs/static/img/eclipse-debug-config.png create mode 100644 OpenRefine/docs/static/img/eclipse-exec-config.png create mode 100644 OpenRefine/docs/static/img/eclipse-import-maven-project-1.png create mode 100644 OpenRefine/docs/static/img/eclipse-import-maven-project-2.png create mode 100644 OpenRefine/docs/static/img/env.png create mode 100644 OpenRefine/docs/static/img/error.png create mode 100644 OpenRefine/docs/static/img/export-menu.png create mode 100644 OpenRefine/docs/static/img/expression-editor.png create mode 100644 OpenRefine/docs/static/img/facetfilter.png create mode 100644 OpenRefine/docs/static/img/failed-visual-test.png create mode 100644 OpenRefine/docs/static/img/fetchingURLs.png create mode 100644 OpenRefine/docs/static/img/goto.png create mode 100644 OpenRefine/docs/static/img/history.png create mode 100644 OpenRefine/docs/static/img/intellij-maven.png create mode 100644 OpenRefine/docs/static/img/intellij-module-settings.png create mode 100644 OpenRefine/docs/static/img/intellij-open-module-settings.png create mode 100644 OpenRefine/docs/static/img/intellij-setup-1.png create mode 100644 OpenRefine/docs/static/img/javahome.png create mode 100644 OpenRefine/docs/static/img/null.png create mode 100644 OpenRefine/docs/static/img/numericfacet.png create mode 100644 OpenRefine/docs/static/img/numericlogfacet.png create mode 100644 OpenRefine/docs/static/img/openrefine_logo.png create mode 100644 OpenRefine/docs/static/img/projectscreen.png create mode 100644 OpenRefine/docs/static/img/reconcile-ambiguous.gif create mode 100644 OpenRefine/docs/static/img/reconcile-by-type.png create mode 100644 OpenRefine/docs/static/img/reconcile-with-property.png create mode 100644 OpenRefine/docs/static/img/reconcileGND.png create mode 100644 OpenRefine/docs/static/img/reconcileIDerror.png create mode 100644 OpenRefine/docs/static/img/reconcileParis.gif create mode 100644 OpenRefine/docs/static/img/reconcileelements.gif create mode 100644 OpenRefine/docs/static/img/reconcilehover.png create mode 100644 OpenRefine/docs/static/img/reconcilewindow.png create mode 100644 OpenRefine/docs/static/img/reconcilewindow2.png create mode 100644 OpenRefine/docs/static/img/scatterplot.png create mode 100644 OpenRefine/docs/static/img/sort.png create mode 100644 OpenRefine/docs/static/img/sort2.png create mode 100644 OpenRefine/docs/static/img/sortPermanent.png create mode 100644 OpenRefine/docs/static/img/sql-exporter.png create mode 100644 OpenRefine/docs/static/img/sql-exporter2.png create mode 100644 OpenRefine/docs/static/img/templating-exporter.png create mode 100644 OpenRefine/docs/static/img/timelinefacet.png create mode 100644 OpenRefine/docs/static/img/transpose1.png create mode 100644 OpenRefine/docs/static/img/transpose2.png create mode 100644 OpenRefine/docs/static/img/unicodefacet.png create mode 100644 OpenRefine/docs/static/img/visual-test-cypress-failure.png create mode 100644 OpenRefine/docs/static/img/wikidata-login.png create mode 100644 OpenRefine/docs/static/img/wikidata-schema.png create mode 100644 OpenRefine/docs/static/img/wikidata-terms.png create mode 100644 OpenRefine/docs/static/img/wikidata-terms2.png create mode 100644 OpenRefine/docs/static/img/wikidata-translated.png create mode 100644 OpenRefine/docs/static/img/yeardata.png create mode 100644 OpenRefine/docs/static/js/fix-location.js create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/index.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/cellediting.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/columnediting.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/exploring.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/exporting.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/expressions.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/facets.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/grel.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/grelfunctions.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/installing.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/jythonclojure.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/reconciling.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/running.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/sortview.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/starting.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/transforming.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/transposing.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/troubleshooting.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/manual/wikidata.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/architecture.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/build-test-run.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/contributing.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/data-extension-api.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/development-roadmap.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/functional-tests.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/homebrew-cask-process.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/migrating-older-extensions.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/openrefine-api.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/reconciliation-api.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/suggest-api.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/technical-reference-index.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/translating.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/version-release-process.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.4/technical-reference/writing-extensions.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/index.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/cellediting.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/columnediting.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/exploring.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/exporting.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/expressions.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/facets.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/grel.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/grelfunctions.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/installing.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/jythonclojure.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/reconciling.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/running.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/sortview.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/starting.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/transforming.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/transposing.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/troubleshooting.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/advanced-schemas.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/configuration.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/new-entities.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/overview.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/quality-assurance.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/reconciling.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/schema-alignment.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/uploading.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/architecture.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/build-test-run.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/contributing.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/development-roadmap.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/functional-tests.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/homebrew-cask-process.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/maintainer-guidelines.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/migrating-older-extensions.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/openrefine-api.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/reconciliation-api.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/technical-reference-index.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/translating-docs.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/translating-ui.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/version-release-process.md create mode 100644 OpenRefine/docs/versioned_docs/version-3.5/technical-reference/writing-extensions.md create mode 100644 OpenRefine/docs/versioned_sidebars/version-3.4-sidebars.json create mode 100644 OpenRefine/docs/versioned_sidebars/version-3.5-sidebars.json create mode 100644 OpenRefine/docs/versions.json create mode 100644 OpenRefine/docs/yarn.lock create mode 100644 OpenRefine/extensions/database/.eclipse-pmd create mode 100644 OpenRefine/extensions/database/.eslintrc.json create mode 100644 OpenRefine/extensions/database/.travis.yml create mode 100644 OpenRefine/extensions/database/README.md create mode 100644 OpenRefine/extensions/database/licenses/jdbc-client.LICENSE.txt create mode 100644 OpenRefine/extensions/database/module/MOD-INF/.gitignore create mode 100644 OpenRefine/extensions/database/module/MOD-INF/controller.js create mode 100644 OpenRefine/extensions/database/module/MOD-INF/dbextension.properties create mode 100644 OpenRefine/extensions/database/module/MOD-INF/module.properties create mode 100644 OpenRefine/extensions/database/module/images/fonts/glyphicons-halflings-regular.eot create mode 100644 OpenRefine/extensions/database/module/images/fonts/glyphicons-halflings-regular.svg create mode 100644 OpenRefine/extensions/database/module/images/fonts/glyphicons-halflings-regular.ttf create mode 100644 OpenRefine/extensions/database/module/images/fonts/glyphicons-halflings-regular.woff create mode 100644 OpenRefine/extensions/database/module/images/fonts/glyphicons-halflings-regular.woff2 create mode 100644 OpenRefine/extensions/database/module/images/more-option-horiz-16.png create mode 100644 OpenRefine/extensions/database/module/images/more_option-vert-16.png create mode 100644 OpenRefine/extensions/database/module/index.vt create mode 100644 OpenRefine/extensions/database/module/langs/translation-bn.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-cs.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-en.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-en_GB.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-eu.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-fr.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-he.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-id.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-it.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-jp.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-ko.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-ml.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-nb_NO.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-pl.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-pt.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-pt_BR.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-sv.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-tr.json create mode 100644 OpenRefine/extensions/database/module/langs/translation-zh_Hans.json create mode 100644 OpenRefine/extensions/database/module/macros.vm create mode 100644 OpenRefine/extensions/database/module/scripts/database-extension.js create mode 100644 OpenRefine/extensions/database/module/scripts/index/database-import-controller.js create mode 100644 OpenRefine/extensions/database/module/scripts/index/database-import-form.html create mode 100644 OpenRefine/extensions/database/module/scripts/index/database-parsing-panel.html create mode 100644 OpenRefine/extensions/database/module/scripts/index/database-source-ui.js create mode 100644 OpenRefine/extensions/database/module/scripts/index/jquery.contextMenu.min.js create mode 100644 OpenRefine/extensions/database/module/scripts/index/jquery.ui.position.min.js create mode 100644 OpenRefine/extensions/database/module/scripts/project/database-exporters.js create mode 100644 OpenRefine/extensions/database/module/styles/bootstrap.css create mode 100644 OpenRefine/extensions/database/module/styles/database-import.less create mode 100644 OpenRefine/extensions/database/module/styles/jquery.contextMenu.css create mode 100644 OpenRefine/extensions/database/module/styles/pure.css create mode 100644 OpenRefine/extensions/database/module/styles/theme.less create mode 100644 OpenRefine/extensions/database/pom.xml create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/DBQueryResultImportReader.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/DBQueryResultPreviewReader.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseColumnType.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseConfiguration.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseImportController.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseModuleImpl.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseService.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseServiceException.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseUtils.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/SQLType.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/SavedConnectionContainer.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/SimpleTextEncryptor.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/ConnectCommand.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/DatabaseCommand.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/ExecuteQueryCommand.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/SavedConnectionCommand.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/TestConnectCommand.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/TestQueryCommand.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/mariadb/MariaDBConnectionManager.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/mariadb/MariaDBDatabaseService.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseColumn.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseInfo.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseQueryInfo.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseRow.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseTable.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/mysql/MySQLConnectionManager.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/mysql/MySQLDatabaseService.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/pgsql/PgSQLConnectionManager.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/pgsql/PgSQLDatabaseService.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManager.java create mode 100644 OpenRefine/extensions/database/src/com/google/refine/extension/database/sqlite/SQLiteDatabaseService.java create mode 100644 OpenRefine/extensions/database/tests/conf/appveyor_tests.xml create mode 100644 OpenRefine/extensions/database/tests/conf/github_actions_tests.xml create mode 100644 OpenRefine/extensions/database/tests/conf/test-mariadb.sql create mode 100644 OpenRefine/extensions/database/tests/conf/test-mysql.sql create mode 100644 OpenRefine/extensions/database/tests/conf/test-pgsql.sql create mode 100644 OpenRefine/extensions/database/tests/conf/test-sqlite.sql create mode 100644 OpenRefine/extensions/database/tests/conf/tests.xml create mode 100644 OpenRefine/extensions/database/tests/log4j-test.properties create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DBExtensionTestUtils.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DBExtensionTests.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DatabaseImportControllerTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DatabaseServiceTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitMariaDBTestDatabase.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitMySQLTestDatabase.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitPostgresTestDatabase.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitSQLiteTestDatabase.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/SimpleTextEncryptorTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/ConnectCommandTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/ExecuteQueryCommandTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/SavedConnectionCommandTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/TestConnectCommandTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/TestQueryCommandTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mariadb/MariaDBConnectionManagerTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mariadb/MariaDBDatabaseServiceTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mysql/MySQLConnectionManagerTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mysql/MySQLDatabaseServiceTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/pgsql/PgSQLConnectionManagerTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/pgsql/PgSQLDatabaseServiceTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManagerTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteDatabaseServiceTest.java create mode 100644 OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/stub/RefineDbServletStub.java create mode 100644 OpenRefine/extensions/gdata/LICENSE.txt create mode 100644 OpenRefine/extensions/gdata/README.txt create mode 100644 OpenRefine/extensions/gdata/module/MOD-INF/controller.js create mode 100644 OpenRefine/extensions/gdata/module/MOD-INF/module.properties create mode 100644 OpenRefine/extensions/gdata/module/authorize.vt create mode 100644 OpenRefine/extensions/gdata/module/authorized.vt create mode 100644 OpenRefine/extensions/gdata/module/index.vt create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-bn.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-bn_IN.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-cs.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-en.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-en_GB.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-es.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-fr.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-he.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-it.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-jp.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-ko.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-nb_NO.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-pl.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-pt.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-pt_BR.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-pt_PT.json create mode 100644 OpenRefine/extensions/gdata/module/langs/translation-sv.json create mode 100644 OpenRefine/extensions/gdata/module/macros.vm create mode 100644 OpenRefine/extensions/gdata/module/scripts/gdata-extension.js create mode 100644 OpenRefine/extensions/gdata/module/scripts/index/gdata-parsing-panel.html create mode 100644 OpenRefine/extensions/gdata/module/scripts/index/gdata-source-ui.js create mode 100644 OpenRefine/extensions/gdata/module/scripts/index/import-from-gdata-form.html create mode 100644 OpenRefine/extensions/gdata/module/scripts/index/importing-controller.js create mode 100644 OpenRefine/extensions/gdata/module/scripts/project/exporters.js create mode 100644 OpenRefine/extensions/gdata/module/styles/importing-controller.less create mode 100644 OpenRefine/extensions/gdata/module/styles/project-injection.less create mode 100644 OpenRefine/extensions/gdata/module/styles/theme.less create mode 100644 OpenRefine/extensions/gdata/pom.xml create mode 100644 OpenRefine/extensions/gdata/src/com/google/refine/extension/gdata/DeAuthorizeCommand.java create mode 100644 OpenRefine/extensions/gdata/src/com/google/refine/extension/gdata/GDataImporter.java create mode 100644 OpenRefine/extensions/gdata/src/com/google/refine/extension/gdata/GDataImportingController.java create mode 100644 OpenRefine/extensions/gdata/src/com/google/refine/extension/gdata/GoogleAPIExtension.java create mode 100644 OpenRefine/extensions/gdata/src/com/google/refine/extension/gdata/SpreadsheetSerializer.java create mode 100644 OpenRefine/extensions/gdata/src/com/google/refine/extension/gdata/TokenCookie.java create mode 100644 OpenRefine/extensions/gdata/src/com/google/refine/extension/gdata/UploadCommand.java create mode 100644 OpenRefine/extensions/gdata/src/com/google/refine/extension/gdata/logo-openrefine-550.png create mode 100644 OpenRefine/extensions/gdata/tests/conf/tests.xml create mode 100644 OpenRefine/extensions/gdata/tests/src/com/google/refine/extension/gdata/GoogleAPIExtensionTest.java create mode 100644 OpenRefine/extensions/gdata/tests/src/com/google/refine/extension/gdata/SpreadsheetSerializerTests.java create mode 100644 OpenRefine/extensions/gdata/tests/src/com/google/refine/extension/gdata/UploadCommandTest.java create mode 100644 OpenRefine/extensions/jython/.gitignore create mode 100644 OpenRefine/extensions/jython/module/MOD-INF/controller.js create mode 100644 OpenRefine/extensions/jython/module/MOD-INF/module.properties create mode 100644 OpenRefine/extensions/jython/pom.xml create mode 100644 OpenRefine/extensions/jython/src/com/google/refine/jython/JythonEvaluable.java create mode 100644 OpenRefine/extensions/jython/src/com/google/refine/jython/JythonHasFieldsWrapper.java create mode 100644 OpenRefine/extensions/jython/src/com/google/refine/jython/JythonObjectWrapper.java create mode 100644 OpenRefine/extensions/jython/tests/conf/tests.xml create mode 100644 OpenRefine/extensions/jython/tests/src/com/google/refine/jython/JythonAttributeTest.java create mode 100644 OpenRefine/extensions/jython/tests/src/com/google/refine/jython/JythonEvaluableTest.java create mode 100644 OpenRefine/extensions/jython/tests/src/tests.log4j.properties create mode 100644 OpenRefine/extensions/pc-axis/module/MOD-INF/controller.js create mode 100644 OpenRefine/extensions/pc-axis/module/MOD-INF/module.properties create mode 100644 OpenRefine/extensions/pc-axis/module/langs/translation-en.json create mode 100644 OpenRefine/extensions/pc-axis/module/scripts/pc-axis-parser-ui.html create mode 100644 OpenRefine/extensions/pc-axis/module/scripts/pc-axis-parser-ui.js create mode 100644 OpenRefine/extensions/pc-axis/pom.xml create mode 100644 OpenRefine/extensions/pc-axis/src/com/google/refine/pcaxis/PCAxisImporter.java create mode 100644 OpenRefine/extensions/pc-axis/src/com/google/refine/pcaxis/PCAxisTableDataReader.java create mode 100644 OpenRefine/extensions/phonetic/.gitignore create mode 100644 OpenRefine/extensions/phonetic/module/MOD-INF/controller.js create mode 100644 OpenRefine/extensions/phonetic/module/MOD-INF/module.properties create mode 100644 OpenRefine/extensions/phonetic/module/langs/translation-en.json create mode 100644 OpenRefine/extensions/phonetic/module/macros.vm create mode 100644 OpenRefine/extensions/phonetic/module/scripts/load-language.js create mode 100644 OpenRefine/extensions/phonetic/pom.xml create mode 100644 OpenRefine/extensions/phonetic/src/org/openrefine/phonetic/keyers/BeiderMorseKeyer.java create mode 100644 OpenRefine/extensions/phonetic/src/org/openrefine/phonetic/keyers/DaitchMokotoffKeyer.java create mode 100644 OpenRefine/extensions/phonetic/tests/conf/tests.xml create mode 100644 OpenRefine/extensions/phonetic/tests/src/org/openrefine/phonetic/keyers/BeiderMorseKeyerTest.java create mode 100644 OpenRefine/extensions/phonetic/tests/src/org/openrefine/phonetic/keyers/DaitchMokotoffKeyerTest.java create mode 100644 OpenRefine/extensions/pom.xml create mode 100644 OpenRefine/extensions/sample/.gitignore create mode 100644 OpenRefine/extensions/sample/module/MOD-INF/controller.js create mode 100644 OpenRefine/extensions/sample/module/MOD-INF/module.properties create mode 100644 OpenRefine/extensions/sample/module/index.vt create mode 100644 OpenRefine/extensions/sample/module/macros.vm create mode 100644 OpenRefine/extensions/sample/module/scripts/project-injection.js create mode 100644 OpenRefine/extensions/sample/module/styles/project-injection.less create mode 100644 OpenRefine/extensions/sample/pom.xml create mode 100644 OpenRefine/extensions/sample/src/com/google/refine/sampleExtension/SampleUtil.java create mode 100644 OpenRefine/extensions/wikidata/.gitignore create mode 100644 OpenRefine/extensions/wikidata/credits.txt create mode 100644 OpenRefine/extensions/wikidata/module/MOD-INF/controller.js create mode 100644 OpenRefine/extensions/wikidata/module/MOD-INF/module.properties create mode 100644 OpenRefine/extensions/wikidata/module/images/Critical.png create mode 100644 OpenRefine/extensions/wikidata/module/images/Critical.svg create mode 100644 OpenRefine/extensions/wikidata/module/images/Important.png create mode 100644 OpenRefine/extensions/wikidata/module/images/Important.svg create mode 100644 OpenRefine/extensions/wikidata/module/images/Information.png create mode 100644 OpenRefine/extensions/wikidata/module/images/Information.svg create mode 100644 OpenRefine/extensions/wikidata/module/images/Warning.png create mode 100644 OpenRefine/extensions/wikidata/module/images/Warning.svg create mode 100644 OpenRefine/extensions/wikidata/module/images/Wikibase_logo.png create mode 100644 OpenRefine/extensions/wikidata/module/images/Wikidata-logo-en.svg create mode 100644 OpenRefine/extensions/wikidata/module/images/close-map.png create mode 100644 OpenRefine/extensions/wikidata/module/images/wikidata.png create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-bn.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-cs.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-en.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-en_GB.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-es.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-fi.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-fr.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-he.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-id.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-it.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-jp.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-ko.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-ml.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-nb_NO.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-nl.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-pl.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-pt.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-pt_BR.json create mode 100644 OpenRefine/extensions/wikidata/module/langs/translation-sv.json create mode 100644 OpenRefine/extensions/wikidata/module/scripts/ajv.min.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/bettersuggest.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/dialogs/add-wikibase-dialog.html create mode 100644 OpenRefine/extensions/wikidata/module/scripts/dialogs/import-schema-dialog.html create mode 100644 OpenRefine/extensions/wikidata/module/scripts/dialogs/import-schema-dialog.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/dialogs/logged-in-dialog.html create mode 100644 OpenRefine/extensions/wikidata/module/scripts/dialogs/manage-account-dialog.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/dialogs/owner-only-consumer-login-dialog.html create mode 100644 OpenRefine/extensions/wikidata/module/scripts/dialogs/password-login-dialog.html create mode 100644 OpenRefine/extensions/wikidata/module/scripts/dialogs/perform-edits-dialog.html create mode 100644 OpenRefine/extensions/wikidata/module/scripts/dialogs/perform-edits-dialog.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/dialogs/wikibase-dialog.html create mode 100644 OpenRefine/extensions/wikidata/module/scripts/dialogs/wikibase-dialog.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/issues-tab.html create mode 100644 OpenRefine/extensions/wikidata/module/scripts/jquery.uls.data.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/langsuggest.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/menu-bar-extension.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/preview-tab.html create mode 100644 OpenRefine/extensions/wikidata/module/scripts/previewrenderer.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/schema-alignment-tab.html create mode 100644 OpenRefine/extensions/wikidata/module/scripts/schema-alignment.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/warningsrenderer.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/wikibase-manager.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/wikibase-manifest-schema-v1.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/wikibase-manifest-schema-v2.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/wikibase-suggest.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/wikidata-extension-manager.js create mode 100644 OpenRefine/extensions/wikidata/module/scripts/wikidata-manifest-v1.0.js create mode 100644 OpenRefine/extensions/wikidata/module/styles/dialogs/add-wikibase-dialog.less create mode 100644 OpenRefine/extensions/wikidata/module/styles/dialogs/import-schema-dialog.less create mode 100644 OpenRefine/extensions/wikidata/module/styles/dialogs/manage-account-dialog.less create mode 100644 OpenRefine/extensions/wikidata/module/styles/dialogs/perform-edits.less create mode 100644 OpenRefine/extensions/wikidata/module/styles/dialogs/wikibase-dialog.less create mode 100644 OpenRefine/extensions/wikidata/module/styles/schema-alignment.less create mode 100644 OpenRefine/extensions/wikidata/module/styles/theme.less create mode 100644 OpenRefine/extensions/wikidata/pom.xml create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/commands/CommandUtilities.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/commands/ConnectionManager.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/commands/LoginCommand.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/commands/PerformWikibaseEditsCommand.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/commands/PreviewResults.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/commands/PreviewWikibaseSchemaCommand.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/commands/SaveWikibaseSchemaCommand.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/editing/EditBatchProcessor.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/editing/NewItemLibrary.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/editing/ReconEntityRewriter.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/exporters/QSSnakPrinter.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/exporters/QSValuePrinter.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/exporters/QuickStatementsExporter.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/exporters/SchemaExporter.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/manifests/Manifest.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/manifests/ManifestException.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/manifests/ManifestParser.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/manifests/ManifestV1.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/manifests/ManifestV2.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/operations/PerformWikibaseEditsOperation.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/operations/SaveWikibaseSchemaOperation.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/Constraint.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/ConstraintFetcher.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/EditInspector.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/QAWarning.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/QAWarningStore.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/SchemaPropertyExtractor.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/CalendarScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/CommonDescriptionScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/ConflictsWithScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/DescriptionScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/DifferenceWithinRangeScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/DistinctValuesScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/EditScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/EnglishDescriptionScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/EntityTypeScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/FormatScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/InverseConstraintScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/ItemRequiresScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/MultiValueScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/NewItemScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/NoEditsMadeScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/QualifierCompatibilityScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/QuantityScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/RestrictedPositionScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/RestrictedValuesScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/SelfReferentialScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/SingleValueScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/SnakScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/StatementScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/UnsourcedScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/UseAsQualifierScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/ValueScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/qa/scrutinizers/WhitespaceScrutinizer.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/ExpressionContext.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbDateConstant.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbDateVariable.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbEntityIdValueConstant.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbEntityVariable.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbExpression.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbItemConstant.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbItemDocumentExpr.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbItemVariable.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbLanguageConstant.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbLanguageVariable.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbLocationConstant.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbLocationVariable.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbMonolingualExpr.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbNameDescExpr.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbPropConstant.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbQuantityExpr.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbReferenceExpr.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbSnakExpr.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbStatementExpr.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbStatementGroupExpr.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbStringConstant.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbStringVariable.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WbVariableExpr.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/WikibaseSchema.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/FullyPropertySerializingValueSnak.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/PrefetchedEntityIdValue.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/ReconEntityIdValue.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/ReconItemIdValue.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/ReconMediaInfoIdValue.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/ReconPropertyIdValue.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/SuggestedEntityIdValue.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/SuggestedFormIdValue.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/SuggestedItemIdValue.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/SuggestedLexemeIdValue.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/SuggestedMediaInfoIdValue.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/SuggestedPropertyIdValue.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/entityvalues/SuggestedSenseIdValue.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/exceptions/InvalidSchemaException.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/exceptions/NewItemNotCreatedYetException.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/schema/exceptions/SkipSchemaExpressionException.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/updates/TermedStatementEntityUpdate.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/updates/TermedStatementEntityUpdateBuilder.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/updates/scheduler/ImpossibleSchedulingException.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/updates/scheduler/PointerExtractor.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/updates/scheduler/QuickStatementsUpdateScheduler.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/updates/scheduler/UpdateScheduler.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/updates/scheduler/UpdateSequence.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/updates/scheduler/WikibaseAPIUpdateScheduler.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/utils/EntityCache.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/utils/LanguageCodeStore.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/utils/SnakUtils.java create mode 100644 OpenRefine/extensions/wikidata/src/org/openrefine/wikidata/utils/StatementGroupJson.java create mode 100644 OpenRefine/extensions/wikidata/tests/conf/tests.xml create mode 100644 OpenRefine/extensions/wikidata/tests/data/entitycache/entitycache-P2427.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/entitycache/entitycache-P25.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/entitycache/entitycache-P31.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/entitycache/entitycache-P361.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/entitycache/entitycache-P571.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/entitycache/entitycache-P580.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/entitycache/entitycache-P6.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/entitycache/entitycache-P813.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/entitycache/entitycache-P854.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/langcode/wikidata-monolingualtext-langcode.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/manifest/commons-manifest-v2.0.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/manifest/wikidata-manifest-v1.0-missing-property-constraint-pid.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/manifest/wikidata-manifest-v1.0-without-constraints.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/manifest/wikidata-manifest-v1.0.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/operations/perform-edits.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/operations/save-schema.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/schema/history_of_medicine.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/schema/history_of_medicine_normalized.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/schema/inception.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/schema/roarmap.json create mode 100644 OpenRefine/extensions/wikidata/tests/data/updates/statement_groups.json create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/commands/CommandTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/commands/ConnectionManagerTests.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/commands/LoginCommandTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/commands/PreviewWikibaseSchemaCommandTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/commands/SaveWikibaseSchemaCommandTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/commands/SchemaCommandTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/editing/EditBatchProcessorTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/editing/NewItemLibraryTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/editing/ReconEntityRewriterTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/exporters/QSSnakPrinterTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/exporters/QSValuePrinterTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/exporters/QuickStatementsExporterTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/exporters/SchemaExporterTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/manifests/ManifestTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/operations/OperationTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/operations/PerformWikibaseEditsOperationTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/operations/SaveWikibaseSchemaOperationTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/ConstraintTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/EditInspectorTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/QAWarningStoreTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/QAWarningTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/SchemaPropertyExtractorTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/CalendarScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/CommonDescriptionScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/ConflictsWithScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/DifferenceWithinScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/DistinctValuesScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/EnglishDescriptionScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/EntityTypeScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/FormatScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/InverseConstraintScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/ItemRequiresScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/MultiValueScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/NewItemScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/NoEditsMadeScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/QualifierCompatibilityScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/QuantityScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/RestrictedPositionScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/RestrictedValuesScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/ScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/SelfReferentialScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/SingleValueScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/SnakScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/StatementScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/UnsourcedScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/UseAsQualifierScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/ValueScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/qa/scrutinizers/WhitespaceScrutinizerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/ExpressionContextTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbDateConstantTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbDateVariableTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbEntityIdValueConstantTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbEntityVariableTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbExpressionTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbItemConstantTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbItemDocumentExprTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbItemVariableTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbLanguageConstantTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbLanguageVariableTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbLocationConstantTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbLocationVariableTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbMonolingualExprTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbNameDescExprTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbPropConstantTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbQuantityExprTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbReferenceExprTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbSnakExprTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbStatementExprTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbStatementGroupExprTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbStringConstantTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbStringVariableTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WbVariableTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/WikibaseSchemaTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/entityvalues/ReconEntityIdValueTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/schema/entityvalues/SuggestedEntityIdValueTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/testing/JacksonSerializationTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/testing/TestingData.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/testing/WikidataRefineTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/updates/ItemUpdateTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/updates/scheduler/PointerExtractorTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/updates/scheduler/QuickStatementsUpdateSchedulerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/updates/scheduler/UpdateSchedulerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/updates/scheduler/WikibaseAPIUpdateSchedulerTest.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/utils/EntityCacheStub.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/utils/EntityCacheTests.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/org/openrefine/wikidata/utils/SnakUtilsTests.java create mode 100644 OpenRefine/extensions/wikidata/tests/src/tests.log4j.properties create mode 100644 OpenRefine/graphics/big-check.psd create mode 100644 OpenRefine/graphics/checks-map.psd create mode 100644 OpenRefine/graphics/cop.psd create mode 100644 OpenRefine/graphics/dmg_background/dmg_background.png create mode 100644 OpenRefine/graphics/dmg_background/dmg_background.psd create mode 100644 OpenRefine/graphics/edit-map.psd create mode 100644 OpenRefine/graphics/icon/open-refine-320px.png create mode 100644 OpenRefine/graphics/icon/openrefine.icns create mode 100644 OpenRefine/graphics/icon/openrefine.ico create mode 100644 OpenRefine/graphics/menu-dropdown.psd create mode 100644 OpenRefine/graphics/path-delimiter.psd create mode 100644 OpenRefine/graphics/row-groups.png create mode 100644 OpenRefine/graphics/slider-brackets.psd create mode 100644 OpenRefine/graphics/small-checks.psd create mode 100644 OpenRefine/graphics/star-flag-map.psd create mode 100644 OpenRefine/graphics/star.psd create mode 100644 OpenRefine/main/IDEs/eclipse/README.txt create mode 100644 OpenRefine/main/pom.xml create mode 100644 OpenRefine/main/src/com/google/refine/ClientSideResourceManager.java create mode 100644 OpenRefine/main/src/com/google/refine/HttpResponder.java create mode 100644 OpenRefine/main/src/com/google/refine/LookupCacheManager.java create mode 100644 OpenRefine/main/src/com/google/refine/ProjectManager.java create mode 100644 OpenRefine/main/src/com/google/refine/ProjectMetadata.java create mode 100644 OpenRefine/main/src/com/google/refine/RefineServlet.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/DecoratedValue.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/Engine.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/EngineConfig.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/FilteredRecords.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/FilteredRows.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/RecordFilter.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/RecordVisitor.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/RowFilter.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/RowVisitor.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/facets/Facet.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/facets/FacetConfig.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/facets/FacetConfigResolver.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/facets/ListFacet.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/facets/NominalFacetChoice.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/facets/RangeFacet.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/facets/ScatterplotDrawingRowVisitor.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/facets/ScatterplotFacet.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/facets/TextSearchFacet.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/facets/TimeRangeFacet.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/filters/AllRowsRecordFilter.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/filters/AnyRowRecordFilter.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/filters/DualExpressionsNumberComparisonRowFilter.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/filters/ExpressionEqualRowFilter.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/filters/ExpressionNumberComparisonRowFilter.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/filters/ExpressionStringComparisonRowFilter.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/filters/ExpressionTimeComparisonRowFilter.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/ConjunctiveFilteredRecords.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/ConjunctiveFilteredRows.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/ExpressionBasedRowEvaluable.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/ExpressionNominalValueGrouper.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/ExpressionNumericValueBinner.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/ExpressionTimeValueBinner.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/FilteredRecordsAsFilteredRows.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/NumericBinIndex.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/NumericBinRecordIndex.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/NumericBinRowIndex.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/RowEvaluable.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/RowVisitorAsRecordVisitor.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/TimeBinIndex.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/TimeBinRecordIndex.java create mode 100644 OpenRefine/main/src/com/google/refine/browsing/util/TimeBinRowIndex.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/ClusteredEntry.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/Clusterer.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/ClustererConfig.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/binning/BinningClusterer.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/binning/ColognePhoneticKeyer.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/binning/DoubleMetaphoneKeyer.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/binning/FingerprintKeyer.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/binning/Keyer.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/binning/KeyerFactory.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/binning/Metaphone3.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/binning/Metaphone3Keyer.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/binning/MetaphoneKeyer.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/binning/NGramFingerprintKeyer.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/binning/SoundexKeyer.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/knn/DistanceFactory.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/knn/SimilarityDistance.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/knn/VicinoDistance.java create mode 100644 OpenRefine/main/src/com/google/refine/clustering/knn/kNNClusterer.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/CSRFTokenFactory.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/Command.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/EngineDependentCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/GetAllPreferencesCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/GetCSRFTokenCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/GetPreferenceCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/GetVersionCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/HttpHeadersSupport.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/HttpUtilities.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/OpenWorkspaceDirCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/SetPreferenceCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/browsing/ComputeClustersCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/browsing/ComputeFacetsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/browsing/GetClusteringFunctionsAndDistancesCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/browsing/GetScatterplotCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/cell/BlankDownCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/cell/EditOneCellCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/cell/FillDownCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/cell/JoinMultiValueCellsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/cell/KeyValueColumnizeCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/cell/MassEditCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/cell/SplitMultiValueCellsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/cell/TextTransformCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/cell/TransposeColumnsIntoRowsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/cell/TransposeRowsIntoColumnsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/column/AddColumnByFetchingURLsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/column/AddColumnCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/column/GetColumnsInfoCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/column/MoveColumnCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/column/RemoveColumnCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/column/RenameColumnCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/column/ReorderColumnsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/column/SplitColumnCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/expr/GetExpressionHistoryCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/expr/GetExpressionLanguageInfoCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/expr/GetStarredExpressionsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/expr/LogExpressionCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/expr/PreviewExpressionCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/expr/ToggleStarredExpressionCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/history/ApplyOperationsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/history/CancelProcessesCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/history/GetHistoryCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/history/GetOperationsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/history/GetProcessesCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/history/UndoRedoCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/importing/CancelImportingJobCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/importing/CreateImportingJobCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/importing/GetImportingConfigurationCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/importing/GetImportingJobStatusCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/importing/ImportingControllerCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/lang/GetLanguagesCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/lang/LoadLanguageCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/project/CreateProjectCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/project/DeleteProjectCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/project/ExportProjectCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/project/ExportRowsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/project/GetModelsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/project/GetProjectMetadataCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/project/ImportProjectCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/project/RenameProjectCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/project/SetProjectMetadataCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/project/SetProjectTagsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/ExtendDataCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/GuessTypesOfColumnCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/PreviewExtendDataCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/ReconClearOneCellCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/ReconClearSimilarCellsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/ReconCopyAcrossColumnsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/ReconDiscardJudgmentsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/ReconJudgeOneCellCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/ReconJudgeSimilarCellsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/ReconMarkNewTopicsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/ReconMatchBestCandidatesCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/ReconMatchSpecificTopicCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/ReconUseValuesAsIdentifiersCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/recon/ReconcileCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/row/AnnotateOneRowCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/row/AnnotateRowsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/row/DenormalizeCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/row/GetRowsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/row/RemoveRowsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/row/ReorderRowsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/workspace/GetAllProjectMetadataCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/commands/workspace/GetAllProjectTagsCommand.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/CsvExporter.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/CustomizableTabularExporterUtilities.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/Exporter.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/ExporterRegistry.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/HtmlTableExporter.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/OdsExporter.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/StreamExporter.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/TabularSerializer.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/TemplatingExporter.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/UrlExporter.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/WriterExporter.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/XlsExporter.java create mode 100755 OpenRefine/main/src/com/google/refine/exporters/sql/SqlCreateBuilder.java create mode 100755 OpenRefine/main/src/com/google/refine/exporters/sql/SqlData.java create mode 100755 OpenRefine/main/src/com/google/refine/exporters/sql/SqlExporter.java create mode 100644 OpenRefine/main/src/com/google/refine/exporters/sql/SqlExporterException.java create mode 100755 OpenRefine/main/src/com/google/refine/exporters/sql/SqlInsertBuilder.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/Binder.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/CellTuple.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/EvalError.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/Evaluable.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/ExpressionUtils.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/HasFields.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/HasFieldsList.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/HasFieldsListImpl.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/LanguageSpecificParser.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/MetaParser.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/ParsingException.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/WrappedCell.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/WrappedRow.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/Coalesce.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/Cross.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/FacetCount.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/Get.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/HasField.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/Jsonize.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/Length.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/Slice.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/ToDate.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/ToNumber.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/ToString.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/Type.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/arrays/ArgsToArray.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/arrays/InArray.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/arrays/Join.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/arrays/Reverse.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/arrays/Sort.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/arrays/Uniques.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/booleans/And.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/booleans/Not.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/booleans/Or.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/booleans/Xor.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/date/DatePart.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/date/Inc.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/date/Now.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/html/InnerHtml.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/html/ParseHtml.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/ACos.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/ASin.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/ATan.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/ATan2.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Abs.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Ceil.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Combin.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Cos.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Cosh.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Degrees.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Even.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Exp.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Fact.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/FactN.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Floor.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/GreatestCommonDenominator.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/LeastCommonMultiple.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Ln.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Log.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Max.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Min.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Mod.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Multinomial.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Odd.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Pow.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Quotient.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Radians.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/RandomNumber.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Round.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Sin.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Sinh.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Sum.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Tan.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/math/Tanh.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Chomp.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Contains.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Diff.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/EndsWith.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Escape.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Find.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Fingerprint.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/IndexOf.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/LastIndexOf.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/MD5.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Match.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/NGram.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/NGramFingerprint.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/ParseJson.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Partition.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Phonetic.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/RPartition.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Range.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Reinterpret.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Replace.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/ReplaceChars.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/SHA1.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/SmartSplit.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Split.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/SplitByCharType.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/SplitByLengths.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/StartsWith.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/ToLowercase.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/ToTitlecase.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/ToUppercase.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Trim.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Unescape.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/Unicode.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/strings/UnicodeType.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/xml/InnerXml.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/xml/OwnText.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/xml/Parent.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/xml/ParseXml.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/xml/ScriptText.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/xml/SelectXml.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/xml/WholeText.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/xml/XmlAttr.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/functions/xml/XmlText.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/util/CalendarParser.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/util/CalendarParserException.java create mode 100644 OpenRefine/main/src/com/google/refine/expr/util/JsonValueConverter.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/Control.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/ControlFunctionRegistry.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/Function.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/Parser.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/Scanner.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/ast/ControlCallExpr.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/ast/FieldAccessorExpr.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/ast/FunctionCallExpr.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/ast/LiteralExpr.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/ast/OperatorCallExpr.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/ast/VariableExpr.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/Filter.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/ForEach.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/ForEachIndex.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/ForNonBlank.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/ForRange.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/If.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/IsBlank.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/IsEmptyString.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/IsError.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/IsNonBlank.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/IsNotNull.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/IsNull.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/IsNumeric.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/IsTest.java create mode 100644 OpenRefine/main/src/com/google/refine/grel/controls/With.java create mode 100644 OpenRefine/main/src/com/google/refine/history/Change.java create mode 100644 OpenRefine/main/src/com/google/refine/history/ChangeSequence.java create mode 100644 OpenRefine/main/src/com/google/refine/history/History.java create mode 100644 OpenRefine/main/src/com/google/refine/history/HistoryEntry.java create mode 100644 OpenRefine/main/src/com/google/refine/history/HistoryEntryManager.java create mode 100644 OpenRefine/main/src/com/google/refine/history/HistoryProcess.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/BinaryFormatGuesser.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/ExcelImporter.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/FixedWidthImporter.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/ImportException.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/ImporterUtilities.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/ImportingParserBase.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/JsonImporter.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/LineBasedFormatGuesser.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/LineBasedImporter.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/MarcImporter.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/OdsImporter.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/RdfJsonldTripleImporter.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/RdfTripleImporter.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/RdfXmlTripleImporter.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/SeparatorBasedImporter.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/TabularImportingParserBase.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/TextFormatGuesser.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/WikitextImporter.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/XmlImporter.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/tree/ImportColumn.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/tree/ImportColumnGroup.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/tree/ImportParameters.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/tree/ImportRecord.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/tree/ImportVertical.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/tree/RecordElementCandidate.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/tree/TreeImportUtilities.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/tree/TreeImportingParserBase.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/tree/TreeReader.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/tree/TreeReaderException.java create mode 100644 OpenRefine/main/src/com/google/refine/importers/tree/XmlImportUtilities.java create mode 100644 OpenRefine/main/src/com/google/refine/importing/DefaultImportingController.java create mode 100644 OpenRefine/main/src/com/google/refine/importing/EncodingGuesser.java create mode 100644 OpenRefine/main/src/com/google/refine/importing/FormatGuesser.java create mode 100644 OpenRefine/main/src/com/google/refine/importing/ImportingController.java create mode 100644 OpenRefine/main/src/com/google/refine/importing/ImportingJob.java create mode 100644 OpenRefine/main/src/com/google/refine/importing/ImportingManager.java create mode 100644 OpenRefine/main/src/com/google/refine/importing/ImportingParser.java create mode 100644 OpenRefine/main/src/com/google/refine/importing/ImportingUtilities.java create mode 100644 OpenRefine/main/src/com/google/refine/importing/UrlRewriter.java create mode 100644 OpenRefine/main/src/com/google/refine/io/FileHistoryEntryManager.java create mode 100644 OpenRefine/main/src/com/google/refine/io/FileProjectManager.java create mode 100644 OpenRefine/main/src/com/google/refine/io/ProjectMetadataUtilities.java create mode 100644 OpenRefine/main/src/com/google/refine/io/ProjectUtilities.java create mode 100644 OpenRefine/main/src/com/google/refine/model/AbstractOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/model/Cell.java create mode 100644 OpenRefine/main/src/com/google/refine/model/Column.java create mode 100644 OpenRefine/main/src/com/google/refine/model/ColumnGroup.java create mode 100644 OpenRefine/main/src/com/google/refine/model/ColumnModel.java create mode 100644 OpenRefine/main/src/com/google/refine/model/ModelException.java create mode 100644 OpenRefine/main/src/com/google/refine/model/OverlayModel.java create mode 100644 OpenRefine/main/src/com/google/refine/model/Project.java create mode 100644 OpenRefine/main/src/com/google/refine/model/Recon.java create mode 100644 OpenRefine/main/src/com/google/refine/model/ReconCandidate.java create mode 100644 OpenRefine/main/src/com/google/refine/model/ReconStats.java create mode 100644 OpenRefine/main/src/com/google/refine/model/ReconType.java create mode 100644 OpenRefine/main/src/com/google/refine/model/Record.java create mode 100644 OpenRefine/main/src/com/google/refine/model/RecordModel.java create mode 100644 OpenRefine/main/src/com/google/refine/model/Row.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/CellAtRow.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/CellAtRowCellIndex.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/CellChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/ColumnAdditionChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/ColumnChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/ColumnMoveChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/ColumnRemovalChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/ColumnRenameChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/ColumnReorderChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/ColumnSplitChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/DataExtensionChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/MassCellChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/MassChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/MassReconChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/MassRowChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/MassRowColumnChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/ReconChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/RowFlagChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/RowRemovalChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/RowReorderChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/changes/RowStarChange.java create mode 100644 OpenRefine/main/src/com/google/refine/model/recon/DataExtensionReconConfig.java create mode 100644 OpenRefine/main/src/com/google/refine/model/recon/ReconConfig.java create mode 100644 OpenRefine/main/src/com/google/refine/model/recon/ReconConfigResolver.java create mode 100644 OpenRefine/main/src/com/google/refine/model/recon/ReconJob.java create mode 100644 OpenRefine/main/src/com/google/refine/model/recon/ReconciledDataExtensionJob.java create mode 100644 OpenRefine/main/src/com/google/refine/model/recon/StandardReconConfig.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/EngineDependentMassCellOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/EngineDependentOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/OnError.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/OperationRegistry.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/OperationResolver.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/UnknownOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/cell/BlankDownOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/cell/FillDownOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/cell/KeyValueColumnizeOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/cell/MassEditOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/cell/MultiValuedCellJoinOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/cell/MultiValuedCellSplitOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/cell/TextTransformOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/cell/TransposeColumnsIntoRowsOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/cell/TransposeRowsIntoColumnsOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/column/ColumnAdditionByFetchingURLsOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/column/ColumnAdditionOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/column/ColumnMoveOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/column/ColumnRemovalOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/column/ColumnRenameOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/column/ColumnReorderOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/column/ColumnSplitOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/recon/ExtendDataOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/recon/ReconClearSimilarCellsOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/recon/ReconCopyAcrossColumnsOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/recon/ReconDiscardJudgmentsOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/recon/ReconJudgeSimilarCellsOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/recon/ReconMarkNewTopicsOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/recon/ReconMatchBestCandidatesOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/recon/ReconMatchSpecificTopicOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/recon/ReconOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/recon/ReconUseValuesAsIdentifiersOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/row/DenormalizeOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/row/RowFlagOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/row/RowRemovalOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/row/RowReorderOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/operations/row/RowStarOperation.java create mode 100644 OpenRefine/main/src/com/google/refine/preference/PreferenceStore.java create mode 100644 OpenRefine/main/src/com/google/refine/preference/PreferenceValue.java create mode 100644 OpenRefine/main/src/com/google/refine/preference/TopList.java create mode 100644 OpenRefine/main/src/com/google/refine/process/LongRunningProcess.java create mode 100644 OpenRefine/main/src/com/google/refine/process/Process.java create mode 100644 OpenRefine/main/src/com/google/refine/process/ProcessManager.java create mode 100644 OpenRefine/main/src/com/google/refine/process/QuickHistoryEntryProcess.java create mode 100644 OpenRefine/main/src/com/google/refine/sorting/BaseSorter.java create mode 100644 OpenRefine/main/src/com/google/refine/sorting/BooleanCriterion.java create mode 100644 OpenRefine/main/src/com/google/refine/sorting/Criterion.java create mode 100644 OpenRefine/main/src/com/google/refine/sorting/DateCriterion.java create mode 100644 OpenRefine/main/src/com/google/refine/sorting/NumberCriterion.java create mode 100644 OpenRefine/main/src/com/google/refine/sorting/SortingConfig.java create mode 100644 OpenRefine/main/src/com/google/refine/sorting/SortingRecordVisitor.java create mode 100644 OpenRefine/main/src/com/google/refine/sorting/SortingRowVisitor.java create mode 100644 OpenRefine/main/src/com/google/refine/sorting/StringCriterion.java create mode 100644 OpenRefine/main/src/com/google/refine/templating/DynamicFragment.java create mode 100644 OpenRefine/main/src/com/google/refine/templating/Fragment.java create mode 100644 OpenRefine/main/src/com/google/refine/templating/Parser.java create mode 100644 OpenRefine/main/src/com/google/refine/templating/StaticFragment.java create mode 100644 OpenRefine/main/src/com/google/refine/templating/Template.java create mode 100644 OpenRefine/main/src/com/google/refine/util/CookiesUtilities.java create mode 100644 OpenRefine/main/src/com/google/refine/util/GetProjectIDException.java create mode 100644 OpenRefine/main/src/com/google/refine/util/HttpClient.java create mode 100644 OpenRefine/main/src/com/google/refine/util/IOUtils.java create mode 100644 OpenRefine/main/src/com/google/refine/util/IndentWriter.java create mode 100644 OpenRefine/main/src/com/google/refine/util/JSONUtilities.java create mode 100644 OpenRefine/main/src/com/google/refine/util/JsonViews.java create mode 100644 OpenRefine/main/src/com/google/refine/util/LookupException.java create mode 100644 OpenRefine/main/src/com/google/refine/util/ParsingUtilities.java create mode 100644 OpenRefine/main/src/com/google/refine/util/PatternSyntaxExceptionParser.java create mode 100644 OpenRefine/main/src/com/google/refine/util/Pool.java create mode 100644 OpenRefine/main/src/com/google/refine/util/SerializationFilters.java create mode 100644 OpenRefine/main/src/com/google/refine/util/StringUtils.java create mode 100644 OpenRefine/main/src/com/google/refine/util/TrackingInputStream.java create mode 100644 OpenRefine/main/tests/cypress/.eslintignore create mode 100644 OpenRefine/main/tests/cypress/.eslintrc.json create mode 100644 OpenRefine/main/tests/cypress/.gitignore create mode 100644 OpenRefine/main/tests/cypress/.prettierignore create mode 100644 OpenRefine/main/tests/cypress/.prettierrc.json create mode 100644 OpenRefine/main/tests/cypress/Readme.md create mode 100644 OpenRefine/main/tests/cypress/build-test-matrix.js create mode 100644 OpenRefine/main/tests/cypress/cypress.json create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/csv-reconcile-species.csv create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/doaj-article-sample.csv create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/fixtures.js create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/food-small-csv.openrefine.tar.zip create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/food.mini.csv create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/food.mini.js create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/food.small.csv create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/food.small.js create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/food.sort.csv create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/food.sort.js create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/reconciled-project-automatch.zip create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/reconciled-project-no-automatch.zip create mode 100644 OpenRefine/main/tests/cypress/cypress/fixtures/shop.mini.tsv create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/create-project/create_project.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/create-project/preview_project.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/extensions/wikidata/.gitkeep create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/import-project/import_project.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/language/change_language.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/open-project/filter_projects.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/open-project/list_projects.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/open-project/open_project.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/preferences/change_preference.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/all-column/collapse_all.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/all-column/edit-columns.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/all-column/edit-rows.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/all-column/flag.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/all-column/star.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/all-column/view.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/blank-down.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/common-transforms/Replace-Smart-quotes-with-ascii.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/common-transforms/collapse-consecutive-whitespace.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/common-transforms/to-date.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/common-transforms/to-empty-string.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/common-transforms/to-lowercase.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/common-transforms/to-null.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/common-transforms/to-number.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/common-transforms/to-text.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/common-transforms/to-titlecase.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/common-transforms/to-uppercase.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/common-transforms/trim-leading-whitespace.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/common-transforms/unescape-html-entities.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/fill-down.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/join-multi-valued-cells.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/replace.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/split-multi-valued-cells.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/transform.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/warning-on-blank-down.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-cells/warning-on-fill-down.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-column/add_columns_based_on_this_column.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-column/join_columns.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-column/rename_remove_column.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-column/reposition_column.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/edit-column/split_into_several_columns.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/facet/.gitkeep create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/facet/customized-facets/.gitkeep create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/facet/facets.numeric.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/facet/facets.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/facet/scatterplot-facet.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/reconcile/actions/clear_reconciliation_data.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/reconcile/actions/create_new_item_for_each.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/reconcile/actions/discard_reconciliation_judgments.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/reconcile/actions/match_to_best_candidate.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/reconcile/add_entity_identifiers.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/reconcile/copy_reconciliation_data.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/reconcile/facets/by_judgment.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/reconcile/use_values_as_identifiers.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/sort.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/text_filter.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/transpose/.gitkeep create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/transpose/cell_accross_columns.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/transpose/cells_in_rows.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/transpose/columnize.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/view/.gitkeep create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/view/collapse.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/view/collapse_left.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/view/collapse_right.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/view/expand-left.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/column/view/expand-right.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/misc/expressions.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/misc/proper-display.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/row/edit_cells.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/viewpanel-header/pagination.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/viewpanel-header/rows_records.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/grid/viewpanel-header/sort.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/project-header/export_project.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/project-header/help.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/project-header/permalink.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/project-header/project_rename.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/undo_redo/apply.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/undo_redo/extract.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project/undo_redo/undo_redo.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/project_management/project_metadata.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/tutorial/importing-data-into-openrefine.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/integration/tutorial/layout-of-openrefine.spec.js create mode 100644 OpenRefine/main/tests/cypress/cypress/plugins/index.js create mode 100644 OpenRefine/main/tests/cypress/cypress/snapshots/project/grid/column/facet/scatterplot-facet.spec.js/scatterplot-default.snap.png create mode 100644 OpenRefine/main/tests/cypress/cypress/snapshots/project/grid/column/facet/scatterplot-facet.spec.js/scatterplot-facet-big-dot.snap.png create mode 100644 OpenRefine/main/tests/cypress/cypress/snapshots/project/grid/column/facet/scatterplot-facet.spec.js/scatterplot-facet-lin.snap.png create mode 100644 OpenRefine/main/tests/cypress/cypress/snapshots/project/grid/column/facet/scatterplot-facet.spec.js/scatterplot-facet-log.snap.png create mode 100644 OpenRefine/main/tests/cypress/cypress/snapshots/project/grid/column/facet/scatterplot-facet.spec.js/scatterplot-facet-regulat-dot.snap.png create mode 100644 OpenRefine/main/tests/cypress/cypress/snapshots/project/grid/column/facet/scatterplot-facet.spec.js/scatterplot-facet-small-dot.snap.png create mode 100644 OpenRefine/main/tests/cypress/cypress/snapshots/project/grid/column/facet/scatterplot-facet.spec.js/scatterplot-matrix-big-dot.snap.png create mode 100644 OpenRefine/main/tests/cypress/cypress/snapshots/project/grid/column/facet/scatterplot-facet.spec.js/scatterplot-matrix-lin.snap.png create mode 100644 OpenRefine/main/tests/cypress/cypress/snapshots/project/grid/column/facet/scatterplot-facet.spec.js/scatterplot-matrix-log.snap.png create mode 100644 OpenRefine/main/tests/cypress/cypress/snapshots/project/grid/column/facet/scatterplot-facet.spec.js/scatterplot-matrix-regulat-dot.snap.png create mode 100644 OpenRefine/main/tests/cypress/cypress/snapshots/project/grid/column/facet/scatterplot-facet.spec.js/scatterplot-matrix-small-dot.snap.png create mode 100644 OpenRefine/main/tests/cypress/cypress/support/commands.js create mode 100644 OpenRefine/main/tests/cypress/cypress/support/index.js create mode 100644 OpenRefine/main/tests/cypress/cypress/support/openrefine_api.js create mode 100644 OpenRefine/main/tests/cypress/package.json create mode 100644 OpenRefine/main/tests/cypress/yarn.lock create mode 100644 OpenRefine/main/tests/data/Colorado-Municipalities-small-xlsx.gz create mode 100644 OpenRefine/main/tests/data/Wpi Data.tsv create mode 100644 OpenRefine/main/tests/data/big5.html create mode 100644 OpenRefine/main/tests/data/big5.txt create mode 100644 OpenRefine/main/tests/data/birds.csv create mode 100644 OpenRefine/main/tests/data/changes/data_extension_2.8.txt create mode 100644 OpenRefine/main/tests/data/changes/data_extension_3.0.txt create mode 100644 OpenRefine/main/tests/data/dates.xls create mode 100644 OpenRefine/main/tests/data/euc-jp.html create mode 100644 OpenRefine/main/tests/data/euc-jp.txt create mode 100644 OpenRefine/main/tests/data/euc-kr.html create mode 100644 OpenRefine/main/tests/data/euc-kr.txt create mode 100644 OpenRefine/main/tests/data/example-latin1.tsv create mode 100644 OpenRefine/main/tests/data/example-linebreaks-in-cells.csv create mode 100644 OpenRefine/main/tests/data/example-linebreaks-in-cells.tsv create mode 100644 OpenRefine/main/tests/data/example-utf8.tsv create mode 100644 OpenRefine/main/tests/data/example_project_metadata.json create mode 100644 OpenRefine/main/tests/data/example_project_metadata_save_mode.json create mode 100644 OpenRefine/main/tests/data/excel95.xls create mode 100644 OpenRefine/main/tests/data/films.ods create mode 100644 OpenRefine/main/tests/data/food.csv create mode 100644 OpenRefine/main/tests/data/food.small.csv create mode 100644 OpenRefine/main/tests/data/government_contracts.csv create mode 100644 OpenRefine/main/tests/data/grid_small.json create mode 100644 OpenRefine/main/tests/data/jorf.xml create mode 100644 OpenRefine/main/tests/data/json-sample-format-1.json create mode 100644 OpenRefine/main/tests/data/movies-condensed.tsv create mode 100644 OpenRefine/main/tests/data/movies.tsv create mode 100644 OpenRefine/main/tests/data/movies.zip create mode 100644 OpenRefine/main/tests/data/nobel-prize-winners.csv create mode 100644 OpenRefine/main/tests/data/ozone_8hr_dmax.csv create mode 100644 OpenRefine/main/tests/data/ozone_sites.csv create mode 100644 OpenRefine/main/tests/data/presidents.tsv create mode 100644 OpenRefine/main/tests/data/scriblio.mrc create mode 100644 OpenRefine/main/tests/data/shift_jis.html create mode 100644 OpenRefine/main/tests/data/shift_jis.txt create mode 100644 OpenRefine/main/tests/data/unsupportedPPMD.zip create mode 100644 OpenRefine/main/tests/data/xml-sample-format-1.xml create mode 100644 OpenRefine/main/tests/data/xml-sample-format-2.xml create mode 100644 OpenRefine/main/tests/data/xml-sample-format-3.xml create mode 100644 OpenRefine/main/tests/data/xml-sample-format-4.xml create mode 100644 OpenRefine/main/tests/server/conf/tests.xml create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/HistoryEntryManagerStub.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/ProjectManagerStub.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/ProjectManagerTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/RefineServletStub.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/RefineServletTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/RefineTest.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/browsing/DecoratedValueTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/browsing/EngineConfigTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/browsing/EngineTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/browsing/facets/ListFacetTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/browsing/facets/NominalFacetChoiceTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/browsing/facets/RangeFacetTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/browsing/facets/ScatterplotFacetTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/browsing/facets/TextSearchFacetTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/browsing/facets/TimeRangeFacetTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/browsing/util/ExpressionNominalValueGrouperTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/clustering/binning/BinningClustererTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/clustering/binning/KeyerTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/clustering/knn/kNNClustererTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/CSRFTokenFactoryTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/CommandStub.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/CommandTestBase.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/CommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/EngineDependentCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/GetCSRFTokenCommandTest.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/OpenWorkspaceDirCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/SetPreferenceCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/browsing/GetClusteringFunctionsAndDistancesCommandTest.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/browsing/ScatterplotDrawCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/cell/EditOneCellCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/cell/JoinMultiValueCellsCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/cell/KeyValueColumnizeCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/cell/SplitMultiValueCellsCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/cell/TransposeColumnsIntoRowsCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/cell/TransposeRowsIntoColumnsCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/column/MoveColumnCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/column/RemoveColumnCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/column/RenameColumnCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/expr/ExpressionCommandTestBase.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/expr/GetExpressionHistoryCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/expr/GetExpressionLanguageInfoCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/expr/GetStarredExpressionsCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/expr/LogExpressionCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/expr/PreviewExpressionCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/expr/ToggleStarredExpressionCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/history/ApplyOperationsCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/history/CancelProcessesCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/history/UndoRedoCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/importing/CancelImportingJobCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/importing/CreateImportingJobCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/importing/ImportingControllerCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/lang/LoadLanguageCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/project/ImportProjectCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/project/RenameProjectCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/project/SetProjectMetadataCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/project/SetProjectTagsCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/recon/GuessTypesOfColumnCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/recon/PreviewExtendDataCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/recon/ReconClearOneCellCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/recon/ReconJudgeOneCellCommandTest.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/row/AnnotateOneRowCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/row/DenormalizeCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/row/GetRowsCommandTest.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/commands/util/CancelProcessesCommandTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/exporters/CsvExporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/exporters/HtmlExporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/exporters/TemplatingExporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/exporters/TsvExporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/exporters/XlsExporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/exporters/XlsxExporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/exporters/sql/SqlExporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/EvalErrorTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/ExpressionUtilsTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/CoalesceTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/CrossTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/FacetCountTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/GetTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/HasFieldTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/JsonizeTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/LengthTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/SliceTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/ToDateTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/ToNumberTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/ToStringTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/TypeTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/arrays/InArrayTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/arrays/JoinTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/arrays/ReverseTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/arrays/SortTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/arrays/UniquesTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/booleans/AndTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/booleans/BooleanTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/booleans/NotTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/booleans/OrTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/booleans/XorTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/date/DatePartTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/date/IncTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/date/NowTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/html/InnerHtmlTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/html/ParseHtmlTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/ChompTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/ContainsTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/DiffTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/EndsWithTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/EscapeTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/FindTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/FingerprintTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/IndexOfTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/LastIndexOfTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/MD5Tests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/MatchTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/NGramFingerprintTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/NGramTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/ParseJsonTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/PartitionTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/PhoneticTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/RPartitionTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/RangeTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/ReinterpretTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/ReplaceCharsTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/ReplaceTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/SHA1Tests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/SmartSplitTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/SplitByCharTypeTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/SplitByLengthsTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/SplitTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/StartsWithTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/ToLowercaseTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/ToTitlecaseTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/ToUppercaseTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/TrimTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/UnescapeTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/UnicodeTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/strings/UnicodeTypeTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/xml/InnerXmlTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/xml/OwnTextTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/xml/ParseXmlTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/functions/xml/SelectXmlTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/expr/util/JsonValueConverterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/FunctionTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/GrelTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/ast/LiteralExprTest.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/FilterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/ForEachIndexTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/ForEachTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/ForNonBlankTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/ForRangeTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/IfTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/IsBlankTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/IsEmptyStringTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/IsErrorTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/IsNonBlankTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/IsNotNullTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/IsNullTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/IsNumericTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/grel/controls/WithTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/history/FileHistoryEntryManagerTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/history/HistoryEntryTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/history/HistoryTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/ExcelImporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/FixedWidthImporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/ImporterTest.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/ImporterUtilitiesTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/JsonImporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/MarcImporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/OdsImporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/RdfTripleImporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/TextFormatGuesserTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/TsvCsvImporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/WikitextImporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/XmlImportUtilitiesStub.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/XmlImportUtilitiesTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importers/XmlImporterTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importing/EncodingGuesserTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importing/ImportingManagerTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/importing/ImportingUtilitiesTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/io/FileProjectManagerTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/io/ProjectMetadataTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/CacheTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/CellTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/ColumnGroupTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/ColumnModelTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/ColumnTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/ProjectStub.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/ReconCandidateTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/ReconStatsTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/ReconTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/ReconTypeTest.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/RecordModelTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/RowTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/changes/DataExtensionChangeTest.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/changes/MassChangeTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/model/recon/StandardReconConfigTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/cell/BlankDownTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/cell/FillDownTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/cell/JoinMultiValuedCellsTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/cell/KeyValueColumnizeTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/cell/MassOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/cell/SplitMultiValuedCellsTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/cell/TransposeTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/column/ColumnAdditionByFetchingURLsOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/column/ColumnAdditionOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/column/ColumnMoveOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/column/ColumnRemovalOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/column/ColumnRenameOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/column/ColumnReorderOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/column/ColumnSplitOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/recon/ExtendDataOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/recon/ReconClearSimilarCellsOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/recon/ReconCopyAcrossColumnsOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/recon/ReconDiscardJudgmentsOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/recon/ReconJudgeSimilarCellsOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/recon/ReconJudgeSimilarCellsTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/recon/ReconMarkNewTopicsOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/recon/ReconMatchBestCandidatesOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/recon/ReconMatchSpecificTopicOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/recon/ReconOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/recon/ReconUseValuesAsIdsOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/row/DenormalizeOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/row/RowFlagOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/row/RowRemovalOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/row/RowReorderOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/operations/row/RowStarOperationTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/preference/PreferenceStoreTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/preference/TopListTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/process/HistoryProcessTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/process/LongRunningProcessStub.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/process/LongRunningProcessTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/process/ProcessManagerTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/process/QuickHistoryEntryProcessTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/sorting/BooleanCriterionTest.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/sorting/DateCriterionTest.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/sorting/NumberCriterionTest.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/sorting/SortingConfigTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/util/ParsingUtilitiesTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/util/PatternSyntaxExceptionParserTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/util/StringUtilsTests.java create mode 100644 OpenRefine/main/tests/server/src/com/google/refine/util/TestUtils.java create mode 100644 OpenRefine/main/tests/server/src/tests.log4j.properties create mode 100644 OpenRefine/main/webapp/WEB-INF/butterfly.properties create mode 100644 OpenRefine/main/webapp/WEB-INF/modules.properties create mode 100644 OpenRefine/main/webapp/WEB-INF/velocity.properties create mode 100644 OpenRefine/main/webapp/WEB-INF/web.xml create mode 100644 OpenRefine/main/webapp/licenses/chrome_frame.LICENSE.txt create mode 100644 OpenRefine/main/webapp/licenses/datejs.LICENSE.txt create mode 100644 OpenRefine/main/webapp/licenses/freebase_suggest.LICENSE.txt create mode 100644 OpenRefine/main/webapp/licenses/imgareaselect.LICENSE.txt create mode 100644 OpenRefine/main/webapp/licenses/jquery.LICENSE.txt create mode 100644 OpenRefine/main/webapp/licenses/jquery.eventstack.LICENSE.txt create mode 100644 OpenRefine/main/webapp/licenses/jquery.i18n.LICENSE.txt create mode 100644 OpenRefine/main/webapp/licenses/jquery_ui.LICENSE.txt create mode 100644 OpenRefine/main/webapp/licenses/simile-ajax.2.3.0.LICENSE.txt create mode 100644 OpenRefine/main/webapp/modules/core/MOD-INF/controller.js create mode 100644 OpenRefine/main/webapp/modules/core/MOD-INF/module.properties create mode 100644 OpenRefine/main/webapp/modules/core/about.html create mode 100644 OpenRefine/main/webapp/modules/core/about.js create mode 100644 OpenRefine/main/webapp/modules/core/error.vt create mode 100644 OpenRefine/main/webapp/modules/core/externals/CLDRPluralRuleParser.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/date.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/imgareaselect/css/imgareaselect-default.css create mode 100644 OpenRefine/main/webapp/modules/core/externals/imgareaselect/jquery.imgareaselect.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-1.12.4.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-1.12.4.min.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-migrate-1.4.1.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-migrate-1.4.1.min.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/animated-overlay.gif create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-icons_222222_256x240.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-icons_228ef1_256x240.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-icons_ef8c08_256x240.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-icons_ffd27a_256x240.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/images/ui-icons_ffffff_256x240.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/jquery-ui.css create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/jquery-ui.min.css create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/css/ui-lightness/theme.css create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/jquery-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery-ui/jquery-ui.min.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery.i18n.emitter.bidi.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery.i18n.emitter.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery.i18n.fallbacks.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery.i18n.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery.i18n.language.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery.i18n.messagestore.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/jquery.i18n.parser.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/js.cookie.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/bs.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/dsb.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/fi.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/ga.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/he.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/hsb.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/hu.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/hy.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/la.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/ml.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/os.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/ru.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/sl.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/languages/uk.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/moment-with-locales.min.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/select2/select2-spinner.gif create mode 100644 OpenRefine/main/webapp/modules/core/externals/select2/select2.css create mode 100644 OpenRefine/main/webapp/modules/core/externals/select2/select2.min.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/select2/select2.png create mode 100644 OpenRefine/main/webapp/modules/core/externals/suggest/css/suggest-4_3.css create mode 100644 OpenRefine/main/webapp/modules/core/externals/suggest/css/suggest-4_3.min.css create mode 100644 OpenRefine/main/webapp/modules/core/externals/suggest/suggest-4_3a.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/tablesorter/jquery.tablesorter.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/tablesorter/jquery.tablesorter.min.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/tablesorter/theme.blue.css create mode 100644 OpenRefine/main/webapp/modules/core/externals/underscore-min.js create mode 100644 OpenRefine/main/webapp/modules/core/externals/underscore-min.map create mode 100644 OpenRefine/main/webapp/modules/core/images/arrow-end.png create mode 100644 OpenRefine/main/webapp/modules/core/images/arrow-start.png create mode 100644 OpenRefine/main/webapp/modules/core/images/checks-map.png create mode 100644 OpenRefine/main/webapp/modules/core/images/close-map.png create mode 100644 OpenRefine/main/webapp/modules/core/images/close.png create mode 100644 OpenRefine/main/webapp/modules/core/images/collapsed.png create mode 100644 OpenRefine/main/webapp/modules/core/images/cop.png create mode 100644 OpenRefine/main/webapp/modules/core/images/down-arrow.png create mode 100644 OpenRefine/main/webapp/modules/core/images/edit-map.png create mode 100644 OpenRefine/main/webapp/modules/core/images/edit.png create mode 100644 OpenRefine/main/webapp/modules/core/images/expanded.png create mode 100644 OpenRefine/main/webapp/modules/core/images/facet-resize-handle.png create mode 100644 OpenRefine/main/webapp/modules/core/images/favicon.png create mode 100644 OpenRefine/main/webapp/modules/core/images/large-spinner.gif create mode 100644 OpenRefine/main/webapp/modules/core/images/leftpanel-showhide.png create mode 100644 OpenRefine/main/webapp/modules/core/images/logo-gem-126.png create mode 100644 OpenRefine/main/webapp/modules/core/images/logo-openrefine-550.png create mode 100644 OpenRefine/main/webapp/modules/core/images/menu-dropdown.png create mode 100644 OpenRefine/main/webapp/modules/core/images/menu-opener.png create mode 100644 OpenRefine/main/webapp/modules/core/images/minimize-map.png create mode 100644 OpenRefine/main/webapp/modules/core/images/right-arrow.png create mode 100644 OpenRefine/main/webapp/modules/core/images/scatterplot-icons.png create mode 100644 OpenRefine/main/webapp/modules/core/images/slider-handle.png create mode 100644 OpenRefine/main/webapp/modules/core/images/small-spinner.gif create mode 100644 OpenRefine/main/webapp/modules/core/images/star-flag-map.png create mode 100644 OpenRefine/main/webapp/modules/core/images/star.png create mode 100644 OpenRefine/main/webapp/modules/core/images/up-arrow.png create mode 100644 OpenRefine/main/webapp/modules/core/index.vt create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-ar.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-bn.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-ceb.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-cs.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-de.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-el.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-en.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-en_GB.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-es.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-fil.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-fr.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-he.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-hi.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-hu.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-id.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-it.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-iu.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-jp.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-ko.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-ml.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-mr.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-nb_NO.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-nl.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-pa.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-pl.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-pt.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-pt_BR.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-ro.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-ru.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-sv.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-tl.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-uk.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-zh.json create mode 100644 OpenRefine/main/webapp/modules/core/langs/translation-zh_Hant.json create mode 100644 OpenRefine/main/webapp/modules/core/macros.vm create mode 100644 OpenRefine/main/webapp/modules/core/preferences.vt create mode 100644 OpenRefine/main/webapp/modules/core/project.vt create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/clustering-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/clustering-dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/column-reordering-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/column-reordering-dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/common-transform-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/common-transform-dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/custom-tabular-exporter-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/custom-tabular-exporter-dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/export-project-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/expression-column-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/expression-column-dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/expression-preview-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/expression-preview-dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/extend-data-preview-dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/http-headers-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/http-headers-dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/scatterplot-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/scatterplot-dialog.js create mode 100755 OpenRefine/main/webapp/modules/core/scripts/dialogs/sql-exporter-dialog.html create mode 100755 OpenRefine/main/webapp/modules/core/scripts/dialogs/sql-exporter-dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/templating-exporter-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/dialogs/templating-exporter-dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/facets/facet.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/facets/list-facet.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/facets/range-facet.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/facets/scatterplot-facet.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/facets/text-search-facet.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/facets/timerange-facet.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/create-project-error-panel.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/create-project-progress-panel.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/create-project-ui-source-selection.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/create-project-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/default-importing-controller/controller.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/default-importing-controller/file-selection-panel.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/default-importing-controller/file-selection-panel.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/default-importing-controller/parsing-panel.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/default-importing-controller/parsing-panel.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/default-importing-sources/import-from-clipboard-form.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/default-importing-sources/import-from-computer-form.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/default-importing-sources/import-from-web-form.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/default-importing-sources/sources.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/edit-metadata-dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/import-project-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/import-project-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/lang-settings-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/lang-settings-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/open-project-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/open-project-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/excel-parser-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/excel-parser-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/fixed-width-parser-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/fixed-width-parser-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/json-parser-select-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/json-parser-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/json-parser-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/line-based-parser-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/line-based-parser-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/preview-table.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/rdf-triples-parser-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/rdf-triples-parser-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/separator-based-parser-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/separator-based-parser-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/wikitext-parser-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/wikitext-parser-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/xml-parser-select-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/xml-parser-ui.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/parser-interfaces/xml-parser-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/index/select-encoding-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/preferences.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/browsing-engine.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/edit-metadata-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/exporters.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/extension-bar.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/history-apply-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/history-entry.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/history-extract-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/history-panel.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/history-panel.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/process-panel.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/progress-panel.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/scripting.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/project/summary-bar.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/reconciliation/add-namespaced-service-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/reconciliation/add-standard-service-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/reconciliation/recon-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/reconciliation/recon-dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/reconciliation/recon-manager.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/reconciliation/standard-service-panel.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/reconciliation/standard-service-panel.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/ajax.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/custom-suggest.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/date-time.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/dialog.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/dom.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/encoding.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/filter-lists.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/menu.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/misc.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/select-encoding-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/sign.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/string.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/util/url.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/add-column-by-fetching-urls-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/add-column-by-reconciliation.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/add-column-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/add-q-column-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/cell-editor.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/cell-recon-preview-popup-header.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/cell-recon-search-for-match.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/cell-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/column-header-ui.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/column-header.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/column-join.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/copy-recon-across-columns-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/data-table-view.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/extend-data-preview-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/key-value-columnize.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/menu-edit-cells.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/menu-edit-column.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/menu-facets.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/menu-reconcile.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/replace-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/sorting-criterion-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/split-column-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/split-multi-valued-cells-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/text-transform-dialog.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/transpose-columns-into-rows.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/views/data-table/warn-of-pending-sort.html create mode 100644 OpenRefine/main/webapp/modules/core/scripts/widgets/histogram-widget.js create mode 100644 OpenRefine/main/webapp/modules/core/scripts/widgets/slider-widget.js create mode 100644 OpenRefine/main/webapp/modules/core/styles/common.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/dialogs/clustering-dialog.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/dialogs/column-reordering-dialog.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/dialogs/custom-tabular-exporter-dialog.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/dialogs/expression-preview-dialog.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/dialogs/scatterplot-dialog.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/dialogs/sql-exporter-dialog.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/index.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/index/create-project-ui.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/index/default-importing-controller.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/index/default-importing-file-selection-panel.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/index/default-importing-parsing-panel.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/index/default-importing-sources.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/index/fixed-width-parser-ui.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/index/import-project-ui.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/index/json-parser-ui.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/index/open-project-ui.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/index/wikitext-parser-ui.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/index/xml-parser-ui.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/jquery-ui-overrides.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/project.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/project/facets.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/project/process.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/project/sidebar.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/pure.css create mode 100644 OpenRefine/main/webapp/modules/core/styles/reconciliation/extend-data-preview-dialog.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/reconciliation/recon-dialog.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/reconciliation/standard-service-panel.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/theme.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/util/custom-suggest.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/util/dialog.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/util/encoding.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/util/menu.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/views/column-join.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/views/data-table-view.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/widgets/histogram-widget.less create mode 100644 OpenRefine/main/webapp/modules/core/styles/widgets/slider-widget.less create mode 100644 OpenRefine/packaging/butterfly.properties create mode 100644 OpenRefine/packaging/linux.xml create mode 100644 OpenRefine/packaging/openrefine.ico create mode 100644 OpenRefine/packaging/pom.xml create mode 100644 OpenRefine/packaging/test_pom.xml create mode 100644 OpenRefine/packaging/windows.xml create mode 100644 OpenRefine/pom.xml create mode 100755 OpenRefine/refine create mode 100644 OpenRefine/refine.bat create mode 100644 OpenRefine/refine.ini create mode 100644 OpenRefine/server/IDEs/eclipse/README.txt create mode 100644 OpenRefine/server/IDEs/netbeans/manifest.mf create mode 100644 OpenRefine/server/IDEs/netbeans/nbbuild.xml create mode 100644 OpenRefine/server/IDEs/netbeans/nbproject/build-impl.xml create mode 100644 OpenRefine/server/IDEs/netbeans/nbproject/genfiles.properties create mode 100644 OpenRefine/server/IDEs/netbeans/nbproject/project.properties create mode 100644 OpenRefine/server/IDEs/netbeans/nbproject/project.xml create mode 100755 OpenRefine/server/lib-local/native/windows/jdatapath.dll create mode 100644 OpenRefine/server/pom.xml create mode 100644 OpenRefine/server/src/com/google/refine/Configurations.java create mode 100644 OpenRefine/server/src/com/google/refine/Refine.java create mode 100644 OpenRefine/server/src/com/google/refine/ValidateHostHandler.java create mode 100644 OpenRefine/server/src/com/google/util/logging/IndentingLayout.java create mode 100644 OpenRefine/server/src/com/google/util/threads/ThreadPoolExecutorAdapter.java create mode 100644 OpenRefine/server/src/log4j2.properties create mode 100644 OpenRefine/settings.xml diff --git a/OpenRefine/.gitattributes b/OpenRefine/.gitattributes new file mode 100644 index 000000000..7057ad030 --- /dev/null +++ b/OpenRefine/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=off + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/OpenRefine/.gitignore b/OpenRefine/.gitignore new file mode 100644 index 000000000..3cf04d797 --- /dev/null +++ b/OpenRefine/.gitignore @@ -0,0 +1,72 @@ +.idea/ +*.log +logs +*~ +\#*# +.*.swp +*.DS_Store +*.class +*.patch +.com.apple.timemachine.supported +.import-temp/ +build/ +dist/ +server/classes/ +main/webapp/WEB-INF/classes/ +main/tests/server/classes/ +main/test-output/ +appengine/classes/ +tools/ +broker/appengine/module/MOD-INF/classes/ +broker/core/module/MOD-INF/classes/ +broker/core/WEB-INF/lib/ +broker/core/data/ +broker/core/test-output/ +tmp/ +/test-output +test-out/ +/bin +open-refine.log +.vscode +.metadata # Eclipse plugins specific + +# Locally stored "Eclipse launch configurations" +*.launch + +.idea +*.iml + +main/target/ +main/webapp/WEB-INF/lib/ +server/target/ +extensions/*/target/ +extensions/*/module/MOD-INF/classes/ +extensions/*/module/MOD-INF/lib/ +extensions/target +target/ +**/test-output/* +*.versionsBackup + +# Ignore classpath as it is automatically generated by Maven integrations in IDEs +*.classpath +*.project +*.settings + +# Ignore Apache Maven default download path +apache-maven-*/ +apache-maven-*-bin.tar.gz + +# Ignore refine-dev.ini +refine-dev.ini + +# Java annotation processor (APT) +.factorypath + +# Code Recommenders +.recommenders/ + +# STS (Spring Tool Suite) +.springBeans + +# Ignore Node modules that might inadvertently install at current path instead of user or configured env var NODE_PATH +node_modules/ diff --git a/OpenRefine/CODE_OF_CONDUCT.md b/OpenRefine/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..d7ffc7432 --- /dev/null +++ b/OpenRefine/CODE_OF_CONDUCT.md @@ -0,0 +1,82 @@ +# OpenRefine Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as OpenRefine +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all project spaces, and it also applies when +an individual is representing the project or its community in public spaces. +Examples of representing a project or community include using an official +project e-mail address, posting via an official social media account, or acting +as an appointed representative at an online or offline event. Representation of +a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the Code of Conduct Committee at code-of-conduct@openrefine.org. +The committee consists of: +* Lozanna Rossenova +* Chris Erdmann +* Jessica Hardwicke + +All complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The code of conduct is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq + diff --git a/OpenRefine/CONTRIBUTING.md b/OpenRefine/CONTRIBUTING.md new file mode 100644 index 000000000..f463341eb --- /dev/null +++ b/OpenRefine/CONTRIBUTING.md @@ -0,0 +1,62 @@ +This document presents how you can contribute to the OpenRefine project. Please also review our [Governance model](https://github.com/OpenRefine/OpenRefine/blob/master/GOVERNANCE.md) + +## Documentation, Questions or Problem + +Our issue list is only for reporting specific bugs and requesting specific features. If you just don't know how to do something using OpenRefine, or want to discuss some ideas, please +- try the [documentation wiki](https://github.com/OpenRefine/OpenRefine/wiki/Documentation-For-Users) +- ask on the [OpenRefine mailing list](https://groups.google.com/d/forum/openrefine). + +If you really want to file a bug or request a feature, go to this [issue list](https://github.com/OpenRefine/OpenRefine/issues). Please use the search function first to make sure a similar issue doesn't already exist. + +## Promote OpenRefine + +You don't need to be a coder to contribute to OpenRefine. Did you write a tutorial or article about OpenRefine on your blog or site? Are you organizing a workshop or presentation for OpenRefine in your city? Let us know via our [user discussion list](https://groups.google.com/d/forum/openrefine) or Twitter account ([@OpenRefine](http://twitter.com/OpenRefine)). We will share the news via our monthly update and via our Twitter handle. + +## Contributing translations + +You can help us [translate OpenRefine](https://github.com/OpenRefine/OpenRefine/wiki/Translate-OpenRefine) in as many languages as possible [via Weblate](https://hosted.weblate.org/engage/openrefine/?utm_source=widget). + +## Contributing code + +You can contribute code in three different ways: +- Fix minor bugs - you can check the issues flagged as [help wanted](https://github.com/OpenRefine/OpenRefine/labels/help%20wanted) or [good first issue](https://github.com/OpenRefine/OpenRefine/labels/good%20first%20issue) or [good second issue](https://github.com/OpenRefine/OpenRefine/labels/good%20second%20issue) +- Develop an OpenRefine extension +- Start your own distribution or fork + +All developers including new distributions and plugin developers are invited to leverage the following OpenRefine project management areas to avoid splitting the community in different communication channels. +- the [wiki](https://github.com/OpenRefine/OpenRefine/wiki) for shared documentation between both user docs and [documentation for developer](https://github.com/OpenRefine/OpenRefine/wiki/Documentation-For-Developers) +- the [developer mailing list](https://groups.google.com/forum/?fromgroups#!forum/openrefine-dev) for technical questions, new feature development and anything code related. We invite you to share you idea first via the developer mailing list. Someone may be able to point out to existing development saving you hours of research and development. +- [OpenRefine github issue tracker](https://github.com/OpenRefine/OpenRefine/issues) for requesting new features and bug reports. +- [Gitter Chat](https://gitter.im/OpenRefine/OpenRefine) + +### How to submit PR's (pull requests), patches, and bug fixes + +- Read [Your first pull request](https://github.com/OpenRefine/OpenRefine/wiki/Your-first-pull-request) +- Avoid merging master in your branch because it makes code review a lot harder. +- If you want to keep your branch up to date with our master, it would be nicer if you could just rebase your branch instead. That would keep the history a lot cleaner. +- Please avoid adding unrelated changes in the PR. Do a separate PR and rebase once they get merged can work really well. +- It is important that pull requests are used systematically, even by those who have the rights to merge them. + +If you make trivial changes, you can send them directly via a pull request. **Please make your changes in a new git branch and send your patch**, including appropriate test cases. + +We want to keep the quality of the trunk at a very high level, since this is ultimately where the Stable Releases are built from after bugs are fixed. Please take the time to test your changes (including travis-ci) before sending a pull request. + +OpenRefine is volunteer supported. Pull Requests are reviewed and merged by volunteers. All Pull Requests will be answered, however it may take some time to get back to you. Thank you in advance for your patience. + +If you don't know where to start and are looking for a bug to fix, please see our [issue list](https://github.com/OpenRefine/OpenRefine/issues). + +### New functionalities via extensions + +OpenRefine support a plugin architecture to extend its functionality. You can find more information on how to write extension on [our wiki](https://github.com/OpenRefine/OpenRefine/wiki/Write-An-Extension). Giuliano Tortoreto wrote a separate documentation detailing how to build an extension for OpenRefine. A [LaTeX](https://github.com/OpenRefine/OpenRefineExtensionDoc) and [PDF version](https://github.com/OpenRefine/OpenRefineExtensionDoc/blob/master/main.pdf) are available. + +If you want to list your extension on the download page, please edit [this file](https://github.com/OpenRefine/openrefine.github.com/blob/master/download.md). + +### New distributions + +OpenRefine is already available in many different distributions (see the [download page](http://openrefine.org/download.html)). New distributions often package OpenRefine for a specific usage or port it. We are fine with new forks ([see discussion](https://groups.google.com/forum/#!msg/openrefine/pasNnMDJ3p8/LrZz_GiFCwAJ)) but we invite you to engage with the community to share your roadmap and progress. + +Github offers a powerful system to work between different repositories and we encourage you to leverage it: +- You can cross reference issues and pull requests between Github repository using `user/repository#number` ([see more here](https://github.com/blog/967-github-secrets#cross-repository-issue-references)) +- If you want to merge a Pull Request that is pending for review to your own repository check the pull request locally ([see more here](https://help.github.com/articles/checking-out-pull-requests-locally/)). + +Don't forget to contribute to the upstream ([main OpenRefine repository](https://github.com/openrefine/openrefine.git)) so your changes from your distribution can be reviewed and merged and to keep other developers aware of your progress. If you want to list your distribution on the download page, please edit [this file](https://github.com/OpenRefine/openrefine.github.com/blob/master/download.md). diff --git a/OpenRefine/Dockerfile b/OpenRefine/Dockerfile new file mode 100644 index 000000000..d2d9c4b0a --- /dev/null +++ b/OpenRefine/Dockerfile @@ -0,0 +1,19 @@ +FROM maven:3-jdk-11 as build + +WORKDIR /usr/src/app +COPY OpenRefine . +WORKDIR /usr/src/app/OpenRefine + +RUN ./refine clean +RUN ./refine build + +FROM openjdk:11 + +WORKDIR /usr/app +COPY --from=build /usr/src/app/OpenRefine . + +VOLUME /data +EXPOSE 3333 + +ENTRYPOINT ["/usr/app/refine"] +CMD ["-i", "0.0.0.0", "-d", "/data", "-m", "3G"] diff --git a/OpenRefine/GOVERNANCE.md b/OpenRefine/GOVERNANCE.md new file mode 100644 index 000000000..d8d3a0b5f --- /dev/null +++ b/OpenRefine/GOVERNANCE.md @@ -0,0 +1,128 @@ +# OpenRefine Governance Model + +## Summary / Overview +OpenRefine is a free, open-source, powerful tool for working with messy data. OpenRefine has a plugin architecture and is distributed under the [new BSD license](http://opensource.org/licenses/BSD-3-Clause) allowing modification, distribution and name changes. + +## Roles and responsibilities +OpenRefine development is based on user consensus and open discussion between users. Decision making must be done in a transparent, open fashion (ie. using discussion list and issue list). No decisions about the project’s direction, bug fixes or features may be done in private without community involvement and participation. Discussions must begin at the earliest possible point on a topic; the community’s participation is vital during the entire decision-making process. + +All project participants abide by the [Code of Conduct](https://github.com/OpenRefine/OpenRefine/blob/master/CODE_OF_CONDUCT.md). + +Anyone with an interest in the project can join the community, contribute to the project design, and participate in the decision making process. This document describes how that participation takes place. + +### Users +Users are community members who have a need for the project. Through their usage, they give the project a purpose. Users are encouraged to participate in the project life by providing feedback on how their needs are satisfied. + +Users can help the project by: + +- Advertising and advocating for the project +- Informing developers of strengths and weaknesses of the tool through the [user discussion list](https://groups.google.com/forum/?fromgroups#!forum/openrefine) or the [issue list](https://github.com/OpenRefine/OpenRefine/issues?state=open) +- Providing moral support (a ‘thank you’ goes a long way) +- Writing tutorials + +How to become an OpenRefine user? [Download OpenRefine](http://openrefine.org/download.html) and start refining! + +### Contributors +Contributors are users getting involved in the project more closely. Contributions can take many forms: + +- Supporting new users via the [user discussion list](https://groups.google.com/forum/?fromgroups#!forum/openrefine) +- Submitting patches to fix bugs or add features via pull requests +- Maintaining and improving the [website](https://openrefine.org/) +- Writing and maintaining the [documentation](https://github.com/OpenRefine/OpenRefine/tree/master/docs) + +How to become an OpenRefine contributor? You will find more details in our [contributing guideline](https://github.com/OpenRefine/OpenRefine/blob/master/CONTRIBUTING.md) + +### Committers +If you make regular contribution to OpenRefine, you will most likely become a Committer. + +Committers have earned enough trust from the community to review and merge pull requests. + +Therefore Committers: +- Help contributors via the [developer discussion list](https://groups.google.com/forum/?fromgroups#!forum/openrefine-dev). +- Triage issues, pull requests and [projects](https://github.com/OpenRefine/OpenRefine/projects) +- Have direct access to the code base to create new branches +- Organize the wiki +- Review and merge pull requests submitted by contributors +- Are part of the OpenRefine organization and have the OpenRefine badge on their GitHub profile + +#### How to become a Committer? + +Be a contributor and be nominated as a Committer. Current Committer selects and elects new Committer. You may nominate yourself. Nomination should be sent to the [developer discussion list](https://groups.google.com/forum/?fromgroups#!forum/openrefine-dev) + +#### Current list of Committers +The list is available here: https://github.com/orgs/OpenRefine/people. + +### Release Manager +The Release Manager is responsible to +* Coordinate with the community to select which issue and pull request are part of the release +* Prepare and coordinate publishing the release + +The current Release Manager is Antonin Delpeuch + +### Steering Committee +The steering committee oversees the general direction of the project and initates links with other organizations and projects. + +* Advise the Project’s staff on processes, strategy, and operations; +* Participate in decision making and/or review of roadmaps, as time allows; +* Participate to some Steering Committee meetings, when time allows; +* Help the Project build connections and partnerships by helping project leadership to steward relationships with funders and partners, making strategic introductions for project leadership, reviewing documents when needed, as time allows; +* Act as an advocate for the Project in events and support the project’s communication online, as time allows. + +#### How to be part of the Steering Committee +Steering Committee are invited by the Advisory Committee + +#### Current list of Steering Committee members +* Chris Erdmann (University of North Carolina, RENCI) +* Alicia Fagerving (Wikimedia Sverige) +* Sandra Fauconnier (Wikimedia Foundation) +* Rufus Pollock (Datopian, Open Knowledge Foundation) +* Simon Rogers (Google News Initiative) +* Lozana Rossenova (Rhizome) +* Juliane Schneider (Harvard Catalyst, Clinical and Translational Science Center) +* Wesley Sherperd (Unifyd Insights) +* Fabio Tacchelli (Siren Solutions) + +### Advisory Committee +The Advisory Committee runs the adminstrative aspect of the project on a day to day basis with the support of Code for Science and Society (CS&S). Its member are bound by the fiscal sponsorship agreement with Code for Science and Society. They meet once per month with Code for Science and Society. + +It is composed of at least three members. No more than 49 percent of the members of the Advisory Committee may be paid by the project. + +Advisory Committee members: +* Represent OpenRefine with Code for Science and Society +* Provide guidance and oversight of the Project’s staff and operations; +* Approve budgets, and contracts +* Vote to terminate contracts when necessary. +* Participate in at least one call per quarter; +* Help advocate for the Project; +* Help the Project build connections and partnerships; +* Can be part of the Admin team for the project on GitHub + +#### Conflict of Interest +In the event of any conflict of interest (a Committee Member, their family member, or someone with whom the Committee Member has a close academic or employment relationship is involved in a decision), the Committee Member must immediately notify other Committee Members. The Committee Member will be asked to recuse themselves from ongoing conversations, and decision process regarding the Transaction. + +#### Current list of Advisory Committee members +* Martin Magdinier +* Antonin Delpeuch. + +## Code For Science and Society + +Since January 2020, OpenRefine is a member project of the Code For Science and Society (CS&S). + +CS&S provides administrative and fiscal infrastructure to receive and manage funds under CS&S Fiscal Sponsorship Agreement. CS&S is a USA based organization qualified as exempt from federal income tax under Section 501(c)(3) of the Internal Revenue Code (IRC) and classified as a public charity under IRC Sections 509(a)(1) and 170(b)(1)(A)(vi). + +### Manage funds + +While the vast majority of OpenRefine contributors are volunteers, we recognize the need to attract and retain contributors to help: +- perform time critical maintenance tasks for the project (for example release management, security update, pull request review and comments) +- address issues that will not be naturally done by the community (for example documentation or working on large or long term projects) + +CS&S currently manages the current funding sources: +- **Grants**: Funds are allocated based on the grants requirements. Grants help to secure resources to achieve long term goal or supports software maintenance, growth, development, and community engagement. +- **Google Summer of Code**: Google Summer of Code mentors are eligible for USD 500 compensation for their work. +- **Donations made through GitHub Sponsors or made directly to CS&S on behalf of OpenRefine**: Decisions on usage of funds is made by the Advisory committee with guidance from the community. + +Combined with CS&S, the Steering and Advisory committees have experience applying and managing grants. If you are interested in applying to a grant to improve OpenRefine, please share your idea early on the Developer mailing list. It will be a pleasure helping you through your grant application. New grants must be approved by the Advisory Committee. that CS&S retains a 15% handling fees on any donation to finance their operations (20% for government funding). + +### Other assets + +CS&S owns and manages the domain openrefine.org diff --git a/OpenRefine/IDEs/eclipse/README.txt b/OpenRefine/IDEs/eclipse/README.txt new file mode 100644 index 000000000..b92ff7e97 --- /dev/null +++ b/OpenRefine/IDEs/eclipse/README.txt @@ -0,0 +1,29 @@ + + OpenRefine for Eclipse + ------------------------- + + + This file contains Eclipse-specific help files that can get simplify your life + developing OpenRefine with Eclipse (http://www.eclipse.org/). + + + + Code Style Format Configurations (Refine.style.xml) + ------------------------------------------------------ + + This is the code formatting configurations that all OpenRefine developers should follow. + + To import, open the Eclipse preferences, then follow to "Java > Code Style > Formatter" + and click the "Import" button and load the file. + + + + - o - + + + Thank you for your interest. + + + The OpenRefine Development Team + http://github.com/OpenRefine/OpenRefine + \ No newline at end of file diff --git a/OpenRefine/IDEs/eclipse/Refine-codetemplates.xml b/OpenRefine/IDEs/eclipse/Refine-codetemplates.xml new file mode 100644 index 000000000..1c75c7acf --- /dev/null +++ b/OpenRefine/IDEs/eclipse/Refine-codetemplates.xml @@ -0,0 +1,62 @@ + \ No newline at end of file diff --git a/OpenRefine/IDEs/eclipse/Refine.style.xml b/OpenRefine/IDEs/eclipse/Refine.style.xml new file mode 100644 index 000000000..63c8a5f8e --- /dev/null +++ b/OpenRefine/IDEs/eclipse/Refine.style.xml @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenRefine/LICENSE.txt b/OpenRefine/LICENSE.txt new file mode 100644 index 000000000..58393644c --- /dev/null +++ b/OpenRefine/LICENSE.txt @@ -0,0 +1,11 @@ +Copyright 2010, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/OpenRefine/README.md b/OpenRefine/README.md new file mode 100644 index 000000000..228946dd9 --- /dev/null +++ b/OpenRefine/README.md @@ -0,0 +1,65 @@ +# OpenRefine + +[![DOI](https://zenodo.org/badge/6220644.svg)](https://zenodo.org/badge/latestdoi/6220644) +[![Join the chat at https://gitter.im/OpenRefine/OpenRefine](https://badges.gitter.im/OpenRefine/OpenRefine.svg)](https://gitter.im/OpenRefine/OpenRefine) ![Java CI](https://github.com/OpenRefine/OpenRefine/workflows/Java%20CI/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/OpenRefine/OpenRefine/badge.svg?branch=master)](https://coveralls.io/github/OpenRefine/OpenRefine?branch=master) [![Translation progress](https://hosted.weblate.org/widgets/openrefine/-/svg-badge.svg)](https://hosted.weblate.org/engage/openrefine/?utm_source=widget) [![Total alerts](https://img.shields.io/lgtm/alerts/g/OpenRefine/OpenRefine.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/OpenRefine/OpenRefine/alerts/) + +OpenRefine is a Java-based power tool that allows you to load data, understand it, +clean it up, reconcile it, and augment it with data coming from +the web. All from a web browser and the comfort and privacy of your own computer. + +[](http://openrefine.org) + +## Download + +* [OpenRefine Releases](https://github.com/OpenRefine/OpenRefine/releases) + +## Snapshot releases + +Latest development version, packaged for: +* [Linux](https://oss.sonatype.org/service/local/artifact/maven/content?r=snapshots&g=org.openrefine&a=openrefine&v=3.6-SNAPSHOT&c=linux&p=tar.gz) +* [MacOS](https://oss.sonatype.org/service/local/artifact/maven/content?r=snapshots&g=org.openrefine&a=openrefine&v=3.6-SNAPSHOT&c=mac&p=dmg) +* [Windows](https://oss.sonatype.org/service/local/artifact/maven/content?r=snapshots&g=org.openrefine&a=openrefine&v=3.6-SNAPSHOT&c=win&p=zip) + +## Run from source + +If you have cloned this repository to your computer, you can run OpenRefine with: + +* `./refine` on Mac OS and Linux +* `refine.bat` on Windows + +This requires [JDK 8](https://jdk.java.net) and [Apache Maven](https://maven.apache.org/). + +## Documentation and Videos + +* [User Manual](https://docs.openrefine.org) +* [FAQ](https://github.com/OpenRefine/OpenRefine/wiki/FAQ) +* [Official Website and tutorial videos](http://openrefine.org) + +## Contributing to the project + +* [Developers Guide & Architecture](https://github.com/OpenRefine/OpenRefine/wiki/Documentation-For-Developers) +* [Contributing Guide](https://github.com/OpenRefine/OpenRefine/blob/master/CONTRIBUTING.md) +* [Project Governance](https://github.com/OpenRefine/OpenRefine/blob/master/GOVERNANCE.md) + +## Contact us + +* [Mailing List](https://groups.google.com/forum/#!forum/openrefine) +* [Twitter](http://www.twitter.com/openrefine) +* [Gitter](https://gitter.im/OpenRefine/OpenRefine) +* [Matrix (bridged from Gitter)](https://matrix.to/#/#OpenRefine_OpenRefine:gitter.im) + +## Licensing and legal issues + +OpenRefine is open source software and is licensed under the BSD license +located in the [LICENSE.txt](LICENSE.txt). See the folder `licenses` for information on open source +libraries that OpenRefine depends on. + +## Credits + +This software was created by Metaweb Technologies, Inc. and originally written +and conceived by David Huynh . Metaweb Technologies, Inc. +was acquired by Google, Inc. in July 2010 and the product was renamed Google Refine. +In October 2012, it was renamed OpenRefine as it transitioned to a +community-supported product. + +See [CONTRIBUTING.md](./CONTRIBUTING.md) for instructions on how to contribute yourself. diff --git a/OpenRefine/SECURITY.md b/OpenRefine/SECURITY.md new file mode 100644 index 000000000..5fc1181b9 --- /dev/null +++ b/OpenRefine/SECURITY.md @@ -0,0 +1,18 @@ +# OpenRefine Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 3.5.x | :white_check_mark: | +| <= 3.4 | :x: | + +## Reporting a Vulnerability + +You can privately report a vulnerability to us by sending a report to this private mailing list [mailto:openrefine-coredev@googlegroups.com](mailto:openrefine-coredev@googlegroups.com) + +Our core team will try their best to fix any valid vulnerability that is reported to them. + +Keep in mind that OpenRefine is designed to run locally on a users PC, while also making network calls across the internet only upon a users choice or command. + +As such, certain vulnerabilities might not apply to OpenRefine's design. diff --git a/OpenRefine/appveyor.yml b/OpenRefine/appveyor.yml new file mode 100644 index 000000000..81ed3c167 --- /dev/null +++ b/OpenRefine/appveyor.yml @@ -0,0 +1,63 @@ +version: 1.0.{build} + +services: +- mysql +- postgresql96 + +init: +- cmd: java -version 2>&1 | find "version" + +clone_depth: 5 +skip_branch_with_pr: true +skip_commits: + files: + - docs/ + +environment: + JAVA_HOME: C:\Program Files\Java\jdk11 + MAVEN_HOME: C:\Program Files (x86)\Apache\Maven + +matrix: + fast_finish: true + +build: off + +# scripts to run before test +before_test: +- cmd: echo Running scripts before build... +- cmd: |- + PATH=C:\Program Files\PostgreSQL\9.6\bin\;C:\Program Files\MySQL\MySQL Server 5.7\bin\;%PATH% + SET MYSQL_PWD=Password12! + mysql -u root --password=Password12! -e "create database test_db;" + mysql -u root test_db --password=Password12! < extensions\database\tests\conf\test-mysql.sql + echo "localhost:*:test_db:postgres:Password12!" > C:\Program Files\PostgreSQL\9.6\pgpass.conf + echo "localhost:*:test_db:postgres:Password12!" > pgpass.conf + echo "localhost:*:test_db:postgres:Password12!" > %userprofile%\pgpass.conf + SET PGPASSFILE=C:\Program Files\PostgreSQL\9.6\pgpass.conf + SET PGPASSWORD=Password12! + SET PGUSER=postgres + createdb test_db + psql -U postgres test_db < extensions\database\tests\conf\test-pgsql.sql + + copy extensions\database\tests\conf\appveyor_tests.xml extensions\database\tests\conf\tests.xml + copy packaging\test_pom.xml packaging\pom.xml +- cmd: |- + mvn process-resources + mvn package -DskipTests=true -Dmaven.javadoc.skip=true -B -V + +test_script: +- cmd: echo Running test_script... +- cmd: >- + echo PATH is: + + path + + refine test + +on_failure: +- cmd: |- + dir + +cache: + - C:\Users\appveyor\.m2 + diff --git a/OpenRefine/benchmark/pom.xml b/OpenRefine/benchmark/pom.xml new file mode 100644 index 000000000..56cf7a872 --- /dev/null +++ b/OpenRefine/benchmark/pom.xml @@ -0,0 +1,159 @@ + + + 4.0.0 + + openrefine + org.openrefine + 3.6-SNAPSHOT + + + benchmark + jar + + OpenRefine Java JMH benchmarks + + + + ${project.groupId} + main + ${project.version} + provided + + + javax.servlet + javax.servlet-api + ${servlet-api.version} + provided + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + provided + + + org.testng + testng + 7.4.0 + test + + + + + UTF-8 + 1.34 + ${java.minversion} + openrefine-benchmarks + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.9.0 + + ${javac.target} + ${javac.target} + ${javac.target} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + ${uberjar.name} + + + org.openjdk.jmh.Main + + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + ${project.groupId}:main:*:* + *:* + + + + + + + + + + + maven-clean-plugin + 2.5 + + + maven-install-plugin + 2.5.2 + + + maven-jar-plugin + ${maven-jar-plugin.version} + + + maven-javadoc-plugin + 3.3.1 + + + maven-resources-plugin + 3.2.0 + + + maven-site-plugin + 3.10.0 + + + maven-source-plugin + 3.2.1 + + + maven-surefire-plugin + 2.17 + + true + + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + true + + + + + + + diff --git a/OpenRefine/benchmark/src/main/java/org/openrefine/benchmark/ToNumberBenchmark.java b/OpenRefine/benchmark/src/main/java/org/openrefine/benchmark/ToNumberBenchmark.java new file mode 100644 index 000000000..ee55a2e79 --- /dev/null +++ b/OpenRefine/benchmark/src/main/java/org/openrefine/benchmark/ToNumberBenchmark.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (C) 2020, OpenRefine contributors + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +package org.openrefine.benchmark; + +import java.util.Properties; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +import com.google.refine.expr.functions.ToNumber; + +public class ToNumberBenchmark { + + static Properties bindings = new Properties(); + + @State(Scope.Benchmark) + public static class ExecutionPlan { + + @Param({ "1000", "10000" }) + public int iterations; + + public ToNumber f; + String[] args = new String[1]; + String testData; + String testDataInt; + Random rnd = new Random(); + + @Setup(Level.Invocation) + public void setUp() { + f = new ToNumber(); + testData = Double.toString(rnd.nextDouble() * 10000); + testDataInt = testData.replace(".", ""); + } + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Warmup(iterations = 3, time = 200, timeUnit = TimeUnit.MILLISECONDS) + @Measurement(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS) + public void toDoubleNew(ExecutionPlan plan, Blackhole blackhole) { + plan.args[0] = plan.testData; + blackhole.consume(plan.f.call(bindings, plan.args)); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Warmup(iterations = 3, time = 200, timeUnit = TimeUnit.MILLISECONDS) + @Measurement(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS) + @Fork(1) + public void toLongNew(ExecutionPlan plan, Blackhole blackhole) { + plan.args[0] = plan.testDataInt; + blackhole.consume(plan.f.call(bindings, plan.args)); + } +} diff --git a/OpenRefine/conf/openrefine.l4j.ini b/OpenRefine/conf/openrefine.l4j.ini new file mode 100644 index 000000000..e4b7cff25 --- /dev/null +++ b/OpenRefine/conf/openrefine.l4j.ini @@ -0,0 +1,13 @@ +# Launch4j runtime config + +# initial memory heap size +-Xms256M + +# max memory memory heap size +-Xmx1024M + +# Use system defined HTTP proxies +-Djava.net.useSystemProxies=true + +#-XX:+UseLargePages +#-Dsomevar="%SOMEVAR%" diff --git a/OpenRefine/conf/pmd.rules.xml b/OpenRefine/conf/pmd.rules.xml new file mode 100644 index 000000000..2dfe998cf --- /dev/null +++ b/OpenRefine/conf/pmd.rules.xml @@ -0,0 +1,32 @@ + + + OpenRefine PMD Ruleset + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenRefine/docs/.gitignore b/OpenRefine/docs/.gitignore new file mode 100644 index 000000000..c32cbeb55 --- /dev/null +++ b/OpenRefine/docs/.gitignore @@ -0,0 +1,24 @@ +node_modules + +lib/core/metadata.js +lib/core/MetadataBlog.js + +translated_docs +build/ +package-lock.json +i18n/* + +# generated files +.docusaurus +.cache-loader + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/OpenRefine/docs/.node-version b/OpenRefine/docs/.node-version new file mode 100644 index 000000000..8351c1939 --- /dev/null +++ b/OpenRefine/docs/.node-version @@ -0,0 +1 @@ +14 diff --git a/OpenRefine/docs/README.md b/OpenRefine/docs/README.md new file mode 100644 index 000000000..777db3d07 --- /dev/null +++ b/OpenRefine/docs/README.md @@ -0,0 +1,106 @@ +How to build these docs +======================= + +We use [Docusaurus 2](https://v2.docusaurus.io/) for our docs, a modern static website generator. + +### Requirements + +Assuming you have [Node.js (LTS recommended)](https://nodejs.org/en/download/) installed (which includes npm), you can install Docusaurus with: + +You will need to install [Yarn](https://yarnpkg.com/getting-started/install) before you can build the site. + +```sh +npm install -g yarn +``` + +### Installation + +Once you have installed yarn, navigate to docs directory & set-up the dependencies. + +```sh +cd docs +yarn +``` + +### Local Development + +```sh +yarn start +``` + +This command starts a local development server and opens up a browser window. Usually at the URL +Most changes are reflected live without having to restart the server. + +If you get an error starting yarn mentioning `update.latest` such as + +```sh +>yarn start + +if (notifier.update && semver.gt(this.update.latest, this.update.current)) { +TypeError: Cannot read property 'latest' of undefined + at Object. (E:\GitHubRepos\OpenRefine\docs\node_modules\@docusaurus\core\bin\docusaurus.js:49:46) +error Command failed with exit code 1. +``` + +then it is likely that you will need to first run + +```sh +yarn upgrade +``` + +which will update all dependencies and store them in the `yarn.lock` file to also be committed. + +### Next version of OpenRefine docs + +If you wish to work on the next version of docs for OpenRefine (`master` branch) then you will need to: + +1. Git checkout our `master` branch +2. Edit files under `docs/docs/` +3. Preview changes with the URL kept pointing to which will automatically + show changes live with yarn after you save a file. + +### Build + +```sh +yarn build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. +### (Optional) Test Build Locally +You can locally test ([with parameters](https://docusaurus.io/docs/cli#docusaurus-serve-sitedir)) the static content in the `build` directory (in case you don't have access to a hosting service) by using: + +```sh +yarn serve +``` + +or to build and then serve locally with one command: + +```sh +yarn serve --build +``` + +### Deployment + +```sh +GIT_USER= USE_SSH=true yarn deploy +``` + +If you are using GitHub pages for hosting, this command is a convenient way to build the website +and push to the `gh-pages` branch. + +### Translations + +It is now possible to translate the [OpenRefine docs](https://docs.openrefine.org/) via the +Crowdin platform: + + + +Unfortunately, unlike Weblate, we need to manually invite anyone who +wants to contribute translations. Feel free to request an invite by emailing us at openrefine-dev@googlegroups.com +We can also add languages, depending on interest. + +Your translations will not be immediately published on , it will take a few days +(at the next commit on the master branch). +The translated pages will first appear under (the documentation for the development version). +When we publish a version, the translations for that version, we will take a snapshot of the translations during that time. +We will trial this process for 3.5. diff --git a/OpenRefine/docs/crowdin.yml b/OpenRefine/docs/crowdin.yml new file mode 100644 index 000000000..24042688e --- /dev/null +++ b/OpenRefine/docs/crowdin.yml @@ -0,0 +1,16 @@ +project_id: '455186' +api_token_env: 'CROWDIN_PERSONAL_TOKEN' +preserve_hierarchy: true +files: [ + # Markdown files for the user manual + { + source: '/docs/manual/**/*', + translation: '/i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name%', + }, + # Docs home page + { + source: '/docs/index.md', + translation: '/i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/%original_file_name%', + }, + + ] diff --git a/OpenRefine/docs/docs/index.md b/OpenRefine/docs/docs/index.md new file mode 100644 index 000000000..473cb8c7a --- /dev/null +++ b/OpenRefine/docs/docs/index.md @@ -0,0 +1,25 @@ +--- +slug: / +id: index +title: OpenRefine user manual +sidebar_label: Introduction +--- + + +This manual is designed to comprehensively walk through every aspect of setting up and using OpenRefine 3.4.1, including every interface function and feature. + + + +This user manual starts with instructions for [installing or upgrading OpenRefine on Windows, Mac, and Linux computers](manual/installing). It then walks you through [the interface and how to run OpenRefine](manual/running#jvm-preferences) from a program or command line, with or without setting custom preferences and modifications. + +The manual then teaches you how to [start a project](manual/starting) by importing an existing dataset. We work through how to [view and learn about your data](manual/exploring) using facets, filters, and sorting. + +Then we launch into [transforming that data permanently](manual/transforming) through common and custom transformations, clustering, pulling data from the web, [reconciling](manual/reconciling), and [writing expressions](manual/expressions). + +Finally we discuss what to do with your improved dataset, whether [exporting](manual/exporting) it to a file or [uploading statements to Wikidata or another Wikibase instance](manual/wikibase/overview). + +If you're stuck on any aspect and can't find an answer in the manual, try the [Troubleshooting page](manual/troubleshooting) for links to various places to find help. + +If you are new and want to learn how to use OpenRefine using an example dataset, you may wish to start with a user-contributed tutorial from our [recommendations list](https://github.com/OpenRefine/OpenRefine/wiki/External-Resources). diff --git a/OpenRefine/docs/docs/manual/cellediting.md b/OpenRefine/docs/docs/manual/cellediting.md new file mode 100644 index 000000000..103c8ed45 --- /dev/null +++ b/OpenRefine/docs/docs/manual/cellediting.md @@ -0,0 +1,165 @@ +--- +id: cellediting +title: Cell editing +sidebar_label: Cell editing +--- +## Overview {#overview} + +OpenRefine offers a number of features to edit and improve the contents of cells automatically and efficiently. + +One way of doing this is editing through a [text facet](facets#text-facet). Once you have created a facet on a column, hover over the displayed results in the sidebar. Click on the small “edit†button that appears to the right of the facet, and type in a new value. This will apply to all the cells in the facet. + +You can apply a text facet on numbers, boolean values, and dates, but if you edit a value it will be converted into the text [data type](exploring#data-types) (regardless of whether you edit a date into another correctly-formatted date, or a “true†value into “falseâ€, etc.). + +## Transform {#transform} + +Select Edit cells → Transform... to open up an expressions window. From here, you can apply [expressions](expressions) to your data. The simplest examples are GREL functions such as [`toUppercase()`](grelfunctions#touppercases) or [`toLowercase()`](grelfunctions#tolowercases), used in expressions as `toUppercase(value)` or `toLowercase(value)`. When used on a column operation, `value` is the information in each cell in the selected column. + +Use the preview to ensure your data is being transformed correctly. + +You can also switch to the Undo / Redo tab inside the expressions window to reuse expressions you’ve already attempted in this project, whether they have been undone or not. + +OpenRefine offers you some frequently-used transformations in the next menu option, Common transforms. For more custom transforms, read up on [expressions](expressions). + +## Common transforms {#common-transforms} + +### Trim leading and trailing whitespace {#trim-leading-and-trailing-whitespace} + +Often cell contents that should be identical, and look identical, are different because of space or line-break characters that are invisible to users. This function will get rid of any characters that sit before or after visible text characters. + +### Collapse consecutive whitespace {#collapse-consecutive-whitespace} + +You may find that some text cells contain what look like spaces but are actually tabs, or contain multiple spaces in a row. This function will remove all space characters that sit in sequence and replace them with a single space. + +### Unescape HTML {#unescape-html} + +Your data may come from an HTML-formatted source that expresses some characters through references (such as “&nbsp;†for a space, or “%u0107†for a ć) instead of the actual Unicode characters. You can use the “unescape HTML entities†transform to look for these codes and replace them with the characters they represent. For other formatting that needs to be escaped, try a custom transformation with [`escape()`](grelfunctions#escapes-s-mode). + +### Replace smart quotes with ASCII {#replace-smart-quotes-with-ascii} + +Smart quotes (or curly quotes) recognize whether they come at the beginning or end of a string, and will generate an “open†quote (“) and a “close†quote (â€). These characters are not ASCII-compliant (though they are UTF8-compliant) so you can use this tranform to replace them with a straight double quote character (") instead. + +### Case transforms {#case-transforms} + +You can transform an entire column of text into UPPERCASE, lowercase, or Title Case using these three options. This can be useful if you are planning to do textual analysis and wish to avoid case-sensitivity (which some functions are) causing problems in your analysis. Consider also using a [custom facet](facets#custom-text-facet) to temporarily modify cases instead of this permanent operation if appropriate. + +### Data-type transforms {#data-type-transforms} + +As detailed in [Data types](exploring#data-types), OpenRefine recognizes different data types: string, number, boolean, and date. When you use these transforms, OpenRefine will check to see if the given values can be converted, then both transform the data in the cells (such as “3†as a text string to “3†as a number) and convert the data type on each successfully transformed cell. Cells that cannot be transformed will output the original value and maintain their original data type. + +:::caution +Be aware that dates may require manual intervention to transform successfully: see the section on [Dates](exploring#dates) for more information. +::: + +Because these common transforms do not offer the ability to output an error instead of the original cell contents, be careful to look for unconverted and untransformed values. You will see a yellow alert at the top of screen that will tell you how many cells were converted - if this number does not match your current row set, you will need to look for and manually correct the remaining cells. Also consider faceting by data type, with the GREL function [`type()`](grelfunctions#typeo). + +You can also convert cells into null values or empty strings. This can be useful if you wish to, for example, erase duplicates that you have identified and are analyzing as a subset. + +## Fill down and blank down {#fill-down-and-blank-down} + +Fill down and blank down are two functions most frequently used when encountering data organized into [records](exploring#row-types-rows-vs-records) - that is, multiple rows associated with one specific entity. + +If you receive information in rows mode and want to convert it to records mode, the easiest way is to sort your first column by the value that you want to use as a unique records key, [make that sorting permanent](transforming#edit-rows), then blank down all the duplicates in that column. OpenRefine will retain the first unique value and erase the rest. Then you can switch from “Show as rows†to “Show as records†and OpenRefine will associate rows to each other based on the remaining values in the first column. + +Be careful that your data is sorted properly before you begin blanking down - not just the first column but other columns you may want to have in a certain order. For example, you may have multiple identical entries in the first column, one with a value in the second column and one with an empty cell in the second column. In this case you want the row with the second-column value to come first, so that you can clean up empty rows later, once you blank down. + +If, conversely, you’ve received data with empty cells because it was already in something akin to records mode, you can fill down information to the rest of the rows. This will duplicate whatever value exists in the topmost cell with a value: if the first row in the record is blank, it will take information from the next cell, or the cell after that, until it finds a value. The blank cells above this will remain blank. + +## Split multi-valued cells {#split-multi-valued-cells} + +Splitting cells with more than one value in them is a common way to get your data from single rows into [multi-row records](exploring#rows-vs-records). Survey data, for example, frequently allows respondents to “Select all that apply,†or an inventory list might have items filed under more than one category. + +You can split a column based on any character or series of characters you input, such as a semi-colon (;) or a slash (/). The default is a comma. Splitting based on a separator will remove the separator characters, so you may wish to include a space with your separator (; ) if it exists in your data. + +You can use [expressions](expressions) to design the point at which a cell should split itself into two or more rows. This can be used to identify special characters or create more advanced evaluations. You can split on a line-break by entering `\n` and checking the “[regular expression](expressions#regular-expressions)†checkbox. + +Regular expressions can be useful if the split is not straightforward: say, if a capital letter (`[A-Z]`) indicates the beginning of a new string, or if you need to _not_ always split on a character that appears in both the strings and as a separator. Remember that this will remove all the matching characters. + +You can also split based on the lengths of the strings you expect to find. This can be useful if you have predictable data in the cells: for example, a 10-digit phone number, followed by a space, followed by another 10-digit phone number. Any characters past the explicit length you’ve specified will be discarded: if you split by “11, 10†any characters that may come after the 21st character will disappear. If some cells only have one phone number, you will end up with blank rows. + +If you have data that should be split into multiple columns instead of multiple rows, see [Split into several columns](columnediting#split-into-several-columns). + +## Join multi-valued cells {#join-multi-valued-cells} + +Joining will reverse the “split multi-valued cells†operation, or join up information from multiple rows into one row. All the strings will be compressed into the topmost cell in the record, in the order they appear. A window will appear where you can set the separator; the default is a comma and a space (, ). This separator is optional. We suggest the separator | as a sufficiently rare character. + +## Cluster and edit {#cluster-and-edit} + +Creating a facet on a column is a great way to look for inconsistencies in your data; clustering is a great way to fix those inconsistencies. Clustering uses a variety of comparison methods to find text entries that are similar but not exact, then shares those results with you so that you can merge the cells that should match. Where editing a single cell or text facet at a time can be time-consuming and difficult, clustering is quick and streamlined. + +Clustering always requires the user to approve each suggested edit - it will display values it thinks are variations on the same thing, and you can select which version to keep and apply across all the matching cells (or type in your own version). + +OpenRefine will do a number of cleanup operations behind the scenes in order to do its analysis, but only the merges you approve will modify your data. Understanding those different behind-the-scenes cleanups can help you choose which clustering method will be more accurate and effective. + +You can start the process in two ways: using the dropdown menu on your column, select Edit cells → Cluster and edit…; or create a text facet and then press the “Cluster†button that appears in the facet box. + +![A screenshot of the Clustering window.](/img/cluster.png) + +The clustering pop-up window will take a small amount of time to analyze your column, and then make some suggestions based on the clustering method currently active. + +For each cluster identified, you can pick one of the existing values to apply to all cells, or manually type in a new value in the text box. And, of course, you can choose not to cluster them at all. OpenRefine will keep analyzing every time you make a change, with Merge selected & re-cluster, and you can work through all the methods this way. + +You can also export the currently identified clusters as a JSON file, or close the window with or without applying your changes. You can also use the histograms on the right to narrow down to, for example, clusters with lots of matching rows, or clusters of long or short values. + +### Clustering methods {#clustering-methods} + +You don’t need to understand the details behind each clustering method to apply them successfully to your data. The order in which these methods are presented in the interface and on this page is the order we recommend - starting with the most strict rules and moving to the most lax, which require more human supervision to apply correctly. + +The clustering pop-up window offers you a variety of clustering methods: + +* key collision + * fingerprint + * ngram-fingerprint + * metaphone3 + * cologne-phonetic + * Daitch-Mokotoff + * Beider-Morse +* nearest neighbor + * levenshtein + * ppm + +#### Key collision {#key-collision} + +**Key collisions** are very fast and can process millions of cells in seconds: + +**Fingerprinting** is the least likely to produce false positives, so it’s a good place to start. It does the same kind of data-cleaning behind the scenes that you might think to do manually: fix whitespace into single spaces, put all uppercase letters into lowercase, discard punctuation, remove diacritics (e.g. accents) from characters, split up all strings (words) and sort them alphabetically (so “Zhenyi, Wang†becomes “wang zhenyiâ€). + +**N-gram fingerprinting** allows you to set the _n_ value to whatever number you’d like, and will create n-grams of _n_ size (after doing some cleaning), alphabetize them, then join them back together into a fingerprint. For example, a 1-gram fingerprint will simply organize all the letters in the cell into alphabetical order - by creating segments one character in length. A 2-gram fingerprint will find all the two-character segments, remove duplicates, alphabetize them, and join them back together (for example, “banana†generates “ba an na an na,†which becomes “anbanaâ€). + +This can help match cells that have typos, or incorrect spaces (such as matching “lookout†and “look out,†which fingerprinting itself won’t identify because it separates words). The higher the _n_ value, the fewer clusters will be identified. With 1-grams, keep an eye out for mismatched values that are near-anagrams of each other (such as “Wellington†and “Elgin Townâ€). + +##### Phonetic clustering {#phonetic-clustering} + +The next four methods are phonetic algorithms: they identify letters that sound the same when pronounced out loud, and assess text values based on that (such as knowing that a word with an “S†might be a mistype of a word with a “Zâ€). They are great for spotting mistakes made by not knowing the spelling of a word or name after hearing it spoken aloud. + +**Metaphone3 fingerprinting** is an English-language phonetic algorithm. For example, “Reuben Gevorkiantz†and “Ruben Gevorkyants†share the same phonetic fingerprint in English. + +**Cologne fingerprinting** is another phonetic algorithm, but for German pronunciation. + +**Daitch-Mokotoff** is a phonetic algorithm for Slavic and Yiddish words, especially names. **Baider-Morse** is a version of Daitch-Mokotoff that is slightly more strict. + +Regardless of the language of your data, applying each of them might find different potential matches: for example, Metaphone clusters “Cornwall†and “Corn Hill†and “Green Hill,†while Cologne clusters “Greenvale†and “Granville†and “Cornwall†and “Green Wall.†+ +#### Nearest neighbor {#nearest-neighbor} + +**Nearest neighbor** clustering methods are slower than key collision methods. They allow the user to set a radius - a threshold for matching or not matching. OpenRefine uses a “blocking†method first, which sorts values based on whether they have a certain amount of similarity (the default is “6†for a six-character string of identical characters) and then runs the nearest-neighbor operations on those sorted groups. + +We recommend setting the block number to at least 3, and then increasing it if you need to be more strict (for example, if every value with “river†is being matched, you should increase it to 6 or more). Note that bigger block values will take much longer to process, while smaller blocks may miss matches. Increasing the radius will make the matches more lax, as bigger differences will be clustered. + +**Levenshtein distance** counts the number of edits required to make one value perfectly match another. As in the key collision methods above, it will do things like change uppercase to lowercase, fix whitespace, change special characters, etc. Each character that gets changed counts as 1 “distance.†“New York†and “newyork†have an edit distance value of 3 (“N†to “nâ€; “Y†to “yâ€; remove the space). It can do relatively advanced edits, such as understand the distance between “M. Makeba†and “Miriam Makeba†(5), but it may create false positives if these distances are greater than other, simpler transformations (such as the one-character distance to “B. Makeba,†another person entirely). + +**PPM (Prediction by Partial Matching)** uses compression to see whether two values are similar or different. In practice, this method is very lax even for small radius values and tends to generate many false positives, but because it operates at a sub-character level it is capable of finding substructures that are not easily identifiable by distances that work at the character level. So it should be used as a “last resort†clustering method. It is also more effective on longer strings than on shorter ones. + +For more of the theory behind clustering, see [Clustering In Depth](https://github.com/OpenRefine/OpenRefine/wiki/Clustering-In-Depth). + +## Replace {#replace} + +OpenRefine provides a find/replace function for you to edit your data. Selecting Edit cells → Replace will bring up a simple window where you can input a string to search and a string to replace it with. You can set case-sensitivity, and set it to only select whole words, defined by a string with spaces or punctuation around it (to prevent, for example, “house†selecting the “house†part of “doghouseâ€). You can use [regular expressions](expressions#regular-expressions) in this field. You may wish to preview the results of this operation by testing it with a [Text filter](facets#text-filter) first. + +You can also perform a sort of find/replace operation by editing one cell, and selecting “apply to all identical cells.†+ +## Edit one cell at a time {#edit-one-cell-at-a-time} + +You can edit individual cells by hovering your mouse over that cell. You should see a tiny blue link labeled “edit.†Click it to edit the cell. That pops up a window with a bigger text field for you to edit. You can change the [data type](exploring#data-types) of that cell, and you can apply these changes to all identical cells (in the same column), using this pop-up window. + +You will likely want to avoid doing this except in rare cases - the more efficient means of improving your data will be through automated and bulk operations. \ No newline at end of file diff --git a/OpenRefine/docs/docs/manual/columnediting.md b/OpenRefine/docs/docs/manual/columnediting.md new file mode 100644 index 000000000..754a61c62 --- /dev/null +++ b/OpenRefine/docs/docs/manual/columnediting.md @@ -0,0 +1,124 @@ +--- +id: columnediting +title: Column editing +sidebar_label: Column editing +--- + +## Overview {#overview} + +Column editing contains some of the most powerful data-improvement methods in OpenRefine. The operations in the Edit column menu involve using one column of data to add entirely new columns and fields to your dataset. + +## Splitting or joining {#splitting-or-joining} + +Many users find that they frequently need to make their data more granular: for example, splitting a “Firstname Lastname†column into two columns, one for first names and one for last names. The reverse is also often true: you may have several columns of category values that you want to join into one “category†column. +. +### Split into several columns {#split-into-several-columns} + +![A screenshot of the settings window for splitting columns.](/img/columnsplit.png) + +You can find this operation at Edit column → Split into several columns.... Splitting one column into several columns requires you to identify the character, string lengths, or evaluating expression you want to split on. Just like [splitting multi-valued cells into rows](cellediting#split-multi-valued-cells), splitting cells into multiple columns will remove the separator character or string you indicate. Splitting by lengths will discard any information that comes after the specified total length. + +You can also specify a maximum number of new columns to be made: separator characters after this limit will be ignored, and the remaining characters will end up in the last column. + +New columns will be named after the original column, with a number: “Location 1,†“Location 2,†etc. You can choose to remove the original column with this operation, and you can have [data types](exploring#data-types) identified where possible. This function will work best with converting strings to numbers, and may not work with [dates](exploring#dates). + +### Join columns {#join-columns} + +![A screenshot of the settings window for joining columns.](/img/columnjoin.png) + +You can join columns by selecting Edit column → Join columns.... All the columns currently in your dataset will appear in the pop-up window. You can select or un-select all the columns you want to join, and drag columns to put them in the order you want to join them in. You will define a separator character (optional) and define a string to insert into empty cells (nulls). + +The joined data will appear in the column you originally selected, or you can create a new column for this content and specify a name. You can delete all the columns that were used in this join operation. + +## Add column based on this column {#add-column-based-on-this-column} + +Selecting Edit column → Add column based on this column... will open up an [expressions](expressions) window where you can transform the data from this column (using `value`), or write a more complex expression that takes information from any number of columns or from external sources. + +Expressions used in this operation will rely on your knowledge of variables. You can learn more in the [Expressions section on variables](expressions#variables). + +The simplest way to use this operation is simply leave the default `value` in the expression field, to create an exact copy of your column. For a column of [reconciled data](reconciling), you can use the variable `cell` instead, to copy both the original string and the existing reconciliation data. This will include matched values, candidates, and new items. + +One useful expression is to create a column based on concatenating (merging) two other columns. Select either of the source columns, choose Edit column → Add column based on this column..., name your new column, and use the following format in the expression window: + +``` +cells["Column 1"].value + cells["Column 2"].value +``` + +If your column names do not contain spaces, you can use the following format instead: + +``` +cells.Column1.value + cells.Column2.value +``` + +If you are in records mode instead of rows mode, you can concatenate using the following format: + +``` +row.record.cells.Column1.value + row.record.cells.Column2.value +``` + +You may wish to add separators or spaces, or modify your input during this operation with more advanced expressions. + +## Add column by fetching URLs {#add-column-by-fetching-urls} + +Through the Add column by fetching URLs function, OpenRefine supports the ability to fetch HTML or data from web pages or services. In this operation you will be building URL strings based on your column of data, by using `value` to insert a relevant substring. Your chosen column needs to contains parts of paths to valid HTML pages or files online. + +If you have a column of URLs and want to fetch the information that they point to, you can simply run the expression as `value`. If your column has, for example, unique identifiers for Wikidata entities (numerical values starting with Q), you can download the JSON-formatted metadata about each entity with + +``` +"https://www.wikidata.org/wiki/Special:EntityData/" + value + ".json" +``` + +or whatever metadata format you prefer. Information about the format options in Wikidata can be found [here](https://www.wikidata.org/wiki/Wikidata:Data_access). The service you are fetching data from may have similar documentation on its provided options. + +![A screenshot of the settings window for fetching URLs.](/img/fetchingURLs.png) + +This service is more useful when getting metadata files instead of HTML, but you may wish to work with a page’s entire HTML contents and then parse out information from that. + +:::caution +Be aware that the fetching process can take quite some time and that servers may not want to fulfill hundreds or thousands of page requests in seconds. Fetching allows you to set a “throttle delay†which determines the amount of time between requests. The default is 5 seconds per row in your dataset (5000 milliseconds). We recommend leaving this at 1000 or greater. +::: + +Note the following: +* Before pressing “OK,†copy and paste a URL or two from the preview and test them in another browser tab to make sure they work. +* In some situations you may need to set [HTTP request headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers). To set these, click the small “Show†button next to “HTTP headers to be used when fetching URLs†in the settings window. The authorization credentials get logged in your operation history in plain text, which may be a security concern for you. You can set the following request headers: + * [User-Agent](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) + * [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) + * [Authorization](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) + +### Common errors {#common-errors} + +When OpenRefine attempts to fetch information from a web service, it can fail in a variety of ways. The following information is meant to help troubleshoot and fix problems encountered when using this function. + +First, make sure that your fetching operation is storing errors (check “store errorâ€). Then run the fetch and look at the error messages. + +**“HTTP error 403 : Forbiddenâ€** can be simply down to you not having access to the URL you are trying to use. If you can access the same URL with your browser, the remote site may be blocking OpenRefine because it doesn't recognize its request as valid. Changing the [User-Agent](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) request header may help. If you believe you should have access to a site but are “forbidden,†you may wish to contract the administrators. + +**“HTTP error 404 : Not Foundâ€** indicates that the information you are requesting does not exist, perhaps due to a problem with your cell values if it only happening in certain rows. + +**“HTTP error 500 : Internal Server Errorâ€** indicates the remote server is having a problem filling your request. You may wish to simply wait and try again later, or double-check the URLs. + +**“error: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failureâ€** can occur when you are trying to retrieve information over HTTPS but the remote site is using an encryption not supported by the Java virtual machine being used by OpenRefine. + +You can check which encryption methods are supported by your OpenRefine/Java installation by using a service such as **How's my SSL**. Add the URL `https://www.howsmyssl.com/a/check` to an OpenRefine cell and run “Add column by fetching URLs†on it, which will provide a description of the SSL client being used. + +You can try installing additional encryption supports by installing the [Java Cryptography Extension](https://www.oracle.com/java/technologies/javase-jce8-downloads.html). +Note that for Mac users and for Windows users with the OpenRefine installation with bundled JRE, these updated cipher suites need to be dropped into the Java install within the OpenRefine application: + +* On Mac, it will look something like `/Applications/OpenRefine.app/Contents/PlugIns/jdk1.8.0_60.jdk/Contents/Home/jre/lib/security`. +* On Windows: `\server\target\jre\lib\security`. + +**“javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failedâ€** can appear when the remote site is using an HTTPS certificate not trusted by your local Java installation. You will need to make sure that the certificate, or (more likely) the root certificate, is trusted. + +The list of trusted certificates is stored in an encrypted file called `cacerts` in your local Java installation. This can be read and updated by a tool called “keytool.†You can find directions on how to add a security certificate to the list of trusted certificates for a Java installation [here](http://magicmonster.com/kb/prg/java/ssl/pkix_path_building_failed.html) and [here](http://javarevisited.blogspot.co.uk/2012/03/add-list-certficates-java-keystore.html). + +Note that for Mac users and for Windows users with the OpenRefine installation with bundled JRE, the `cacerts` file within the OpenRefine application needs to be updated. + +* On Mac, it will look something like `/Applications/OpenRefine.app/Contents/PlugIns/jdk1.8.0_60.jdk/Contents/Home/jre/lib/security/cacerts`. +* On Windows: `\server\target\jre\lib\security\`. + +## Renaming, removing, and moving {#renaming-removing-and-moving} + +Every column's Edit column dropdown contains options to move it (to the beginning, end, left, or right), rename it, and delete it. +These operations can be undone, but a removed column cannot be restored later if you keep modifying your data. If you wish to temporarily hide a column, go to [View](sortview#view) → Collapse this column instead. + +Be cautious about moving columns in [records mode](cellediting#rows-vs-records): if you change the first column in your dataset (the key column), your records may change in unintended ways. diff --git a/OpenRefine/docs/docs/manual/exploring.md b/OpenRefine/docs/docs/manual/exploring.md new file mode 100644 index 000000000..23bafc1a7 --- /dev/null +++ b/OpenRefine/docs/docs/manual/exploring.md @@ -0,0 +1,116 @@ +--- +id: exploring +title: Exploring data +sidebar_label: Overview +--- + +## Overview {#overview} + +OpenRefine offers lots of features to help you learn about your dataset, even if you don’t change a single character. In this section we cover different ways for sorting through, filtering, and viewing your data. + +Unlike spreadsheets, OpenRefine doesn’t store formulas and display the output of those calculations; it only shows the value inside each cell. It doesn’t support cell colors or text formatting. + +## Data types {#data-types} + +Each piece of information (each cell) in OpenRefine is assigned a data type. Some file formats, when imported, can set data types that are recognized by OpenRefine. Cells without an associated data type on import will be considered a “string†at first, but you can have OpenRefine convert cell contents into other data types later. This is set at the cell level, not at the column level. + +You can see data types in action when you preview a new project: check the box next to Attempt to parse cell text into numbers, and cells will be converted to the “number†data type based on their contents. You’ll see numbers change from black text to green if they are recognized. + +The data type will determine what you can do with the value. For example, if you want to add two values together, they must both be recognized as the number type. + +You can check data types at any time by: +* clicking “edit†on a single cell (where you can also edit the type) +* creating a Custom Text Facet on a column, and inserting `type(value)` into the Expression field. This will generate the data type in the preview, and you can facet by data type if you press OK. + +The data types supported are: +* string (one or more text characters) +* number (one or more characters of numbers only) +* boolean (values of “true†or “falseâ€) +* [date](#dates) (ISO-8601-compliant extended format with time in UTC: YYYY-MM-DDTHH:MM:SSZ) + +OpenRefine recognizes two further data types as a result of its own processes: +* error +* null + +An “error†data type is created when the cell is storing an error generated during a transformation in OpenRefine. + +A “null†data type is a special type that means “this cell has no value.†It’s distinct from cells that have values such as “0†or “falseâ€, or cells that look empty but have whitespace in them, or cells that contain empty strings. When you use `type(value)`, it will show you that the cell’s value is “null†and its type is “undefined.†You can opt to [show “null†values](sortview#showhide-null), by going to All → View → Show/Hide ‘null’ values in cells. + +Changing a cell's data type is not the same operation as transforming its contents. For example, using a column-wide transform such as Transform → Common transforms → To date may not convert all values successfully, but going to an individual cell, clicking “editâ€, and changing the data type can successfully convert text to a date. These operations use different underlying code. Learn more about date formatting and transformations in the next section. + +To transform data from one type to another, see [Transforming data](cellediting#data-type-transforms) for information on using common tranforms, and see [Expressions](expressions) for information on using [toString()](grelfunctions#tostringo-string-format-optional), [toDate()](grelfunctions#todateo-b-monthfirst-s-format1-s-format2-), and other functions. + + +### Dates {#dates} + +A “date†type is created when a column is [transformed into dates](transforming#to-date), when an expression is used to [convert cells to dates](grelfunctions#todateo-b-monthfirst-s-format1-s-format2-) or when individual cells are set to have the data type “dateâ€. + +Date-formatted data in OpenRefine relies on a number of conversion tools and standards. For something to be considered a date in OpenRefine, it will be converted into the ISO-8601-compliant extended format with time in UTC: YYYY-MM-DDTHH:MM:SSZ. + +When you run Edit cells → Common transforms → To date, the following column of strings on the left will transform into the values on the right: + +|Input|→|Output| +|---|---|---| +|23/12/2019|→|2019-12-23T00:00:00Z| +|14-10-2015|→|2015-10-14T00:00:00Z| +|2012 02 16|→|2012-02-16T00:00:00Z| +|August 2nd 1964|→|1964-08-02T00:00:00Z| +|today|→|today| +|never|→|never| + +OpenRefine uses a variety of tools to recognize, convert, and format [dates](exploring#dates) and so some of the values above can be reformatted using other methods. In this case, clicking the “today†cell and editing its data type manually will convert “today†into a value such as “2020-08-14T00:00:00Zâ€. Attempting the same data-type change on “never†will give you an error message and refuse to proceed. + +You can do more precise conversion and formatting using expressions and arguments based on the state of your data: see the GREL functions reference section on [Date functions](grelfunctions#date-functions) for more help. + +You can convert dates into a more human-readable format when you [export your data using the custom tabular exporter](exporting#custom-tabular-exporter). You are given the option to keep your dates in the ISO 8601 format, to output short, medium, long, or full locale formats, or to specify a custom format. This means that you can format your dates into, for example, MM/DD/YY (the US short standard) with or without including the time, after working with ISO-8601-formatted dates in your project. + +The following table shows some example [date and time formatting styles for the U.S. and French locales](https://docs.oracle.com/javase/tutorial/i18n/format/dateFormat.html): + +|Style |U.S. Locale |French Locale| +|---|---|---| +|Default |Jun 30, 2009 7:03:47 AM |30 juin 2009 07:03:47| +|Short |6/30/09 7:03 AM |30/06/09 07:03| +|Medium |Jun 30, 2009 7:03:47 AM |30 juin 2009 07:03:47| +|Long |June 30, 2009 7:03:47 AM PDT |30 juin 2009 07:03:47 PDT| +|Full |Tuesday, June 30, 2009 7:03:47 AM PDT |mardi 30 juin 2009 07 h 03 PDT| + +## Rows vs. records {#rows-vs-records} + +A row is a simple way to organize data: a series of cells, one cell per column. Sometimes there are multiple pieces of information in one cell, such as when a survey respondent can select more than one response. + +In cases where there is more than one value for a single column in one or more rows, you may wish to use OpenRefine’s records mode: this defines a single record as potentially containing more than one row. From there you can transform cells into multiple rows, each cell containing one value you’d like to work with. + +Generally, when you import some data, OpenRefine reads that data in row mode. From the project screen, you can convert the project into records mode. OpenRefine remembers this action and will present you with records mode each time you open the project from then on. + +OpenRefine understands records based on the content of the first column, what we call the “key column.†Splitting a row into a multi-row record will base all association on the first column in your dataset. + +If you have more than one column to split out into multiple rows, OpenRefine will keep your data associated with its original record, and associate subgroups based on the top-most row in each group. + +You can imagine the structure as a tree with many branches, all leading back to the same trunk. + +For example, your key column may be a film or television show, with multiple cast members identified by name, associated to that work. You may have one or more roles listed for each person. The roles are linked to the actors, which are linked to the title. + +|Work|Actor|Role| +|---|---|---| +|The Wizard of Oz|Judy Garland|Dorothy Gale| +||Ray Bolger|"Hunk"| +|||The Scarecrow| +||Jack Haley|"Hickory"| +|||The Tin Man| +||Bert Lahr|"Zeke"| +|||The Cowardly Lion| +||Frank Morgan|Professor Marvel| +|||The Gatekeeper| +|||The Carriage Driver| +|||The Guard| +|||The Wizard of Oz| +||Margaret Hamilton|Miss Almira Gulch| +|||The Wicked Witch of the West| + +Once you are in records mode, you can still move some columns around, but if you move a column to the beginning, you may find your data becomes misaligned. The new key column will sort into records based on empty cells, and values in the old key column will be assigned to the last row in the old record (the key value sitting above those values). + +OpenRefine assigns a unique key behind the scenes, so your records don’t need a unique identifier in the key column. You can keep track of which rows are assigned to each record by the record number that appears under the All column. + +To [split multi-valued cells](transforming#split-multi-valued-cells) and apply other operations that take advantage of records mode, see [Transforming data](transforming). + +Be careful when in records mode that you do not accidentally delete rows based on being blank in one column where there is a value in another. diff --git a/OpenRefine/docs/docs/manual/exporting.md b/OpenRefine/docs/docs/manual/exporting.md new file mode 100644 index 000000000..21b1516a9 --- /dev/null +++ b/OpenRefine/docs/docs/manual/exporting.md @@ -0,0 +1,134 @@ +--- +id: exporting +title: Exporting your work +sidebar_label: Exporting +--- + +## Overview {#overview} + +Once your dataset is ready, you will need to get it out of OpenRefine and into the system of your choice. OpenRefine outputs a number of file formats, can upload your data directly into Google Sheets, and can create or update statements on Wikidata. + +You can also [export your full project data](#export-a-project) so that it can be opened by someone else using OpenRefine (or yourself, on another computer). + +## Export data {#export-data} + +![A screenshot of the Export dropdown.](/img/export-menu.png) + +Many of the options only export data in the current view - that is, with current filters and facets applied. Some will give you the choice to export your entire dataset or just the currently-viewed rows. + +To export data from a project, click the Export dropdown button in the top right corner and pick the format you want. Your options are: + +* Tab-separated value (TSV) or Comma-separated value (CSV) +* HTML-formatted table +* Excel spreadsheet (XLS or XLSX) +* Open Document Format (ODF) spreadsheet (ODS) +* Upload to Google Sheets (requires [Google account authorization](starting#google-sheet-from-drive)) +* [Custom tabular exporter](#custom-tabular-exporter) +* [SQL statement exporter](#sql-statement-exporter) +* [Templating exporter](#templating-exporter), which generates JSON by default + +You can also export reconciled data to Wikidata, or export your Wikidata schema for future use with other OpenRefine projects: + +* [Upload edits to Wikidata](wikibase/uploading#uploading-with-openrefine) +* [Export to QuickStatements](wikibase/uploading#uploading-with-quickstatements) (version 1) +* [Export Wikidata schema](wikibase/overview#import-and-export-schema) + +### Custom tabular exporter {#custom-tabular-exporter} + +![A screenshot of the custom tabular content tab.](/img/custom-tabular-exporter.png) + +With the custom tabular exporter, you can choose which of your data to export, the separator you wish to use, and whether you'd like to download the result to your computer or upload it into a Google Sheet. + +On the Content tab, you can drag and drop the columns appearing in the column list to reorder the output. The options for reconciled and date data are applied to each column individually. + +This exporter is especially useful with reconciled data, as you can choose whether you wish to output the cells' original values, the matched values, or the matched IDs. Ouputting “match entity's nameâ€, “matched entity's IDâ€, or “cell's content†will output, respectively, the contents of `cell.recon.match.name`, `cell.recon.match.id`, and `cell.value`. + +“Output nothing for unmatched cells†will export empty cells for both newly-created matches and cells with no chosen matches. “Link to matched entity's page†will produce hyperlinked text in an HTML table output, but have no effect in other formats. + +At this time, the date-formatting options in this window do not work. You can [keep track of this issue on Github](https://github.com/OpenRefine/OpenRefine/issues/3368). +In the future, you will be able to choose how to [output date-formatted cells](exploring#dates). You can create a custom date output by using [formatting according to the SimpleDateFormat parsing key found here](grelfunctions#todateo-b-monthfirst-s-format1-s-format2-). + +![A screenshot of the custom tabular file download tab.](/img/custom-tabular-exporter2.png) + +On the Download tab, you can generate a preview of how the first ten rows of your dataset will output. If you do not choose one of the file formats on the right, the Download button will generate a text file. On the Upload tab, you can create a new Google Sheet. + +With the Option Code tab, you can copy JSON of your current custom settings to reuse on another export, or you can paste in existing JSON settings to apply to the current project. + +### SQL exporter {#sql-exporter} + +The SQL exporter creates a SQL statement containing the data you’ve exported, which you can use to overwrite or add to an existing database. Choosing Export → SQL exporter will bring up a window with two tabs: one to define what data to output, and another to modify other aspects of the SQL statement, with options to preview and download the statement. + +![A screenshot of the SQL statement content window.](/img/sql-exporter.png) + +The Content tab allows you to craft your dataset into an SQL table. From here, you can choose which columns to export, the data type to export for each (or choose "VARCHAR"), and the maximum character length for each field (if applicable based on the data type). You can set a default value for empty cells after unchecking “Allow null†in one or more columns. + +With this output tool, you can choose whether to output only currently visible rows, or all the rows in your dataset, as well as whether to include empty rows. The option to “Trim column names†will remove their whitespace characters. + +![A screenshot of the SQL statement download window.](/img/sql-exporter2.png) + +The Download tab allows you to finalize your complete SQL statement. + +Include schema means that you will start your statement with the creation of a table. Without that, you will only have an INSERT statement. + +Include content means including the INSERT statement with data from your project. Without that, you will only create empty columns. + +You can include DROP and IF EXISTS if you require them, and set a name for the table to which the statement will refer. + +You can then preview your statement, which will open up a new browser tab/window showing a statement with the first ten rows of your data (if included), or you can save a `.sql` file to your computer. + +### Templating exporter {#templating-exporter} + +If you pick Templating… from the Export dropdown menu, you can “roll your own†exporter. This is useful for formats that we don't support natively yet, or won't support. The Templating exporter generates JSON by default. + +![A screenshot of the Templating exporter generating JSON by default.](/img/templating-exporter.png) + +The Templating Export window allows you to set your own separators, prefix, and suffix to create a complete dataset in the language of your choice. In the Row template section, you can choose which columns to generate from each row by calling them with [variables](expressions#variables). + +This can be used to: +* output [reconciliation data](expressions#reconciliation), such as `cells["ColumnName"].recon.match.name` +* create multiple columns of output from different [member fields](expressions#variables) of a single project column +* employ [expressions](expressions) to modify data for output: for example, `cells["ColumnName"].value.toUppercase()`. + +Anything that appears inside doubled curly braces ({{ }}) is treated as a GREL expression; anything outside is generated as straight text. You can use Jython or Clojure by declaring it at the start: +``` +{{jython:return cells["ColumnName"].value}} +``` + +:::caution +Note that some syntax is different in this tool than elsewhere in OpenRefine: a forward slash must be escaped with a backslash, while other characters do not need escaping. You cannot, at this time, include a closing curly brace (}) anywhere in your expression, or it will cause it to malfunction. +::: + +You can include [regular expressions](expressions#regular-expressions) as usual (inside forward slashes, with any GREL function that accepts them). For example, you could output a version of your cells with punctuation removed, using an expression such as +``` +{{jsonize(cells["ColumnName"].value.replaceChars("/[.!?$&,/]/",""))}} +``` + +You could also simply output a plain-text document inserting data from your project into sentences: for example, "In `{{cells["Year"].value}}` we received `{{cells["RequestCount"].value}}` requests." + +You can use the shorthand `${ColumnName}` (no need for quotes) to insert column values directly. You cannot use this inside an expression, because of the closing curly brace. + +If your projects is in records mode, the Row separator field will insert a separator between records, rather than individual rows. Rows inside a single record will be directly appended to one another as per the content in the Row Template field. + +Once you have created your template, you may wish to save the text you produced in each field, in order to reuse it in the future. Once you click Export OpenRefine will output a simple `.txt` file, and your template will be discarded. + +We have recipes on using the Templating exporter to [produce several different formats](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#12-templating-exporter). + +## Export a project {#export-a-project} + +You can share a project in progress with another computer, a colleague, or with someone who wants to check your history. This can be useful for showing that your data cleanup didn’t distort or manipulate the information in any way. Once you have exported a project, another OpenRefine installation can [import it as a new project](starting#import-a-project). + +You can either save it locally or upload it to Google Drive (which requires you to authorize a Google account). + +:::caution +OpenRefine project archives contain confidential data from previous steps, which will still be accessible to anyone who has the archive. If you are hoping to keep your original dataset hidden for privacy reasons, such as using OpenRefine to anonymize information, do not share your project archive. +::: + +To save your project archive locally: from the Export dropdown, select OpenRefine project archive to file. OpenRefine exports your full project with all of its history. It does not export any current views or applied facets. Existing reconciliation information will be preserved, but the importing computer will need to add the same reconciliation services to keep working with that data. + +OpenRefine exports files in `.tar.gz` format. You can rename the file when you save it; otherwise it will bear the project name. + +To save your project archive to Google Drive: from the Export dropdown, select OpenRefine project archive to Google Drive.... OpenRefine will not share the link with you, only confirm that the file was uploaded. + +## Export operations {#export-operations} + +You can [save and re-apply the history of any project](running#reusing-operations) (all the operations shown in the Undo/Redo tab). This creates JSON that you can save for later reuse on another OpenRefine project. diff --git a/OpenRefine/docs/docs/manual/expressions.md b/OpenRefine/docs/docs/manual/expressions.md new file mode 100644 index 000000000..d10420378 --- /dev/null +++ b/OpenRefine/docs/docs/manual/expressions.md @@ -0,0 +1,208 @@ +--- +id: expressions +title: Expressions +sidebar_label: Overview +--- + +## Overview {#overview} + +You can use expressions in multiple places in OpenRefine to extend data cleanup and transformation. Expressions are available with the following functions: +* Facet: + + * Custom text facet... + * Custom numeric facet… + * Customized facets (click “change†after they have been created to bring up an expressions window) +* Edit cells: + + * Transform… + * Split multi-valued cells… + * Join multi-valued cells… +* Edit column: + + * Split + * Join + * Add column based on this column + * Add column by fetching URLs. + +In the expressions editor window you have the opportunity to select a supported language. The default is [GREL (General Refine Expression Language)](grel); OpenRefine also comes with support for [Clojure](jythonclojure#clojure) and [Jython](jythonclojure#jython). Extensions may offer support for more expressions languages. + +These languages have some syntax differences but support many of the same [variables](#variables). For example, the GREL expression `value.split(" ")[1]` would be written in Jython as `return value.split(" ")[1]`. + +This page is a general reference for available functions, variables, and syntax. For examples that use these expressions for common data tasks, look at the [Recipes section on the wiki](https://github.com/OpenRefine/OpenRefine/wiki/Documentation-For-Users#recipes-and-worked-examples). + +## Expressions {#expressions} + +There are significant differences between OpenRefine's expressions and the spreadsheet formulas you may be used to using for data manipulation. OpenRefine does not store formulas in cells and display output dynamically: OpenRefine’s transformations are one-time operations that can change column contents or generate new columns. These are applied using variables such as `value` or `cell` to perform the same modification to each cell in a column. + +Take the following example: + +|ID|Friend|Age| +|---|---|---| +|1.|John Smith|28| +|2.|Jane Doe|33| + +Were you to apply a transformation to the “friend†column with the expression + +``` + value.split(" ")[1] +``` + +OpenRefine would work through each row, splitting the “friend†values based on a space character. The `value` for row 1 is “John Smith†so the output would be “Smith†(as "[1]" selects the second part of the created output); the `value` for row 2 is “Jane Doe†so the output would be “Doeâ€. Using variables, a single expression yields different results for different rows. The old information would be discarded; you couldn't get "John" and "Jane" back unless you undid the operation in the [History](running#history-undoredo) tab. + +For another example, if you were to create a new column based on your data using the expression `row.starred`, it would generate a column of true and false values based on whether your rows were starred at that moment. If you were to then star more rows and unstar some rows, that data would not dynamically update - you would need to run the operation again to have current true/false values. + +Note that an expression is typically based on one particular column in the data - the column whose drop-down menu is first selected. Many variables are created to stand for things about the cell in that “base column†of the current row on which the expression is evaluated. There are also variables about rows, which you can use to access cells in other columns. + +## The expressions editor {#the-expressions-editor} + +When you select a function that accepts expressions, you will see a window overlay the screen with what we call the expressions editor. + +![The expressions editor window with a simple expression: value + 10.](/img/expression-editor.png) + +The expressions editor offers you a field for entering your formula and shows you a preview of its transformation on your first few rows of cells. + +There is a dropdown menu from which you can choose an expression language. The default at first is GREL; if you begin working with another language, that selection will persist across OpenRefine. Jython and Clojure are also offered with the installation package, and you may be able to add more language support with third-party extensions and customizations. + +There are also tabs for: +* History, which shows you formulas you’ve recently used from across all your projects +* Starred, which shows you formulas from your History that you’ve starred for reuse +* Help, a quick reference to GREL functions. + +Starring formulas you’ve used in the past can be helpful for repetitive tasks you’re performing in batches. + +You can also choose how formula errors are handled: replicate the original cell value, output an error message into the cell, or ouput a blank cell. + +## Regular expressions {#regular-expressions} + +OpenRefine offers several fields that support the use of regular expressions (regex), such as in a Text filter or a Replace… operation. GREL and other expressions can also use regular expression markup to extend their functionality. + +If this is your first time working with regex, you may wish to read [this tutorial specific to the Java syntax that OpenRefine supports](https://docs.oracle.com/javase/tutorial/essential/regex/). We also recommend this [testing and learning tool](https://regexr.com/). + +### GREL-supported regex {#grel-supported-regex} + +To write a regular expression inside a GREL expression, wrap it between a pair of forward slashes (/) much like the way you would in Javascript. For example, in + +``` +value.replace(/\s+/, " ") +``` + +the regular expression is `\s+`, and the syntax used in the expression wraps it with forward slashes (`/\s+/`). Though the regular expression syntax in OpenRefine follows that of Java (normally in Java, you would write regex as a string and escape it like "\\s+"), a regular expression within a GREL expression is similar to Javascript. + +Do not use slashes to wrap regular expressions outside of a GREL expression. + +On the [GREL functions](grelfunctions) page, functions that support regex will indicate that with a “p†for “pattern.†The GREL functions that support regex are: +* [contains](grelfunctions#containss-sub-or-p) +* [replace](grelfunctions#find-and-replace) +* [find](grelfunctions#find-and-replace) +* [match](grelfunctions#matchs-p) +* [partition](grelfunctions#partitions-s-or-p-fragment-b-omitfragment-optional) +* [rpartition](grelfunctions#rpartitions-s-or-p-fragment-b-omitfragment-optional) +* [split](grelfunctions#splits-s-or-p-sep-b-preservetokens-optional) +* [smartSplit](grelfunctions#smartsplits-s-or-p-sep-optional) + +### Jython-supported regex {#jython-supported-regex} + +You can also use [regex with Jython expressions](http://www.jython.org/docs/library/re.html), instead of GREL, for example with a Custom Text Facet: + +``` +python import re g = re.search(ur"\u2014 (.*),\s*BWV", value) return g.group(1) +``` + +### Clojure-supported regex {#clojure-supported-regex} + +[Clojure](https://clojure.org/reference/reader) uses the same regex engine as Java, and can be invoked with [re-find](http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/re-find), [re-matches](http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/re-matches), etc. You can use the #"pattern" reader macro as described [in the Clojure documentation](https://clojure.org/reference/other_functions#regex). For example, to get the nth element of a returned sequence, you can use the nth function: + +``` +clojure (nth (re-find #"\u2014 (.*),\s*BWV" value) 1) +``` + +## Variables {#variables} + +Most OpenRefine variables have attributes: aspects of the variables that can be called separately. We call these attributes “member fields†because they belong to certain variables. For example, you can query a record to find out how many rows it contains with `row.record.rowCount`: `rowCount` is a member field specific to the `record` variable, which is a member field of `row`. Member fields can be called using a dot separator, or with square brackets (`row["record"]`). The square bracket syntax is also used for variables that can call columns by name, for example, `cells["Postal Code"]`. + +|Variable |Meaning | +|-|-| +| `value` | The value of the cell in the current column of the current row (can be null) | +| `row` | The current row | +| `row.record` | One or more rows grouped together to form a record | +| `cells` | The cells of the current row, with fields that correspond to the column names (or row.cells) | +| `cell` | The cell in the current column of the current row, containing value and other attributes | +| `cell.recon` | The cell's reconciliation information returned from a reconciliation service or provider | +| `rowIndex` | The index value of the current row (the first row is 0) | +| `columnName` | The name of the current cell's column, as a string | + +### Row {#row} + +The `row` variable itself is best used to access its member fields, which you can do using either a dot operator or square brackets: `row.index` or `row["index"]`. + +|Field |Meaning | +|-|-| +| `row.index` | The index value of the current row (the first row is 0) | +| `row.cells` | The cells of the row, returned as an array | +| `row.columnNames` | An array of the column names of the project. This will report all columns, even those with null cell values in that particular row. Call a column by number with `row.columnNames[3]` | +| `row.starred` | A boolean indicating if the row is starred | +| `row.flagged` | A boolean indicating if the row is flagged | +| `row.record` | The [record](#record) object containing the current row | + +For array objects such as `row.columnNames` you can preview the array using the expressions window, and output it as a string using `toString(row.columnNames)` or with something like: + +``` +forEach(row.columnNames,v,v).join("; ") +``` + +### Cells {#cells} + +The `cells` object is used to call information from the columns in your project. For example, `cells.Foo` returns a [cell](#cell) object representing the cell in the column named “Foo†of the current row. If the column name has spaces, use square brackets, e.g., `cells["Postal Code"]`. To get the corresponding column's value inside the `cells` variable, use `.value` at the end, for example, `cells["Postal Code"].value`. There is no `cells.value` - it can only be used with member fields. + +### Cell {#cell} + +A `cell` object contains all the data of a cell and is stored as a single object. + +You can use `cell` on its own in the expressions editor to copy all the contents of a column to another column, including reconciliation information. Although the preview in the expressions editor will only show a small representation (“[object Cell]â€), it will actually copy all the cell's data. Try this with Edit Column → Add Column based on this column .... + +|Field |Meaning |Member fields | +|-|-|-| +| `cell` | An object containing the entire contents of the cell | .value, .recon, .errorMessage | +| `cell.value` | The value in the cell, which can be a string, a number, a boolean, null, or an error | | +| `cell.recon` | An object encapsulating reconciliation results for that cell | See the [reconciliation](expressions#reconciliation) section | +| `cell.errorMessage` | Returns the message of an *EvalError* instead of the error object itself (use value to return the error object) | .value | + +### Reconciliation {#reconciliation} + +Several of the fields here provide the data used in [reconciliation facets](reconciling#reconciliation-facets). You must type `cell.recon`; `recon` on its own will not work. + +|Field|Meaning |Member fields | +|-|-|-| +| `cell.recon.judgment` | A string: either “matchedâ€, "newâ€, "none†| | +| `cell.recon.judgmentAction` | A string: either "single†or “similar†(or “unknownâ€) | | +| `cell.recon.judgmentHistory` | A number, the epoch timestamp (in milliseconds) of your judgment | | +| `cell.recon.matched` | A boolean, true if judgment is “matched†| | +| `cell.recon.match` | The recon candidate that has been matched against this cell (or null) | .id, .name, .type | +| `cell.recon.best` | The highest scoring recon candidate from the reconciliation service (or null) | .id, .name, .type, .score | +| `cell.recon.features` | An array of reconciliation features to help you assess the accuracy of your matches | .typeMatch, .nameMatch, .nameLevenshtein, .nameWordDistance | +| `cell.recon.features.typeMatch` | A boolean, true if your chosen type is “matched†and false if not (or “(no type)†if unreconciled) | | +| `cell.recon.features.nameMatch` | A boolean, true if the cell and candidate strings are identical and false if not (or “(unreconciled)â€) | | +| `cell.recon.features.nameLevenshtein` | A number representing the [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance): larger if the difference is greater between value and candidate | | +| `cell.recon.features.nameWordDistance` | A number based on the [word similarity](reconciling#reconciliation-facets) | | +| `cell.recon.candidates` | An array of the top 3 candidates (default) | .id, .name, .type, .score | + +The `cell.recon.candidates` and `cell.recon.best` objects have a few deeper fields: `id`, `name`, `type`, and `score`. `type` is an array of type identifiers for a list of candidates, or a single string for the best candidate. + +Arrays such as `cell.recon.candidates` and `cell.recon.candidates.type` can be joined into lists and stored as strings with something like: +``` +forEach(cell.recon.candidates,v,v.name).join("; ") +``` + +### Record {#record} + +A `row.record` object encapsulates one or more rows that are grouped together, when your project is in records mode. You must call it as `row.record`; `record` will not return values. + +|Field|Meaning | +|-|-| +| `row.record.index` | The index of the current record (starting at 0) | +| `row.record.cells` | An array of the [cells](#cells) in the given column of the record | +| `row.record.fromRowIndex` | The row index of the first row in the record | +| `row.record.toRowIndex` | The row index of the last row in the record + 1 (i.e. the next record) | +| `row.record.rowCount` | A count of the number of rows in the record | + +For example, you can facet by number of rows in each record by creating a Custom Numeric Facet (or a Custom Text Facet) and entering `row.record.rowCount`. \ No newline at end of file diff --git a/OpenRefine/docs/docs/manual/facets.md b/OpenRefine/docs/docs/manual/facets.md new file mode 100644 index 000000000..06e54b751 --- /dev/null +++ b/OpenRefine/docs/docs/manual/facets.md @@ -0,0 +1,329 @@ +--- +id: facets +title: Exploring facets +sidebar_label: Facets +--- + +## Overview {#overview} + +Facets are one of OpenRefine’s strongest features - that’s where the diamond logo comes from! + +Faceting allows you to look for patterns and trends. Facets are essentially aspects or angles of data variance in a given column. For example, if you had survey data where respondents indicated one of five responses from “Strongly agree†to “Strongly disagree,†those five responses make up a text facet, showing how many people selected each option. + +Faceted browsing gives you a big-picture look at your data (do they agree or disagree?) and also allows you to filter down to a specific subset to explore it more (what do people who disagree say in other responses?). + +Typically, you create a facet on a particular column. That facet selection appears on the left, in the Facet/Filter tab, and you can click on a displayed facet to view all the records that match. You can also “exclude†the facet, to view every record that does _not_ match, and you can select more than one facet by clicking “include.†+ + +### An example {#an-example} + +You can learn about facets and filtering with the following example. You can copy the following table and paste it using the Clipboard method of starting a project if you would like to try it yourself. + +We collected a list of the [10 most populous cities from Wikidata](https://w.wiki/3Em), using an example query of theirs. We removed the GPS coordinates and added the country. + +| cityLabel | population | countryLabel | +|-|-|-| +| Shanghai | 23390000 | People's Republic of China | +| Beijing | 21710000 | People's Republic of China | +| Lagos | 21324000 | Nigeria | +| Dhaka | 16800000 | Bangladesh | +| Mumbai | 15414288 | India | +| Istanbul | 14657434 | Turkey | +| Tokyo | 13942856 | Japan | +| Tianjin | 13245000 | People's Republic of China | +| Guangzhou | 13080500 | People's Republic of China | +| São Paulo | 12106920 | Brazil | + +If we want to see which countries have the most populous cities, we can create a text facet on the “countryLabel†column and OpenRefine will generate a list of all the different strings used in these cells. + +We will see in the sidebar that the countries identified are displayed, along with the number of matches (the “countâ€). We can sort this list alphabetically or by the count. If you sort by count at the top of the facet window, you’ll learn which countries hold the most populous cities. + +|Facet|Count| +|---|---| +|People's Republic of China|4| +|Bangladesh|1| +|Brazil|1| +|India|1| +|Japan|1| +|Nigeria|1| +|Turkey|1| + +If we want to learn more about a particular country, we can click on its appearance in the facet sidebar. This narrows our dataset down temporarily to only rows matching that facet. + +You’ll see the “10 rows†indicator change to “4 matching rows (10 total)†if you click on “People’s Republic of Chinaâ€. In the data grid, you’ll see fewer rows: only the ones matching your current filter. Each row will maintain its original numbering, though - in this case, rows #1, 2, and 8. + +If you want to go back to the original dataset, click Reset All or the small “exclude†text next to the facet. If you want to view the most populous cities in both China and India, click “include†next to each facet. Now you’ll see 5 rows - #1, 2, 5, 8, 9. + +We can also explore our data using the population information. In this case, because population is a number, we can create a numeric facet. This will give us the ability to explore by range rather than by exact matching values. + +With the numeric facet, we are given a scale from the smallest to the largest value in the column. We can drag the range minimum and maximum to narrow the results. In this case, if we narrow down to only cities with more than 20 million in population, we get 3 matching rows out of the original 10. + +When you look back at the text facet display of country names, you should see a smaller list with a reduced count: OpenRefine is now displaying the facets of the 3 matching rows, not the total dataset of 10 rows. + +We can combine these facets - say, by narrowing to only the Chinese cities with populations greater than 20 million - simply by clicking in both. You should see 2 matching rows for both these criteria. + +### Things to know about facets {#things-to-know-about-facets} + +When you have facets applied, you will see “matching rows†in the [project grid header](running#project-grid-header). If you click Export and copy your data out of OpenRefine while facets are active, many of the exporting options will only export the matching rows, not all the rows in your project. + +OpenRefine has several default facets, which you’ll learn about below. The most powerful facets are the ones designed by you - custom facets, written using [expressions](expressions) to transform the data behind the scenes and help you narrow down to precisely what you’re looking for. + +Facets are not saved in the project along with the data. But you can save a link to the current state of the application. Find the [Permalink](running#the-project-bar) next to the project’s name. + +You can modify any facet expression by clicking the “change†button to the right of the column name in the facet sidebar. + +Facet boxes that appear in the sidebar can be resized and rearranged. You can drag and drop the title bar of each box to reorder them, and drag on the bottom bar of text facet boxes. + +## Text facet {#text-facet} + +A text facet can be generated on any column with the “text†data type. Select the column dropdown and go to Facet → Text facet. The created facet will be sorted alphabetically, and can be sorted by count. + +A text facet is very simple: it takes the total contents of the cells of the column in question and matches them up. It does no guessing about typos or near-matches. + +You can edit any entry that appears in the facet display, by hovering over the facet and clicking the “edit†button that appears. You can then type in a new value manually. This will mass-edit every identical cell in the column. This is a great way to fix typos, whitespace, and other issues that may be affecting the way facets appear. You can also automate the cleanup of facets by using [clustering](transforming#cluster-and-edit): a “Cluster†button is displayed within the facet window. It may be most efficient to cluster cells to one value, and then mass-edit that value to your desired string within the clustering operation window. + +Each text facet shows up to 2,000 choices by default. You can [increase this limit on the Preferences screen](running#preferences) if you need to, which may slow down your browser. If your applied facet has more choices than the current limit, you'll be offered the option to increase the limit, which will permanently edit that preference for you. + +The choices and counts displayed in each facet can be copied as tab-separated values. To do so, click on the "X choices" link near the top left corner of the facet. This can be useful to generate small summary tables of your data. + +![A column of years faceted as text and numbers, and with the count ready to be copied.](/img/yeardata.png) + +## Numeric facet {#numeric-facet} + +![A screenshot of an example numeric facet.](/img/numericfacet.png) + +Whereas a text facet groups unique text values into groups, a numeric facet sorts numbers by their range - smallest to biggest. This displays visually as a histogram, and allows you to set a custom facet within that range. You can drag the minimum and maximum range markers to set a range. OpenRefine snaps to some basic equal-sized divisions - 19 in the example set above. + +You will be offered the option to include blank, non-numeric, and error values in your numeric visualization; these will appear in the visual range as “0†values. + +:::info Numbers as text +You can create a text facet on numeric data, which will treat each entry as a string. This can be useful if you wish, for example, to manually include facets instead of selecting a range, or sort by count, or copy that count. +::: + +:::info Faceting customization +As mentioned in the overview, facets can be modified or customized by GREL [expressions](expressions) in many ways. For example, to facet by clusters of [row](expressions#variables) numbers with `row.index/100` or better visualizing numbers greater than 1000 with `max(row.index, 1000)`. +::: + +## Timeline facet {#timeline-facet} + +![A screenshot of an example timeline facet.](/img/timelinefacet.png) + +Much like a numeric facet, a timeline facet will display as a small histogram with the values sorted: in this case, chronologically. A timeline facet only works on cells formatted as the [“date†data type](exploring#dates). + +The facet appears with a count of blank cells and those with errors, which can help you analyze whether your date cells are correctly converted. + +## Scatterplot facet {#scatterplot-facet} + +A scatterplot is a visual representation of two related sets of numeric data. + +You have the option to generate linear scatterplots (where the X and Y axes show continuous increases) or logarithmic scatterplots (where the X and Y axes show exponential or scaled increases). You can also rotate the plot by 45 degrees in either direction, and you can choose the size of the dot indicating a datapoint. You can make these choices in both the preview and in the facet display. + +A scatterplot facet can be generated on any column. You require two or more number columns to generate scatterplots. Selecting Facet → Scatterplot facet will create a preview of data plotted from every number-formatted column in your dataset, comparing every column against every other column. Each scatterplot will show in its own square, allowing you to choose which data comparison you would like to analyze further. You can control which columns are on the X and Y axes by rearranging the columns in your dataset. + +![A simple scatterplot of two numeric values.](/img/scatterplot.png) + +When you click on your desired square, that two-column comparison will appear in the facets sidebar. From here, you can drag your mouse to draw a rectangle inside the scatterplot, which will narrow down to just the rows matching the points plotted inside that rectangle (as shown by the rectangle inside the square in the image above). This rectangle can be resized by dragging any of the four edges. To draw a new rectangle, simply click and drag your mouse again. To add more scatterplots to the facet sidebar, re-run this process and select a different square. + +If you have multiple facets applied, plotted points in your scatterplot displays will be greyed out if they are not part of the current matching data subset. If the rectangle you have drawn within a scatterplot display only includes grey dots, you will see no matching rows. + +If you would like to export a scatterplot, OpenRefine will open a new tab with a generated PNG file that you can save. + +## Custom text facet {#custom-text-facet} + +You may want to explore your textual data with modifications that aren't permanent. Creating custom text facets will load your column into memory, transform the data temporarily, and store those transformations inside the facet. + +You can also use custom text facets to analyze numerical data, such as by analyzing a number as a string, or by creating a test that will return “true†and “false†as values. + +Clicking on Facet → Custom text facet… will bring up an [expressions](expressions) window where you can enter in a GREL, Jython, or Clojure expression to modify how the facet works. + +A custom text facet operates just like a [text facet](#text-facet) by default. Unlike a text facet, however, you cannot click “edit†on the facets that appear in the sidebar and change the matching cells in your dataset - because what they display is modified, not the original entries. + +For example, you may wish to analyze only the first word in a text field - perhaps the first name in a column of “[First Name] [Last Name]†entries. In this case, you can tell OpenRefine to facet only on the information that comes before the first space: + +``` +value.split(" ")[0] +``` + +In this case, `split()` is creating an array of text strings based on every space in the cells ["Firstname", "Lastname"]. Because arrays number their entries starting with 0, we want the first value, so we ask for `[0]`. (Assuming the first name is one word, not something like “Mary Anne.â€) We can do the same splitting and ask for the last name with + +``` +value.split(" ")[1] +``` + +You may want to create a facet that references several columns. For example, let’s say you have two columns, “First Name†and “Last Nameâ€, and you want out how many people have the same initial letter for both names (e.g., Marilyn Monroe, Steven Segal). To do so, create a custom text facet on either column and enter the expression + +``` +cells["First Name"].value[0] == cells["Last Name"].value[0] +``` + +That expression will look for the first letter (the character at index 0) of each entry and compare them. Then it will facet your rows into “true†and “false.†+ +You can learn more about text-modification functions on the [Expressions page](expressions). + +## Custom numeric facet {#custom-numeric-facet} + +You may want to explore your numerical data with modifications that aren't permanent. You can also use custom numeric facets to analyze textual data, such as by getting the length of text strings (with `value.length()`), or by analyzing it as though it were formatted as numbers (with `toNumber(value)`). + +If you would like to build your own version of a numeric facet, you can use the Custom Numeric Facet option. Clicking on Facet → Custom Numeric Facet… will bring up an [expressions](expressions) window where you can enter in a GREL, Jython, or Clojure expression to modify how the facet works. A custom numeric facet operates just like a [numeric facet](#numeric-facet) by default. + +For example, you may wish to create a numeric facet that rounds your value to the nearest integer, enter + +``` +round(value) +``` + +If you have two columns of numbers and for each row you wish to create a numeric facet only on the larger of the two, enter + +``` +max(cells["Column1"].value, cells["Column2"].value) +``` + +If the numeric values in a column are drawn from a power law distribution, then it's better to group them by their logs: + +``` +value.log() +``` + +If the values are periodic you could take the modulus by the period to understand if there's a pattern: + +``` +mod(value, 7) +``` + +You can learn more about numeric-modification functions on the [Expressions page](expressions). + +## Customized facets {#customized-facets} + +Customized facets have been added to expand the number of default facets users can apply with a single click. They represent some common and useful functions you shouldn’t have to work out using an [expression](expressions). + +All facets that display in the Facet/Filter tab can be edited by clicking on the “change†button to the right of the column title. This brings up the expressions window that will allow you to modify and preview the expression being used. + +### Word facet {#word-facet} + +A Word facet is a simple version of a text facet: it splits up the content of the cells based on spaces, and outputs each character string as a facet: + +``` +value.split(" ") +``` + +This can be useful for exploring the language used in a corpus, looking for common first and last names or titles, or seeing what’s in multi-valued cells you don’t wish to split up. + +Word facet is case-sensitive and only splits by spaces, not by line breaks or other natural divisions. + +### Duplicates facet {#duplicates-facet} + +A Duplicates facet will return only rows that have non-unique values in the column you’ve selected. It will create a facet of “true†and “false†values - true being cells that are not unique, and “false†being cells that are. The actual expression being used is + +``` +facetCount(value, 'value', '[Column]') > 1 +``` + +Duplicates facets are case-sensitive and you may wish to filter out things like leading and trailing whitespace or other hard-to-see issues. You can modify the facet expression, for example, with: + +``` +facetCount(trim(toLowercase(value)), 'trim(toLowercase(value))', 'cityLabel') > 1 +``` + +### Numeric log facet {#numeric-log-facet} + +Logarithmic scales reduce wide-ranging quantities to more compact and manageable ranges. A log transformation can be used to make highly skewed distributions less skewed. If your numerical data is unevenly distributed (say, lots of values in one range, and then a long tail extending off into different magnitudes), a Numeric log facet can represent that range better than a simple numeric facet. It will break these values down into more navigable segments than the buckets of a numeric facet. This facet can make patterns in your data more visible. OpenRefine uses a base-10 log, the “common logarithm.†+ +For example, we can look at [this data about the body weight of various mammals](http://wiki.stat.ucla.edu/socr/index.php/SOCR_Data_Brain2BodyWeight): + +|Species|BodyWeight (kg)| +|---|---| +| Newborn_Human | 3.2 | +| Adult_Human | 73 | +| Pithecanthropus_Man | 70 | +| Squirrel | 0.8 | +| Hamster | 0.15 | +| Chimpanzee | 50 | +| Rabbit | 1.4 | +| Dog_(Beagle) | 10 | +| Cat | 4.5 | +| Rat | 0.4 | +| Sperm_Whale | 35000 | +| Turtle | 3 | +| Alligator | 270 | + +Most values will be clustered in the 0-100 range, but 35,000 is many magnitudes above that. A numeric facet will create 36 equal buckets of 1,000 each - containing almost all the cells in the first bucket. A numeric log facet will instead display the data more evenly across the visual range. + +![A screenshot of a numeric facet first and a numeric log facet second.](/img/numericlogfacet.png) + +A 1-bounded numeric log facet can be used if you'd like to exclude all the values below 1 (including zero and negative numbers). + +### Text-length facet {#text-length-facet} + +The Text-length facet returns a numerical value for each cell and plots it on a numeric facet chart. The expression used is + +``` +value.length() +``` + +This can be useful to, for example, look for values that did not successfully split on an earlier split operation, or to validate that data is a certain expected length (such as whether a date in YYYY/MM/DD is eight to ten characters). + +You can also employ a Log of text-length facet that allows you to navigate more easily a wide range of string lengths. This can be useful in the case of web-scraping, where lots of textual data is loaded into single cells and needs to be parsed out. + + +### Unicode character-code facet {#unicode-character-code-facet} + +![A screenshot of the Unicode facet.](/img/unicodefacet.png) + +The Unicode facet identifies and returns [Unicode decimal values](https://en.wikipedia.org/wiki/List_of_Unicode_characters). It generates a list of the Unicode numerical values of each character used in each text cell, which allows you to narrow down and search for special characters, punctuation, and other data formatting issues. + +This facet creates a numerical chart, which offers you the ability to narrow down to a range of numbers. For example, lowercase characters are numbers 97-122, uppercase characters are numbers 65-90, and numerical digits are numbers 48-57. + +### Facet by error {#facet-by-error} + +An error is a data type created by OpenRefine in the process of transforming data. For example, say you had converted a column to the number data type. If one cell had text characters in it, OpenRefine could either output the original text string unchanged or output an error. If you allow errors to be created, you can facet by them later to search for them and fix them. + +![A view of the expressions window with an error converting a string to a number.](/img/error.png) + +To store errors in cells, ensure that you have store error selected for the “On error†option in the expressions window. + +### Facet by null, empty, or blank {#facet-by-null-empty-or-blank} + +Any column can be faceted for [null and/or empty cells](#cell-data-types). These can help you find cells where you want to manually enter content. + +“Blank†means both null values and empty values. All three facets will generate “true†and “false†facets, “true†being blank. + +An empty cell is a cell that is set to contain a string, but doesn’t have any characters in it (a zero-length string). This can be left over from an operation that removed characters, or from manually editing a cell and deleting its contents. + +### Facet by star or flag {#facet-by-star-or-flag} + +Stars and flags offer you the opportunity to mark specific rows for yourself for later focus. Stars and flags persist through closing and opening your project, and thus can provide a different function than using a permalink to persist your facets. Stars and flags can be used in any way you want, although they are designed to help you flag errors and star rows of particular importance. + +You can manually star or flag rows simply by clicking on the icons to the left of each row. + +You can also apply stars or flags to all matching rows by using the All dropdown menu (on the first column) and selecting Edit rows → Star rows or Flag rows. This will create “true†and “false†facets in the Facet/Filter. These operations will modify all matching rows in your current subset. You can unstar or unflag them as well. + +You may wish to create a custom subset of your data through a series of separate faceting activities (rather than successively narrowing down with multiple facets applied). For example, you may wish to: +* apply a facet +* star all the matching rows +* remove that facet +* apply another, unrelated facet +* star all the new matching rows (which will not modify already-starred rows) +* remove that facet +* and then work with all of the cumulative starred rows. + +You can also create a text facet on any column with the expression `row.starred` or `row.flagged`. + +## Text filter {#text-filter} + +Filters allow you to narrow down your data based on whether a given column includes a text string. + +When you choose Text filter a box appears in the Facet/Filter tab that allows you to enter in text. Matching rows will narrow dynamically with every character you enter. You can set the search to be case-sensitive or not, and you can use this box to enter in a regular expression. + +For example, you can enter in “side†as a text filter, and it will return all cells in that column containing “side,†“sideways,†“offside,†etc. + +The text filter field supports [regular expressions](expressions#regular-expressions). For example, you can employ a regular expression to view all properly-formatted emails: + +``` +([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9\-\.]+)\.([a-zA-Z0-9\-]{2,15}) +``` + +You can press “invert†on this facet to then see blank cells or invalid email addresses. + +This filter works differently than facets because it is always active as long as it appears in the sidebar. If you “reset†it, you will delete all the text or expression you have entered. + +You can apply multiple text filters in succession, which will successively narrow your data subset. This can be useful if you apply multiple inverted filters, such as to filter out all rows that respond “yes†or “maybe†and only look at the remaining responses. diff --git a/OpenRefine/docs/docs/manual/grel.md b/OpenRefine/docs/docs/manual/grel.md new file mode 100644 index 000000000..7ec90b464 --- /dev/null +++ b/OpenRefine/docs/docs/manual/grel.md @@ -0,0 +1,154 @@ +--- +id: grel +title: General Refine Expression Language +sidebar_label: General Refine Expression Language +--- + +## Basics {#basics} + +GREL (General Refine Expression Language) is designed to resemble Javascript. Formulas use variables and depend on data types to do things like string manipulation or mathematical calculations: + +|Example|Output| +|---|---| +| `value + " (approved)"` | Concatenate two strings; whatever is in the cell gets converted to a string first | +| `value + 2.239` | Add 2.239 to the existing value (if a number); append text "2.239" to the end of the string otherwise | +| `value.trim().length()`     | Trim leading and trailing whitespace of the cell value and then output the length of the result | +| `value.substring(7, 10)` | Output the substring of the value from character index 7, 8, and 9 (excluding character index 10) | +| `value.substring(13)` | Output the substring from index 13 to the end of the string | + +Note that the operator for string concatenation is `+` (not “&†as is used in Excel). + +Evaluating conditions uses symbols such as <, >, *, /, etc. To check whether two objects are equal, use two equal signs (`value=="true"`). + +See the [GREL functions page for a thorough reference](grelfunctions) on each function and its inputs and outputs. Read on below for more about the general nature of GREL expressions. + +## Syntax {#syntax} + +In GREL, functions can use either of these two forms: +* functionName(arg0, arg1, ...) +* arg0.functionName(arg1, ...) + +The second form is a shorthand to make expressions easier to read. It simply pulls the first argument out and appends it to the front of the function, with a dot: + +|Dot notation |Full notation | +|-|-| +| `value.trim().length()` | `length(trim(value))` | +| `value.substring(7, 10)` | `substring(value, 7, 10)` | + +So, in the dot shorthand, the functions occur from left to right in the order of calling, rather than in the reverse order with parentheses. This allows you to string together multiple functions in a readable order. + +The dot notation can also be used to access the member fields of [variables](expressions#variables). For referring to column names that contain spaces (anything not a continuous string), use square brackets instead of dot notation: + +|Example |Description | +|-|-| +| `FirstName.cells` | Access the cell in the column named “FirstName†of the current row | +| `cells["First Name"]` | Access the cell in the column called “First Name†of the current row | + +Square brackets can also be used to get substrings and sub-arrays, and single items from arrays: + +|Example |Description | +|-|-| +| `value[1,3]` | A substring of value, starting from character 1 up to but excluding character 3 | +| `"internationalization"[1,-2]` | Will return “nternationalizati†(negative indexes are counted from the end) | +| `row.columnNames[5]` | Will return the name of the fifth column | + +Any function that outputs an array can use square brackets to select only one part of the array to output as a string (remember that the index of the items in an array starts with 0). + +For example, [partition()](grelfunctions#partitions-s-or-p-fragment-b-omitfragment-optional) would normally output an array of three items: the part before your chosen fragment, the fragment you've identified, and the part after. Selecting only the third part with `"internationalization".partition("nation")[2]` will output “alization†(and so will [-1], indicating the final item in the array). + +## Controls {#controls} + +GREL offers controls to support branching and looping (that is, “if†and “for†functions), but unlike functions, their arguments don't all get evaluated before they get run. A control can decide which part of the code to execute and can affect the environment bindings. Functions, on the other hand, can't do either. Each control decides which of their arguments to evaluate to `value`, and how. + +Please note that the GREL control names are case-sensitive: for example, the isError() control can't be called with iserror(). + +#### if(e, eTrue, eFalse) {#ife-etrue-efalse} + +Expression e is evaluated to a value. If that value is true, then expression eTrue is evaluated and the result is the value of the whole if() expression. Otherwise, expression eFalse is evaluated and that result is the value. + +Examples: + +| Example expression | Result | +| ------------------------------------------------------------------------ | ------------ | +| `if("internationalization".length() > 10, "big string", "small string")` | “big string†| +| `if(mod(37, 2) == 0, "even", "odd")` | “odd†| + +Nested if (switch case) example: + + if(value == 'Place', 'http://www.example.com/Location', + + if(value == 'Person', 'http://www.example.com/Agent', + + if(value == 'Book', 'http://www.example.com/Publication', + + null))) + +#### with(e1, variable v, e2) {#withe1-variable-v-e2} + +Evaluates expression e1 and binds its value to variable v. Then evaluates expression e2 and returns that result. + +| Example expression | Result | +| ------------------------------------------------------------------------------------ | ---------- | +| `with("european union".split(" "), a, a.length())` | 2 | +| `with("european union".split(" "), a, forEach(a, v, v.length()))` | [ 8, 5 ] | +| `with("european union".split(" "), a, forEach(a, v, v.length()).sum() / a.length())` | 6.5 | + +#### filter(e1, v, e test) {#filtere1-v-e-test} + +Evaluates expression e1 to an array. Then for each array element, binds its value to variable v, evaluates expression test - which should return a boolean. If the boolean is true, pushes v onto the result array. + +| Expression | Result | +| ---------------------------------------------- | ------------- | +| `filter([ 3, 4, 8, 7, 9 ], v, mod(v, 2) == 1)` | [ 3, 7, 9 ] | + +#### forEach(e1, v, e2) {#foreache1-v-e2} + +Evaluates expression e1 to an array. Then for each array element, binds its value to variable v, evaluates expression e2, and pushes the result onto the result array. When e1 is a JSON object, `forEach` iterates over its keys. + +| Expression | Result | +| ------------------------------------------ | ------------------- | +| `forEach([ 3, 4, 8, 7, 9 ], v, mod(v, 2))` | [ 1, 0, 0, 1, 1 ] | + +#### forEachIndex(e1, i, v, e2) {#foreachindexe1-i-v-e2} + +Evaluates expression e1 to an array. Then for each array element, binds its index to variable i and its value to variable v, evaluates expression e2, and pushes the result onto the result array. + +| Expression | Result | +| ------------------------------------------------------------------------------- | --------------------------- | +| `forEachIndex([ "anne", "ben", "cindy" ], i, v, (i + 1) + ". " + v).join(", ")` | 1. anne, 2. ben, 3. cindy | + +#### forRange(n from, n to, n step, v, e) {#forrangen-from-n-to-n-step-v-e} + +Iterates over the variable v starting at from, incrementing by the value of step each time while less than to. At each iteration, evaluates expression e, and pushes the result onto the result array. + +#### forNonBlank(e, v, eNonBlank, eBlank) {#fornonblanke-v-enonblank-eblank} + +Evaluates expression e. If it is non-blank, forNonBlank() binds its value to variable v, evaluates expression eNonBlank and returns the result. Otherwise (if e evaluates to blank), forNonBlank() evaluates expression eBlank and returns that result instead. + +Unlike other GREL functions beginning with “for,†forNonBlank() is not iterative. forNonBlank() essentially offers a shorter syntax to achieving the same outcome by using the isNonBlank() function within an “if†statement. + +#### isBlank(e), isNonBlank(e), isNull(e), isNotNull(e), isNumeric(e), isError(e) {#isblanke-isnonblanke-isnulle-isnotnulle-isnumerice-iserrore} + +Evaluates the expression e, and returns a boolean based on the named evaluation. + +Examples: + +| Expression | Result | +| ------------------- | ------- | +| `isBlank("abc")` | false | +| `isNonBlank("abc")` | true | +| `isNull("abc")` | false | +| `isNotNull("abc")` | true | +| `isNumeric(2)` | true | +| `isError(1)` | false | +| `isError("abc")` | false | +| `isError(1 / 0)` | true | + +Remember that these are controls and not functions: you can’t use dot notation (for example, the format `e.isX()` will not work). + +## Constants {#constants} +|Name |Meaning | +|-|-| +| true | The boolean constant true | +| false | The boolean constant false | +| PI | From [Java's Math.PI](https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#PI), the value of pi (that is, 3.1415...) | diff --git a/OpenRefine/docs/docs/manual/grelfunctions.md b/OpenRefine/docs/docs/manual/grelfunctions.md new file mode 100644 index 000000000..5e4893851 --- /dev/null +++ b/OpenRefine/docs/docs/manual/grelfunctions.md @@ -0,0 +1,535 @@ +--- +id: grelfunctions +title: GREL functions +sidebar_label: GREL functions +--- + +## Reading this reference {#reading-this-reference} + +For the reference below, the function is given in full-length notation and the in-text examples are written in dot notation. Shorthands are used to indicate the kind of [data type](exploring#data-types) used in each function: s for string, b for boolean, n for number, d for date, a for array, p for a regex pattern, and o for object (meaning any data type), as well as “null†and “error†data types. + +If a function can take more than one kind of data as input or can output more than one kind of data, that is indicated with more than one letter (as with “s or aâ€) or with o for object, meaning it can take any type of data (string, boolean, date, number, etc.). + +We also use shorthands for substring (“subâ€) and separator string (“sepâ€). +Optional arguments will say “(optional)â€. + +In places where OpenRefine will accept a string (s) or a regex pattern (p), you can supply a string by putting it in quotes. If you wish to use any [regex](expressions#regular-expressions) notation, wrap the pattern in forward slashes. + +## Boolean functions {#boolean-functions} + +###### and(b1, b2, ...) {#andb1-b2-} + +Uses the logical operator AND on two or more booleans to output a boolean. Evaluates multiple statements into booleans, then returns true if all of the statements are true. For example, `(1 < 3).and(1 < 0)` returns false because one condition is true and one is false. + +###### or(b1, b2, ...) {#orb1-b2-} + +Uses the logical operator OR on two or more booleans to output a boolean. For example, `(1 < 3).or(1 > 7)` returns true because at least one of the conditions (the first one) is true. + +###### not(b) {#notb} + +Uses the logical operator NOT on a boolean to output a boolean. For example, `not(1 > 7)` returns true because 1 > 7 itself is false. + +###### xor(b1, b2, ...) {#xorb1-b2-} + +Uses the logical operator XOR (exclusive-or) on two or more booleans to output a boolean. Evaluates multiple statements, then returns true if only one of them is true. For example, `(1 < 3).xor(1 < 7)` returns false because more than one of the conditions is true. + +## String functions {#string-functions} + +###### length(s) {#lengths} + +Returns the length of string s as a number. + +###### toString(o, string format (optional)) {#tostringo-string-format-optional} + +Takes any value type (string, number, date, boolean, error, null) and gives a string version of that value. + +You can use toString() to convert numbers to strings with rounding, using an [optional string format](https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html). For example, if you applied the expression `value.toString("%.0f")` to a column: + +|Input|Output| +|-|-| +|3.2|3| +|0.8|1| +|0.15|0| +|100.0|100| + +You can also convert dates to strings, using date parsing syntax built into OpenRefine (see [the toDate() function for details](#todateo-b-monthfirst-s-format1-s-format2-)). For example, `value.toString("MMM-dd-yyyy")` would convert the date value [2024-10-15T00:00:00Z] to “Oct-15-2024â€. + +Note: In OpenRefine, using toString() on a null cell outputs the string “nullâ€. + +### Testing string characteristics {#testing-string-characteristics} + +###### startsWith(s, sub) {#startswiths-sub} + +Returns a boolean indicating whether s starts with sub. For example, `"food".startsWith("foo")` returns true, whereas `"food".startsWith("bar")` returns false. + +###### endsWith(s, sub) {#endswiths-sub} + +Returns a boolean indicating whether s ends with sub. For example, `"food".endsWith("ood")` returns true, whereas `"food".endsWith("odd")` returns false. + +###### contains(s, sub or p) {#containss-sub-or-p} + +Returns a boolean indicating whether s contains sub, which is either a substring or a regex pattern. For example, `"food".contains("oo")` returns true whereas `"food".contains("ee")` returns false. + +You can search for a regular expression by wrapping it in forward slashes rather than quotes: `"rose is a rose".contains(/\s+/)` returns true. startsWith() and endsWith() can only take strings, while contains() can take a regex pattern, so you can use contains() to look for beginning and ending string patterns. + +### Basic string modification {#basic-string-modification} + +#### Case conversion {#case-conversion} + +###### toLowercase(s) {#tolowercases} + +Returns string s converted to all lowercase characters. + +###### toUppercase(s) {#touppercases} + +Returns string s converted to all uppercase characters. + +###### toTitlecase(s) {#totitlecases} + +Returns string s converted into titlecase: a capital letter starting each word, and the rest of the letters lowercase. For example, `"Once upon a midnight DREARY".toTitlecase()` returns the string “Once Upon A Midnight Drearyâ€. + +#### Trimming {#trimming} + +###### trim(s) {#trims} + +Returns a copy of the string s with leading and trailing whitespace removed. For example, `" island ".trim()` returns the string “islandâ€. Identical to strip(). + +###### strip(s) {#strips} + +Returns a copy of the string s with leading and trailing whitespace removed. For example, `" island ".strip()` returns the string “islandâ€. Identical to trim(). + +###### chomp(s, sep) {#chomps-sep} + +Returns a copy of string s with the string sep removed from the end if s ends with sep; otherwise, just returns s. For example, `"barely".chomp("ly")` and `"bare".chomp("ly")` both return the string “bareâ€. + +#### Substring {#substring} + +###### substring(s, n from, n to (optional)) {#substrings-n-from-n-to-optional} + +Returns the substring of s starting from character index from, and up to (excluding) character index to. If the to argument is omitted, substring will output to the end of s. For example, `"profound".substring(3)` returns the string “foundâ€, and `"profound".substring(2, 4)` returns the string “ofâ€. + +Remember that character indices start from zero. A negative character index counts from the end of the string. For example, `"profound".substring(0, -1)` returns the string “profounâ€. + +###### slice(s, n from, n to (optional)) {#slices-n-from-n-to-optional} + +Identical to substring() in relation to strings. Also works with arrays; see [Array functions section](#slicea-n-from-n-to-optional). + +###### get(s, n from, n to (optional)) {#gets-n-from-n-to-optional} + +Identical to substring() in relation to strings. Also works with named fields. Also works with arrays; see [Array functions section](#geta-n-from-n-to-optional). + +#### Find and replace {#find-and-replace} + +###### indexOf(s, sub) {#indexofs-sub} + +Returns the first character index of sub as it first occurs in s; or, returns -1 if s does not contain sub. For example, `"internationalization".indexOf("nation")` returns 5, whereas `"internationalization".indexOf("world")` returns -1. + +###### lastIndexOf(s, sub) {#lastindexofs-sub} + +Returns the first character index of sub as it last occurs in s; or, returns -1 if s does not contain sub. For example, `"parallel".lastIndexOf("a")` returns 3 (pointing at the second “aâ€). + +###### replace(s, s or p find, s replace) {#replaces-s-or-p-find-s-replace} + +Returns the string obtained by replacing the find string with the replace string in the inputted string. For example, `"The cow jumps over the moon and moos".replace("oo", "ee")` returns the string “The cow jumps over the meen and meesâ€. Find can be a regex pattern. For example, `"The cow jumps over the moon and moos".replace(/\s+/, "_")` will return “The_cow_jumps_over_the_moon_and_moosâ€. + +You cannot find or replace nulls with this, as null is not a string. You can instead: + +1. Facet by null and then bulk-edit them to a string, or +2. Transform the column with an expression such as `if(value==null,"new",value)`. + +###### replaceChars(s, s find, s replace) {#replacecharss-s-find-s-replace} + +Returns the string obtained by replacing a character in s, identified by find, with the corresponding character identified in replace. For example, `"Téxt thát was optícálly recógnízéd".replaceChars("áéíóú", "aeiou")` returns the string “Text that was optically recognizedâ€. You cannot use this to replace a single character with more than one character. + +###### find(s, sub or p) {#finds-sub-or-p} + +Outputs an array of all consecutive substrings inside string s that match the substring or [regex](expressions#grel-supported-regex) pattern p. For example, `"abeadsabmoloei".find(/[aeio]+/)` would result in the array [ "a", "ea", "a", "o", "oei" ]. + +You can supply a substring instead of p, by putting it in quotes, and OpenRefine will compile it into a regex pattern. Anytime you supply quotes, OpenRefine interprets the contents as a string, not regex. If you wish to use any regex notation, wrap the pattern in forward slashes. + +###### match(s, p) {#matchs-p} + +Attempts to match the string s in its entirety against the [regex](expressions#grel-supported-regex) pattern p and, if the pattern is found, outputs an array of all [capturing groups](https://www.regular-expressions.info/brackets.html) (found in order). For example, `"230.22398, 12.3480".match(/.*(\d\d\d\d)/)` returns an array of 1 substring: [ "3480" ]. It does not find 2239 as the first sequence with four digits, because the regex indicates the four digits must come at the end of the string. + +You will need to convert the array to a string to store it in a cell, with a function such as toString(). An empty array [] is returned when there is no match to the desired substrings. A null is output when the entire regex does not match. + +Remember to enclose your regex in forward slashes, and to escape characters and use parentheses as needed. Parentheses denote a desired substring (capturing group); for example, “.*(\d\d\d\d)†would return an array containing a single value, while “(.*)(\d\d\d\d)†would return two. So, if you are looking for a desired substring anywhere within a string, use the syntax `value.match(/.*(desired-substring-regex).*/)`. + +For example, if `value` is “hello 123456 goodbyeâ€, the following would occur: + +|Expression|Result| +|-|-| +|`value.match(/\d{6}/)` |null (does not match the full string)| +|`value.match(/.*\d{6}.*/)` |[ ] (no indicated substring)| +|`value.match(/.*(\d{6}).*/)` |[ "123456" ] (array with one value)| +|`value.match(/(.*)(\d{6})(.*)/)` |[ "hello ", "123456", " goodbye" ] (array with three values)| + +### String parsing and splitting {#string-parsing-and-splitting} + +###### toNumber(s) {#tonumbers} + +Returns a string converted to a number. Will attempt to convert other formats into a string, then into a number. If the value is already a number, it will return the number. + +###### split(s, s or p sep, b preserveTokens (optional)) {#splits-s-or-p-sep-b-preservetokens-optional} + +Returns the array of strings obtained by splitting s by sep. The separator can be either a string or a regex pattern. For example, `"fire, water, earth, air".split(",")` returns an array of 4 strings: [ "fire", " water", " earth", " air" ]. Note that the space characters are retained but the separator is removed. If you include “true†for the preserveTokens boolean, empty segments are preserved. + +###### splitByLengths(s, n1, n2, ...) {#splitbylengthss-n1-n2-} + +Returns the array of strings obtained by splitting s into substrings with the given lengths. For example, `"internationalization".splitByLengths(5, 6, 3)` returns an array of 3 strings: [ "inter", "nation", "ali" ]. Excess characters are discarded. + +###### smartSplit(s, s or p sep (optional)) {#smartsplits-s-or-p-sep-optional} + +Returns the array of strings obtained by splitting s by sep, or by guessing either tab or comma separation if there is no sep given. Handles quotes properly and understands cancelled characters. The separator can be either a string or a regex pattern. For example, `value.smartSplit("\n")` will split at a carriage return or a new-line character. + +Note: [`value.escape('javascript')`](#escapes-s-mode) is useful for previewing unprintable characters prior to using smartSplit(). + +###### splitByCharType(s) {#splitbychartypes} + +Returns an array of strings obtained by splitting s into groups of consecutive characters each time the characters change [Unicode categories](https://en.wikipedia.org/wiki/Unicode_character_property#General_Category). For example, `"HenryCTaylor".splitByCharType()` will result in an array of [ "H", "enry", "CT", "aylor" ]. It is useful for separating letters and numbers: `"BE1A3E".splitByCharType()` will result in [ "BE", "1", "A", "3", "E" ]. + +###### partition(s, s or p fragment, b omitFragment (optional)) {#partitions-s-or-p-fragment-b-omitfragment-optional} + +Returns an array of strings [ a, fragment, z ] where a is the substring within s before the first occurrence of fragment, and z is the substring after fragment. Fragment can be a string or a regex. For example, `"internationalization".partition("nation")` returns 3 strings: [ "inter", "nation", "alization" ]. If s does not contain fragment, it returns an array of [ s, "", "" ] (the original unpartitioned string, and two empty strings). + +If the omitFragment boolean is true, for example with `"internationalization".partition("nation", true)`, the fragment is not returned. The output is [ "inter", "alization" ]. + +You can use regex for your fragment. The expresion `"abcdefgh".partition(/c.e/)` will output [“abcâ€, "cde", defgh†]. + +###### rpartition(s, s or p fragment, b omitFragment (optional)) {#rpartitions-s-or-p-fragment-b-omitfragment-optional} + +Returns an array of strings [ a, fragment, z ] where a is the substring within s before the last occurrence of fragment, and z is the substring after the last instance of fragment. (Rpartition means “reverse partition.â€) For example, `"parallel".rpartition("a")` returns 3 strings: [ "par", "a", "llel" ]. Otherwise works identically to partition() above. + +### Encoding and hashing {#encoding-and-hashing} + +###### diff(s1, s2, s timeUnit (optional)) {#diffs1-s2-s-timeunit-optional} + +Takes two strings and compares them, returning a string. Returns the remainder of s2 starting with the first character where they differ. For example, `"cacti".diff("cactus")` returns "us". Also works with dates; see [Date functions](#diffd1-d2-s-timeunit). + +###### escape(s, s mode) {#escapes-s-mode} + +Escapes s in the given escaping mode. The mode can be one of: "html", "xml", "csv", "url", "javascript". Note that quotes are required around your mode. See the [recipes](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#question-marks--showing-in-your-data) for examples of escaping and unescaping. + +###### unescape(s, s mode) {#unescapes-s-mode} + +Unescapes s in the given escaping mode. The mode can be one of: "html", "xml", "csv", "url", "javascript". Note that quotes are required around your mode. See the [recipes](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#atampampt----att) for examples of escaping and unescaping. + +###### md5(o) {#md5o} + +Returns the [MD5 hash](https://en.wikipedia.org/wiki/MD5) of an object. If fed something other than a string (array, number, date, etc.), md5() will convert it to a string and deliver the hash of the string. For example, `"internationalization".md5()` will return 2c55a1626e31b4e373ceedaa9adc12a3. + +###### sha1(o) {#sha1o} + +Returns the [SHA-1 hash](https://en.wikipedia.org/wiki/SHA-1) of an object. If fed something other than a string (array, number, date, etc.), sha1() will convert it to a string and deliver the hash of the string. For example, `"internationalization".sha1()` will return cd05286ee0ff8a830dbdc0c24f1cb68b83b0ef36. + +###### phonetic(s, s encoding) {#phonetics-s-encoding} + +Returns a phonetic encoding of a string, based on an available phonetic algorithm. See the [section on phonetic clustering](cellediting#clustering-methods) for more information. Can be one of the following supported phonetic methods: [metaphone, doublemetaphone, metaphone3](https://www.wikipedia.org/wiki/Metaphone), [soundex](https://en.wikipedia.org/wiki/Soundex), [cologne](https://en.wikipedia.org/wiki/Cologne_phonetics). Quotes are required around your encoding method. For example, `"Ruth Prawer Jhabvala".phonetic("metaphone")` outputs the string “R0PRWRJHBFLâ€. + +###### reinterpret(s, s encoderTarget, s encoderSource) {#reinterprets-s-encodertarget-s-encodersource} + +Returns s reinterpreted through the given character encoders. You must supply one of the [supported encodings](http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html) for each of the original source and the target output. Note that quotes are required around your character encoder. + +When an OpenRefine project is started, data is imported and interpreted. A specific character encoding is identified or manually selected at that time (such as UTF-8). You can reinterpret a column into another specificed encoding using this function. This function may not fix your data; it may be better to use this in conjunction with new projects to test the interpretation, and pre-format your data as needed. + +###### fingerprint(s) {#fingerprints} + +Returns the fingerprint of s, a string that is the first step in [fingerprint clustering methods](cellediting#clustering-methods): it will trim whitespaces, convert all characters to lowercase, remove punctuation, sort words alphabetically, etc. For example, `"Ruth Prawer Jhabvala".fingerprint()` outputs the string “jhabvala prawer ruthâ€. + +###### ngram(s, n) {#ngrams-n} + +Returns an array of the word n-grams of s. That is, it lists all the possible consecutive combinations of n words in the string. For example, `"Ruth Prawer Jhabvala".ngram(2)` would output the array [ "Ruth Prawer", "Prawer Jhabvala" ]. A word n-gram of 1 simply lists all the words in original order; an n-gram larger than the number of words in the string will only return the original string inside an array (e.g. `"Ruth Prawer Jhabvala".ngram(4)` would simply return ["Ruth Prawer Jhabvala"]). + +###### ngramFingerprint(s, n) {#ngramfingerprints-n} + +Returns the [n-gram fingerprint](cellediting#clustering-methods) of s. For example, `"banana".ngram(2)` would output “anbanaâ€, after first generating the 2-grams “ba an na an naâ€, removing duplicates, and sorting them alphabetically. + +###### unicode(s) {#unicodes} + +Returns an array of strings describing each character of s in their full unicode notation. For example, `"Bernice Rubens".unicode()` outputs [ 66, 101, 114, 110, 105, 99, 101, 32, 82, 117, 98, 101, 110, 115 ]. + +###### unicodeType(s) {#unicodetypes} + +Returns an array of strings describing each character of s by their unicode type. For example, `"Bernice Rubens".unicodeType()` outputs [ "uppercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "space separator", "uppercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter" ]. + +## Format-based functions (JSON, HTML, XML) {#format-based-functions-json-html-xml} + +###### jsonize(o) {#jsonizeo} + +Quotes a value as a JSON literal value. + +###### parseJson(s) {#parsejsons} + +Parses a string as JSON. get() can then be used with parseJson(): for example, `parseJson(" { 'a' : 1 } ").get("a")` returns 1. + +For example, from the following JSON array in `value`, we want to get all instances of “keywords†having the same object string name of “textâ€, and combine them, using the forEach() function to iterate over the array. + + { + "status":"OK", + "url":"", + "language":"english", + "keywords":[ + { + "text":"York en route", + "relevance":"0.974363" + }, + { + "text":"Anthony Eden", + "relevance":"0.814394" + }, + { + "text":"President Eisenhower", + "relevance":"0.700189" + } + ] + } + +The GREL expression `forEach(value.parseJson().keywords,v,v.text).join(":::")` will output “York en route:::Anthony Eden:::President Eisenhowerâ€. + +### Jsoup XML and HTML parsing {#jsoup-xml-and-html-parsing} + +###### parseHtml(s) {#parsehtmls} +Given a cell full of HTML-formatted text, parseHtml() simplifies HTML tags (such as by removing “ /†at the end of self-closing tags), closes any unclosed tags, and inserts linebreaks and indents for cleaner code. You cannot pass parseHtml() a URL, but you can pre-fetch HTML with the [Add column by fetching URLs](columnediting#add-column-by-fetching-urls) menu option. + +A cell cannot store the output of parseHtml() unless you convert it with toString(): for example, `value.parseHtml().toString()`. + +When parseHtml() simplifies HTML, it can sometimes introduce errors. When closing tags, it makes its best guesses based on line breaks, indentation, and the presence of other tags. You may need to manually check the results. + +You can then extract or [select()](#selects-element) which portions of the HTML document you need for further splitting, partitioning, etc. An example of extracting all table rows from a div using parseHtml().select() together is described more in depth at [StrippingHTML](https://github.com/OpenRefine/OpenRefine/wiki/StrippingHTML). + +###### parseXml(s) {#parsexmls} +Given a cell full of XML-formatted text, parseXml() returns a full XML document and adds any missing closing tags. You can then extract or [select()](#selects-element) which portions of the XML document you need for further splitting, partitioning, etc. Functions the same way as parseHtml() is described above. + +###### select(s, element) {#selects-element} +Returns an array of all the desired elements from an HTML or XML document, if the element exists. Elements are identified using the [Jsoup selector syntax](https://jsoup.org/apidocs/org/jsoup/select/Selector.html). For example, `value.parseHtml().select("img.portrait")[0]` would return the entirety of the first “img†tag with the “portrait†class found in the parsed HTML inside `value`. Returns an empty array if no matching element is found. Use with toString() to capture the results in a cell. A tutorial of select() is shown in [StrippingHTML](https://github.com/OpenRefine/OpenRefine/wiki/StrippingHTML). + +You can use select() more than once: + +``` +value.parseHtml().select("div#content")[0].select("tr").toString() +``` + +###### htmlAttr(s, element) {#htmlattrs-element} +Returns a string from an attribute on an HTML element. Use it in conjunction with parseHtml() as in the following example: `value.parseHtml().select("a.email")[0].htmlAttr("href")` would retrieve the email address attached to a link with the “email†class. + +###### xmlAttr(s, element) {#xmlattrs-element} +Returns a string from an attribute on an XML element. Functions the same way htmlAttr() is described above. Use it in conjunction with parseXml(). + +###### htmlText(element) {#htmltextelement} +Returns a string of the text from within an HTML element (including all child elements), removing HTML tags and line breaks inside the string. Use it in conjunction with parseHtml() and select() to provide an element, as in the following example: `value.parseHtml().select("div.footer")[0].htmlText()`. + +###### xmlText(element) {#xmltextelement} +Returns a string of the text from within an XML element (including all child elements). Functions the same way htmlText() is described above. Use it in conjunction with parseXml() and select() to provide an element. + +###### wholeText(element) {#wholetextelement} + +Selects the (unencoded) text of an element and its children, including any new lines and spaces, and returns a string of unencoded, un-normalized text. Use it in conjunction with parseHtml() and select() to provide an element as in the following example: `value.parseHtml().select("div.footer")[0].wholeText()`. + +###### innerHtml(element) {#innerhtmlelement} +Returns the [inner HTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) of an HTML element. This will include text and children elements within the element selected. Use it in conjunction with parseHtml() and select() to provide an element. + +###### innerXml(element) {#innerxmlelement} +Returns the inner XML elements of an XML element. Does not return the text directly inside your chosen XML element - only the contents of its children. To select the direct text, use ownText(). To select both, use xmlText(). Use it in conjunction with parseXml() and select() to provide an element. + +###### ownText(element) {#owntextelement} +Returns the text directly inside the selected XML or HTML element only, ignoring text inside children elements (for this, use innerXml()). Use it in conjunction with a parser and select() to provide an element. + +## Array functions {#array-functions} + +###### length(a) {#lengtha} +Returns the size of an array, meaning the number of objects inside it. Arrays can be empty, in which case length() will return 0. + +###### slice(a, n from, n to (optional)) {#slicea-n-from-n-to-optional} +Returns a sub-array of a given array, from the first index provided and up to and excluding the optional last index provided. Remember that array objects are indexed starting at 0. If the to value is omitted, it is understood to be the end of the array. For example, `[0, 1, 2, 3, 4].slice(1, 3)` returns [ 1, 2 ], and `[ 0, 1, 2, 3, 4].slice(2)` returns [ 2, 3, 4 ]. Also works with strings; see [String functions](#slices-n-from-n-to-optional). + +###### get(a, n from, n to (optional)) {#geta-n-from-n-to-optional} +Returns a sub-array of a given array, from the first index provided and up to and excluding the optional last index provided. Remember that array objects are indexed starting at 0. + +If the to value is omitted, only one array item is returned, as a string, instead of a sub-array. To return a sub-array from one index to the end, you can set the to argument to a very high number such as `value.get(2,999)` or you can use something like `with(value,a,a.get(1,a.length()))` to count the length of each array. + +Also works with strings; see [String functions](#gets-n-from-n-to-optional). + +###### inArray(a, s) {#inarraya-s} +Returns true if the array contains the desired string, and false otherwise. Will not convert data types; for example, `[ 1, 2, 3, 4 ].inArray("3")` will return false. + +###### reverse(a) {#reversea} +Reverses the array. For example, `[ 0, 1, 2, 3].reverse()` returns the array [ 3, 2, 1, 0 ]. + +###### sort(a) {#sorta} +Sorts the array in ascending order. Sorting is case-sensitive, uppercase first and lowercase second. For example, `[ "al", "Joe", "Bob", "jim" ].sort()` returns the array [ "Bob", "Joe", "al", "jim" ]. + +###### sum(a) {#suma} +Return the sum of the numbers in the array. For example, `[ 2, 1, 0, 3 ].sum()` returns 6. + +###### join(a, sep) {#joina-sep} +Joins the items in the array with sep, and returns it all as a string. For example, `[ "and", "or", "not" ].join("/")` returns the string “and/or/notâ€. + +###### uniques(a) {#uniquesa} +Returns the array with duplicates removed. Case-sensitive. For example, `[ "al", "Joe", "Bob", "Joe", "Al", "Bob" ].uniques()` returns the array [ "Joe", "al", "Al", "Bob" ]. + +As of OpenRefine 3.4.1, uniques() reorders the array items it returns; in 3.4 beta 644 and onwards, it preserves the original order (in this case, [ "al", "Joe", "Bob", "Al" ]). + +## Date functions {#date-functions} + +###### now() {#now} + +Returns the current time according to your system clock, in the [ISO 8601 extended format](exploring#data-types) (converted to UTC). For example, 10:53am (and 00 seconds) on November 26th 2020 in EST returns [date 2020-11-26T15:53:00Z]. + +###### toDate(o, b monthFirst, s format1, s format2, ...) {#todateo-b-monthfirst-s-format1-s-format2-} + +Returns the inputted object converted to a date object. Without arguments, it returns the ISO 8601 extended format. With arguments, you can control the output format: +* monthFirst: set false if the date is formatted with the day before the month. +* formatN: attempt to parse the date using an ordered list of possible formats. Supply formats based on the [SimpleDateFormat](https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html) syntax (and see the table below for a handy reference). + +For example, you can parse a column containing dates in different formats, such as cells with “Nov-09†and “11/09â€, using `value.toDate('MM/yy','MMM-yy').toString('yyyy-MM')` and both will output “2009-11â€. For another example, “1/4/2012 13:30:00†can be parsed into a date using `value.toDate('d/M/y H:m:s')`. + +| Letter | Date or Time Component | Presentation | Examples | +|-|-|-|-| +| G | Era designator | Text | AD | +| y | Year | Year | 1996; 96 | +| Y | [Week year](https://en.wikipedia.org/wiki/ISO_week_date#First_week) | Year | 2009; 09 | +| M | Month in year | Month | July; Jul; 07 | +| w | Week in year | Number | 27 | +| W | Week in month | Number | 2 | +| D | Day in year | Number | 189 | +| d | Day in month | Number | 10 | +| F | Day of week in month | Number | 2 | +| E | Day name in week | Text | Tuesday; Tue | +| u | Day number of week (1 = Monday, ..., 7 = Sunday) | Number | 1 | +| a | AM/PM marker | Text | PM | +| H | Hour in day (0-23) | Number | 0 | +| k | Hour in day (1-24) | Number | 24 | +| K | Hour in AM/PM (0-11) | Number | 0 | +| h | Hour in AM/PM (1-12) | Number | 12 | +| m | Minute in hour | Number | 30 | +| s | Second in minute | Number | 55 | +| S | Millisecond | Number | 978 | +| n | Nanosecond | Number | 789000 | +| z | Time zone | General time zone | Pacific Standard Time; PST; GMT-08:00 | +| Z | Time zone | RFC 822 time zone | \-0800 | +| X | Time zone | ISO 8601 time zone | \-08; -0800; -08:00 | + +###### diff(d1, d2, s timeUnit) {#diffd1-d2-s-timeunit} + +Given two dates, returns a number indicating the difference in a given time unit (see the table below). For example, `diff(("Nov-11".toDate('MMM-yy')), ("Nov-09".toDate('MMM-yy')), "weeks")` will return 104, for 104 weeks, or two years. The later date should go first. If the output is negative, invert d1 and d2. + +Also works with strings; see [diff() in string functions](#diffsd1-sd2-s-timeunit-optional). + +###### inc(d, n, s timeUnit) {#incd-n-s-timeunit} + +Returns a date changed by the given amount in the given unit of time (see the table below). The default unit is “hourâ€. A positive value increases the date, and a negative value moves it back in time. For example, if you want to move a date backwards by two months, use `value.inc(-2,"month")`. + +###### datePart(d, s timeUnit) {#datepartd-s-timeunit} + +Returns part of a date. The data type returned depends on the unit (see the table below). + +OpenRefine supports the following values for timeUnit: + +| Unit | Date part returned | Returned data type | Example using [date 2014-03-14T05:30:04.000789000Z] as value | +|-|-|-|-| +| years | Year | Number | value.datePart("years") → 2014 | +| year | Year | Number | value.datePart("year") → 2014 | +| months | Month | Number | value.datePart("months") → 2 | +| month | Month | Number | value.datePart("month") → 2 | +| weeks | Week of the month | Number | value.datePart("weeks") → 3 | +| week | Week of the month | Number | value.datePart("week") → 3 | +| w | Week of the month | Number | value.datePart("w") → 3 | +| weekday | Day of the week | String | value.datePart("weekday") → Friday | +| hours | Hour | Number | value.datePart("hours") → 5 | +| hour | Hour | Number | value.datePart("hour") → 5 | +| h | Hour | Number | value.datePart("h") → 5 | +| minutes | Minute | Number | value.datePart("minutes") → 30 | +| minute | Minute | Number | value.datePart("minute") → 30 | +| min | Minute | Number | value.datePart("min") → 30 | +| seconds | Seconds | Number | value.datePart("seconds") → 04 | +| sec | Seconds | Number | value.datePart("sec") → 04 | +| s | Seconds | Number | value.datePart("s") → 04 | +| milliseconds | Millseconds | Number | value.datePart("milliseconds") → 789 | +| ms | Millseconds | Number | value.datePart("ms") → 789 | +| S | Millseconds | Number | value.datePart("S") → 789 | +| n | Nanoseconds | Number | value.datePart("n") → 789000 | +| nano | Nanoseconds | Number | value.datePart("n") → 789000 | +| nanos | Nanoseconds | Number | value.datePart("n") → 789000 | +| time | Milliseconds between input and the [Unix Epoch](https://en.wikipedia.org/wiki/Unix_time) | Number | value.datePart("time") → 1394775004000 | + +## Math functions {#math-functions} + +For integer division and precision, you can use simple evaluations such as `1 / 2`, which is equivalent to `floor(1/2)` - that is, it returns only whole number results. If either operand is a floating point number, they both get promoted to floating point and a floating point result is returned. You can use `1 / 2.0` or `1.0 / 2` or `1.0 * x / y` (if you're working with variables of unknown contents). + +:::caution +Some of these math functions don't recognize integers when supplied as the first argument in dot notation (e.g., `5.cos()` simply returns 5 instead of the expected result). To ensure operations are successful, always wrap the first argument in brackets, such as `(value).cos()`. +::: + +|Function|Use|Example| +|-|-|-| +|`abs(n)`|Returns the absolute value of a number.|`abs(-6)` returns 6.| +|`acos(n)`|Returns the arc cosine of an angle, in the range 0 through [PI](https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#PI).|`acos(0.345)` returns 1.218557541697832.| +|`asin(n)`|Returns the arc sine of an angle in the range of -PI/2 through PI/2.|`asin(0.345)` returns 0.35223878509706474.| +|`atan(n)`|Returns the arc tangent of an angle in the range of -PI/2 through PI/2.|`atan(0.345)` returns 0.3322135507465967.| +|`atan2(n1, n2)`|Converts rectangular coordinates (n1, n2) to polar (r, theta). Returns number theta.|`atan2(0.345,0.6)` returns 0.5218342798144103.| +|`ceil(n)`|Returns the ceiling of a number.|`3.7.ceil()` returns 4 and `-3.7.ceil()` returns -3.| +|`combin(n1, n2)`|Returns the number of combinations for n2 elements as divided into n1.|`combin(20,2)` returns 190.| +|`cos(n)`|Returns the trigonometric cosine of a value.|`cos(5)` returns 0.28366218546322625.| +|`cosh(n)`|Returns the hyperbolic cosine of a value.|`cosh(5)` returns 74.20994852478785.| +|`degrees(n)`|Converts an angle from radians to degrees.|`degrees(5)` returns 286.4788975654116.| +|`even(n)`|Rounds the number up to the nearest even integer.|`even(5)` returns 6.| +|`exp(n)`|Returns [e](https://en.wikipedia.org/wiki/E_(mathematical_constant)) raised to the power of n.|`exp(5)` returns 148.4131591025766.| +|`fact(n)`|Returns the factorial of a number, starting from 1.|`fact(5)` returns 120.| +|`factn(n1, n2)`|Returns the factorial of n1, starting from n2.|`factn(10,3)` returns 280.| +|`floor(n)`|Returns the floor of a number.|`3.7.floor()` returns 3 and `-3.7.floor()` returns -4.| +|`gcd(n1, n2)`|Returns the greatest common denominator of two numbers.|`gcd(95,135)` returns 5.| +|`lcm(n1, n2)`|Returns the least common multiple of two numbers.|`lcm(95,135)` returns 2565.| +|`ln(n)`|Returns the natural logarithm of n.|`ln(5)` returns 1.6094379124341003.| +|`log(n)`|Returns the base 10 logarithm of n.|`log(5)` returns 0.6989700043360189.| +|`max(n1, n2)`|Returns the larger of two numbers.|`max(3,10)` returns 10.| +|`min(n1, n2)`|Returns the smaller of two numbers.|`min(3,10)` returns 3.| +|`mod(n1, n2)`|Returns n1 modulus n2. Note: `value.mod(9)` will work, whereas `74.mod(9)` will not work.|`mod(74, 9)` returns 2. | +|`multinomial(n1, n2 …(optional))`|Calculates the multinomial of one number or a series of numbers.|`multinomial(2,3)` returns 10.| +|`odd(n)`|Rounds the number up to the nearest odd integer.|`odd(10)` returns 11.| +|`pow(n1, n2)`|Returns n1 raised to the power of n2. Note: value.pow(3)` will work, whereas `2.pow(3)` will not work.|`pow(2, 3)` returns 8 (2 cubed) and `pow(3, 2)` returns 9 (3 squared). The square root of any numeric value can be called with `value.pow(0.5)`.| +|`quotient(n1, n2)`|Returns the integer portion of a division (truncated, not rounded), when supplied with a numerator and denominator.|`quotient(9,2)` returns 4.| +|`radians(n)`|Converts an angle in degrees to radians.|`radians(10)` returns 0.17453292519943295.| +|`randomNumber(n lowerBound, n upperBound)`|Returns a random integer in the interval between the lower and upper bounds (inclusively). Will output a different random number in each cell in a column.| +|`round(n)`|Rounds a number to the nearest integer.|`3.7.round()` returns 4 and `-3.7.round()` returns -4.| +|`sin(n)`|Returns the trigonometric sine of an angle.|`sin(10)` returns -0.5440211108893698.| +|`sinh(n)`|Returns the hyperbolic sine of an angle.|`sinh(10)` returns 11013.232874703393.| +|`sum(a)`|Sums the numbers in an array. Ignores non-number items. Returns 0 if the array does not contain numbers.|`sum([ 10, 2, three ])` returns 12.| +|`tan(n)`|Returns the trigonometric tangent of an angle.|`tan(10)` returns 0.6483608274590866.| +|`tanh(n)`|Returns the hyperbolic tangent of a value.|`tanh(10)` returns 0.9999999958776927.| + +## Other functions {#other-functions} + +###### type(o) {#typeo} +Returns a string with the data type of o, such as undefined, string, number, boolean, etc. For example, a [Transform](cellediting#transform) operation using `value.type()` will convert all cells in a column to strings of their data types. + +###### facetCount(choiceValue, s facetExpression, s columnName) {#facetcountchoicevalue-s-facetexpression-s-columnname} +Returns the facet count corresponding to the given choice value, by looking for the facetExpression in the choiceValue in columnName. For example, to create facet counts for the following table, we could generate a new column based on “Gift†and enter in `value.facetCount("value", "Gift")`. This would add the column we've named “Countâ€: + +| Gift | Recipient | Price | Count | +|-|-|-|-| +| lamp | Mary | 20 | 1 | +| clock | John | 57 | 2 | +| watch | Amit | 80 | 1 | +| clock | Claire | 62 | 2 | + +The facet expression, wrapped in quotes, can be useful to manipulate the inputted values before counting. For example, you could do a textual cleanup using fingerprint(): `(value.fingerprint()).facetCount(value.fingerprint(),"Gift")`. + +###### hasField(o, s name) {#hasfieldo-s-name} +Returns a boolean indicating whether o has a member field called [name](expressions#variables). For example, `cell.recon.hasField("match")` will return false if a reconciliation match hasn’t been selected yet, or true if it has. You cannot chain your desired fields: for example, `cell.hasField("recon.match")` will return false even if the above expression returns true). + +###### coalesce(o1, o2, o3, ...) {#coalesceo1-o2-o3-} +Returns the first non-null from a series of objects. For example, `coalesce(value, "")` would return an empty string Ҡif `value` was null, but otherwise return `value`. + +###### cross(cell, s projectName (optional), s columnName (optional)) {#crosscell-s-projectname-optional-s-columnname-optional} +Returns an array of zero or more rows in the project projectName for which the cells in their column columnName have the same content as the cell in your chosen column. For example, if two projects contained matching names, and you wanted to pull addresses for people by their names from a project called “People†you would apply the following expression to your column of names: +``` +cell.cross("People","Name").cells["Address"].value[0] +``` + +This would match your current column to the “Name†column in “People†and, using those matches, pull the respective “Address†value into your current project. + +You may need to do some data preparation with cross(), such as using trim() on your key columns or deduplicating values. + +The first argument will be interpreted as `cell.value` if set to `cell`. If you omit projectName and columnName, they will default to the current project and index column (number 0). + +Recipes and more examples for using cross() can be found [on our wiki](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#combining-datasets). diff --git a/OpenRefine/docs/docs/manual/installing.md b/OpenRefine/docs/docs/manual/installing.md new file mode 100644 index 000000000..74db80926 --- /dev/null +++ b/OpenRefine/docs/docs/manual/installing.md @@ -0,0 +1,425 @@ +--- +id: installing +title: Installing OpenRefine +sidebar_label: Installing +--- + +## System requirements {#system-requirements} + +OpenRefine does not require internet access to run its basic functions. Once you download and install it, it runs as a small web server on your own computer, and you access that local web server by using your browser. It only requires an internet connection to import data from the web, reconcile data using a web service, or export data to the web. + +OpenRefine requires three things on your computer in order to function: + +#### Compatible operating system {#compatible-operating-system} + +OpenRefine is designed to work with **Windows**, **Mac**, and **Linux** operating systems. [Our team releases packages for each](https://openrefine.org/download.html). + +#### Java {#java} + +[Java](https://java.com/en/download/) must be installed and configured on your computer to run OpenRefine. The Mac version of OpenRefine includes Java; new in OpenRefine 3.4, there is also a Windows package with Java included. + +If you install and start OpenRefine on a Windows computer without Java, it will automatically open up a browser window to the [Java downloads page](https://java.com/en/download/), and you can simply follow the instructions there. + +We recommend you [download](https://java.com/en/download/) and install Java before proceeding with the OpenRefine installation. Please note that OpenRefine 3.5 works with Java 8 to Java 17. + +#### Compatible browser {#compatible-browser} + +OpenRefine works best on browsers based on Webkit, such as: + +* Google Chrome +* Chromium +* Opera +* Microsoft Edge + +We are aware of some minor rendering and performance issues on other browsers such as Firefox. We don't support Internet Explorer. If you are having issues running OpenRefine, see the [section on Running](running.md#troubleshooting). + +### Release versions {#release-versions} + +OpenRefine always has a [latest stable release](https://github.com/OpenRefine/OpenRefine/releases/latest), as well as some more recent developments available in beta, release candidate, or [snapshot releases](https://github.com/OpenRefine/OpenRefine-snapshot-releases/releases). If you are installing for the first time, we recommend [the latest stable release](https://github.com/OpenRefine/OpenRefine/releases/latest). + +If you wish to use an extension that is only compatible with an earlier version of OpenRefine, and do not require the latest features, you may find that [an older stable version is best for you](https://github.com/OpenRefine/OpenRefine/releases) in our list of releases. Look at later releases to see which security vulnerabilities are being fixed, in order to assess your own risk tolerance for using earlier versions. Look for “final release†versions instead of “beta†or “release candidate†versions. + +#### Unstable versions {#unstable-versions} + +If you need a recently developed function, and are willing to risk some untested code, you can look at [the most recent items in the list](https://github.com/OpenRefine/OpenRefine/releases) and see what changes appeal to you. + +“Beta†and “release candidate†versions may both have unreported bugs and are most suitable for people who are willing to help us troubleshoot these versions by [creating bug reports](https://github.com/OpenRefine/OpenRefine/issues). + +For the absolute latest development updates, see the [snapshot releases](https://github.com/OpenRefine/OpenRefine-snapshot-releases/releases). These are created with every commit. + +#### What’s changed {#whats-changed} + +Our [latest version is OpenRefine 3.4.1](https://github.com/OpenRefine/OpenRefine/releases/tag/3.4.1), released September 24th 2020. The major changes in this version are listed on the [3.4.1 release page](https://github.com/OpenRefine/OpenRefine/releases/tag/3.4.1) with the downloadable packages. + +You can find information about all OpenRefine versions on the [Releases page on Github](https://github.com/OpenRefine/OpenRefine/releases). + +:::info Other distributions +OpenRefine may also work in other environments, such as [Chromebooks](https://gist.github.com/organisciak/3e12e5138e44a2fed75240f4a4985b4f) where Linux terminals are available. Look at our list of [Other Distributions on the Downloads page](https://openrefine.org/download.html) for other ways of running OpenRefine, and refer to our contributor community to see new environments in development. +::: + +## Installing or upgrading {#installing-or-upgrading} +### Back up your data {#back-up-your-data} + +If you are upgrading from an older version of OpenRefine and have projects already on your computer, you should create backups of those projects before you install a new version. + +First, [locate your workspace directory](#where-is-data-stored). Then copy everything you find there and paste it into a folder elsewhere on your computer. + +For extra security you can [export your existing OpenRefine projects](exporting#export-a-project). + +:::caution +Take note of the [extensions](#installing-extensions) you have currently installed. They may not be compatible with the upgraded version of OpenRefine. Installations can be installed in two places, so be sure to check both your workspace directory and the existing installation directory. +::: + +### Install or upgrade OpenRefine {#install-or-upgrade-openrefine} + +If you are upgrading an existing OpenRefine installation, you can delete the old program files and install the new files into the same space. Do not overwrite the files as some obsolete files may be left over unnecessarily. + +:::caution +If you have extensions installed, do not delete the `webapp\extensions` folder where you installed them. You may wish to install extensions into the workspace directory instead of the program directory. There is no guarantee that extensions will be forward-compatible with new versions of OpenRefine, and we do not maintain extensions. +::: + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + + +Once you have downloaded the `.zip` file, extract it into a folder where you wish to store program files (such as `D:\Program Files\OpenRefine`). + +You can right-click on `openrefine.exe` or `refine.bat` and pin one of those programs to your Start Menu or create shortcuts for easier access. + + + + + +Once you have downloaded the `.dmg` file, open it and drag the OpenRefine icon onto the Applications folder icon (just like you would normally install Mac applications). + + + + + +The quick version: + +1. Install [Homebrew](http://brew.sh) +2. In Terminal enter ` brew cask install openrefine` +1. Then find OpenRefine in your Applications folder. + +The long version: + +[Homebrew](http://brew.sh) is a popular command-line package manager for Mac. Installing Homebrew is accomplished by pasting the installation command on the Homebrew website into a Terminal window. Once Homebrew is installed, applications like OpenRefine can be installed via a simple command. You can [install Homebrew from their website](http://brew.sh). + +###### Install {#install} + +Install OpenRefine with this command: + +``` +brew cask install openrefine +``` + +You should see output like this: + +``` +==> Downloading https://github.com/OpenRefine/OpenRefine/releases/download/2.7/openrefine-mac-2.7.dmg +########################### 100.0% + ==> Verifying checksum for Cask openrefine + ==> Installing Cask openrefine + ==> Moving App 'OpenRefine.app' to '/Applications/OpenRefine.app'. + 🺠openrefine was successfully installed! +``` + +Behind the scenes, this command causes Homebrew to download the OpenRefine installer, verify the file’s authenticity (using a SHA-256 checksum), mount the disk image, copy the `OpenRefine.app` application bundle into the Applications folder, unmount the disk image, and save a copy of the installer and metadata about the installation for future use. + +If an existing `OpenRefine.app` is found in the Applications folder, Homebrew will not overwrite it, so installing via Homebrew requires either deleting or renaming previously installed copies. + +###### Uninstall {#uninstall} + +To uninstall OpenRefine, paste this command into the Terminal: + +``` + brew cask uninstall openrefine +``` + +You should see output like this: + +``` + ==> Removing App '/Applications/OpenRefine.app'. +``` + +###### Update {#update} + +To update to the latest version of OpenRefine, paste this command into the Terminal: + +``` + brew cask reinstall openrefine +``` + +You should see output like this: + +``` + ==> Downloading https://github.com/OpenRefine/OpenRefine/releases/download/2.7/openrefine-mac-2.7.dmg +########################### 100.0% + ==> Verifying checksum for Cask openrefine + ==> Removing App '/Applications/OpenRefine.app'. + ==> Moving App 'OpenRefine.app' to '/Applications/OpenRefine.app'. + 🺠openrefine was successfully installed! +``` + +If you had previously installed the `openrefine-dev` cask (containing a release candidate) and you want to move to the stable release, you need to first uninstall the old cask and then install the new one: + +``` + brew cask uninstall openrefine-dev + brew cask install openrefine +``` + + + + +Once you have downloaded the `.tar.gz` file, open a shell, navigate to the folder containing the download, and type: + +``` +tar xzf openrefine-linux-3.4.tar.gz +``` + + + + + +--- + + +### Set where data is stored {#set-where-data-is-stored} + +OpenRefine stores data in two places: program files in the program directory, wherever it is you’ve installed it; and project files in what we call the “workspace directory.†You can access this folder easily from OpenRefine by going to the [home screen](running#the-home-screen) (at [http://127.0.0.1:3333/](http://127.0.0.1:3333/)) and clicking Browse workspace directory. + +By default this is: + + + + + +Depending on your version of Windows, the data is in one of these directories: +* `%appdata%\OpenRefine` +* `%localappdata%\OpenRefine` +* `C:\Documents and Settings\(user id)\Local Settings\Application Data\OpenRefine` +* `C:\Users\(user id)\AppData\Roaming\OpenRefine` +* `C:\Users\(user id)\AppData\Local\OpenRefine` +* `C:\Users\(user id)\OpenRefine` + +For older Google Refine releases, replace `OpenRefine` with `Google\Refine`. + +You can change this by adding this line to the file `openrefine.l4j.ini` and specifying your desired drive and folder path: + +``` +-Drefine.data_dir=D:\MyDesiredFolder +``` + +If your folder path has spaces, use neutral quotation marks around it: + +``` +-Drefine.data_dir="D:\My Desired Folder" +``` + +If the folder does not exist, OpenRefine will create it. + + + + + +``` +~/Library/Application Support/OpenRefine/ +``` + +For older versions, as Google Refine: + +``` +~/Library/Application Support/Google/Refine/ +``` + +Logging is to `/var/log/daemon.log` - grep for `com.google.refine.Refine`. + + + + + +``` +~/.local/share/openrefine/ +``` + +You can change this when you run OpenRefine from the terminal, by pointing to the workspace directory through the `-d` parameter: + +``` + ./refine -p 3333 -i 0.0.0.0 -m 6000M -d /My/Desired/Folder +``` + + + + + +--- + + +### Logs {#logs} + +OpenRefine does not currently output an error log, but because the OpenRefine console window is always open (on Linux and Windows) while OpenRefine runs in your browser, you can copy information from the console if an error occurs. + +Using a Mac, you can [run OpenRefine using the terminal](running#starting-and-exiting) in order to capture errors. + +--- + +## Increasing memory allocation {#increasing-memory-allocation} + +OpenRefine relies on having computer memory available to it to work effectively. If you are planning to work with large datasets, you may wish to set up OpenRefine to handle it at the outset. By “large†we generally mean one of the following indicators: +* more than one million total cells +* an input file size of more than 50 megabytes (MB) +* more than 50 [rows per record in records mode](running#records-mode) + +By default OpenRefine is set to operate with 1 gigabyte (GB) of memory (1024MB). If you feel that OpenRefine is running slowly, or you are getting “out of memory†errors (for example, `java.lang.OutOfMemoryError`), you can try allocating more memory. + +A good practice is to start with no more than 50% of whatever memory is left over after the estimated usage of your operating system, to leave memory for your browser to run. + +All of the settings below use a four-digit number to specify the megabytes (MB) used (actually [mebibytes](https://en.wikipedia.org/wiki/Mebibyte)). The default is usually 1024MB, but the new value doesn't need to be a multiple of 1024. + +:::info Dealing with large datasets +If your project is big enough to need more than the default amount of memory, consider turning off Parse cell text into numbers, dates, ... on import. It's convenient, but less efficient than explicitly converting any columns that you need as a data type other than the default “string†type. +::: + + + + + +#### Using openrefine.exe {#using-openrefineexe} + +If you run `openrefine.exe`, you will need to edit the `openrefine.l4j.ini` file found in the program directory and edit the line + +``` +# max memory memory heap size +-Xmx1024M +``` + +The line “-Xmx1024M†defines the amount of memory available in megabytes. Change the number “1024†- for example, edit the line to “-Xmx2048M†to make 2048MB [2GB] of memory available. + +:::caution openrefine.exe not running? +Once you increase the memory allocation, you may find that you cannot run `openrefine.exe`. In this case, your computer needs a 64-bit version of [Java](https://www.java.com/en/download/help/index_installing.xml) (this is different from [Java JDK](#install-or-upgrade-java). Look for the “Windows Offline (64-bit)†download on the Downloads page and install that. Your system must also be set to use the 64-bit version of Java by [changing the Java configuration](https://www.java.com/en/download/help/update_runtime_settings.xml). +::: + +#### Using refine.bat {#using-refinebat} + +On Windows, OpenRefine can also be run by using the file `refine.bat` in the program directory. If you start OpenRefine using `refine.bat`, the memory available to OpenRefine can be specified either through command line options, or through the `refine.ini` file. + +To set the maximum amount of memory on the command line when using `refine.bat`, `cd` to the program directory, then type + +```refine.bat /m 2048m``` + +where “2048†is the maximum amount of MB that you want OpenRefine to use. + +To change the default that `refine.bat` uses, edit the `refine.ini` line that reads + +```REFINE_MEMORY=1024M``` + +Note that this file is only read if you use `refine.bat`, not `openrefine.exe`. + + + + +If you have downloaded the `.dmg` package and you start OpenRefine by double-clicking on it: + +* close OpenRefine +* control-click on the OpenRefine icon (opens the contextual menu) +* click on "show package content†(a finder window opens) +* open the “Contents†folder +* open the `Info.plist` file with any text editor (like Mac's default TextEdit) +* Change “-Xmx1024M†into, for example, “-Xmx2048M†or “-Xmx8G†+* save the file +* restart OpenRefine. + + + + +If you have downloaded the `.tar.gz` package and you start OpenRefine from the command line, add the “-m xxxxM†parameter like this: +`./refine -m 2048m` + +#### Setting a default {#setting-a-default} + +If you don't want to set this option on the command line each time, you can also set it in the `refine.ini` file. Edit the line + +``` +REFINE_MEMORY=1024M +``` + +Make sure it is not commented out (that is, that the line doesn't start with a “#†character), and change “1024†to a higher value. Save the file, and when you next start OpenRefine it will use this value. + + + + + +--- + + +## Installing extensions {#installing-extensions} + +Extensions have been created by our contributor community to add functionality or provide convenient shortcuts for common uses of OpenRefine. [We list extensions we know about on our downloads page](https://openrefine.org/download.html). + +:::info Contributing extensions +If you’d like to create or modify an extension, [see our developer documentation here](https://github.com/OpenRefine/OpenRefine/wiki/Documentation-For-Developers). If you’re having a problem, [use our downloads page](https://openrefine.org/download.html) to go to the extension’s page and report the issue there. +::: + +### Two ways to install extensions {#two-ways-to-install-extensions} + +You can [install extensions in one of two places](#set-where-data-is-stored): + +* Into your OpenRefine program folder, so they will only be available to that version/installation of OpenRefine (meaning the extension will not run if you upgrade OpenRefine), or +* Into your workspace, where your projects are stored, so they will be available no matter which version of OpenRefine you’re using. + +We provide these options because you may wish to reinstall a given extension manually each time you upgrade OpenRefine, in order to be sure it works properly. + +### Find the right place to install {#find-the-right-place-to-install} + +If you want to install the extension into the program folder, go to your program directory and then go to `webapp\extensions` (or create it if not does not exist). + +If you want to install the extension into your workspace, you can: +* launch OpenRefine and click Open Project in the sidebar +* At the bottom of the screen, click Browse workspace directory +* A file-explorer or finder window will open in your workspace +* Create a new folder called “extensions†inside the workspace if it does not exist. + +You can also [find your workspace on each operating system using these instructions](#set-where-data-is-stored). + +### Install the extension {#install-the-extension} + +Some extensions have their own instructions: make sure you read the documentation before you begin installing. + +Some extensions may have multiple versions, to match OpenRefine versions, so be sure to choose the right release for your installation. If you have questions about compatibility or want to request or voice your support for an update, [use our downloads page](https://openrefine.org/download.html) to go to the extension’s page and report the issue there. + +Generally, the installation process will be: + +* Download the extension (usually as a zip file from GitHub) +* Extract the zip contents into the “extensions†directory, making sure all the contents go into one folder with the name of the extension +* Start (or restart) OpenRefine. + +To confirm that installation was a success, follow the instructions provided by the extension. Each extension will appear in its own way inside the OpenRefine interface. Make sure you read its documentation to know where the functionality will appear, such as under specific dropdown menus. diff --git a/OpenRefine/docs/docs/manual/jythonclojure.md b/OpenRefine/docs/docs/manual/jythonclojure.md new file mode 100644 index 000000000..a93d18155 --- /dev/null +++ b/OpenRefine/docs/docs/manual/jythonclojure.md @@ -0,0 +1,76 @@ +--- +id: jythonclojure +title: Jython & Clojure +sidebar_label: Jython & Clojure +--- + +## Jython {#jython} + +Jython 2.7.2 comes bundled with the default installation of OpenRefine 3.4.1. You can add libraries and code by following [this tutorial](https://github.com/OpenRefine/OpenRefine/wiki/Extending-Jython-with-pypi-modules). A large number of Python files (`.py` or `.pyc`) are compatible. + +Python code that depends on C bindings will not work in OpenRefine, which uses Java / Jython only. Since Jython is essentially Java, you can also import Java libraries and utilize those. + +You will need to restart OpenRefine, so that new Jython or Python libraries are initialized during startup. + +OpenRefine now has [most of the Jsoup.org library built into GREL functions](grelfunctions#jsoup-xml-and-html-parsing-functions) for parsing and working with HTML and XML elements. + +### Syntax {#syntax} + +Expressions in Jython must have a `return` statement: + +``` + return value[1:-1] +``` + +``` + return rowIndex%2 +``` + +Fields have to be accessed using the bracket operator rather than dot notation: + +``` + return cells["col1"]["value"] +``` + +For example, to access the [edit distance](reconciling#reconciliation-facets) between a reconciled value and an original cell value using [recon variables](#reconciliation): + +``` + return cell["recon"]["features"]["nameLevenshtein"] +``` + +To return the lower case of `value` (if the value is not null): + +``` + if value is not None: + return value.lower() + else: + return None +``` + +### Tutorials {#tutorials} +- [Extending Jython with pypi modules](https://github.com/OpenRefine/OpenRefine/wiki/Extending-Jython-with-pypi-modules) +- [Working with phone numbers using Java libraries inside Python](https://github.com/OpenRefine/OpenRefine/wiki/Jython#tutorial---working-with-phone-numbers-using-java-libraries-inside-python) + +Full documentation on the Jython language can be found on its official site: [http://www.jython.org](http://www.jython.org). + +## Clojure {#clojure} + +Clojure 1.10.1 comes bundled with the default installation of OpenRefine 3.4.1. At this time, not all [variables](expressions#variables) can be used with Clojure expressions: only `value`, `row`, `rowIndex`, `cell`, and `cells` are available. + +For example, functions can take the form +``` +(.. value (toUpperCase) ) +``` + +Or can look like +``` +(-> value (str/split #" ") last ) +``` + +which functions like `value.split(" ")` in GREL. + +For help with syntax, see the [Clojure website's guide to syntax](https://clojure.org/guides/learn/syntax). + +User-contributed Clojure recipes can be found on our wiki at [https://github.com/OpenRefine/OpenRefine/wiki/Recipes#11-clojure](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#11-clojure). + +Full documentation on the Clojure language can be found on its official site: [https://clojure.org/](https://clojure.org/). \ No newline at end of file diff --git a/OpenRefine/docs/docs/manual/reconciling.md b/OpenRefine/docs/docs/manual/reconciling.md new file mode 100644 index 000000000..0d14e80ad --- /dev/null +++ b/OpenRefine/docs/docs/manual/reconciling.md @@ -0,0 +1,242 @@ +--- +id: reconciling +title: Reconciling +sidebar_label: Reconciling +--- + +## Overview {#overview} + +Reconciliation is the process of matching your dataset with that of an external source. Datasets for comparison might be produced by libraries, archives, museums, academic organizations, scientific institutions, non-profits, or interest groups. You can also reconcile against user-edited data on [Wikidata or other Wikibase instances](wikibase/reconciling), or reconcile against [a local dataset that you yourself supply](https://github.com/OpenRefine/OpenRefine/wiki/Reconcilable-Data-Sources#local-services). + +To reconcile your OpenRefine project against an external dataset, that dataset must offer a web service that conforms to the [Reconciliation Service API standards](https://reconciliation-api.github.io/specs/0.1/). + +You may wish to reconcile in order to: +* fix spelling or variations in proper names +* clean up manually-entered subject headings against authorities such as the [Library of Congress Subject Headings](https://id.loc.gov/authorities/subjects.html) (LCSH) +* link your data to an existing dataset +* add to an editable platform such as [Wikidata](https://www.wikidata.org) +* or see whether entities in your project appear in some specific list, such as the [Panama Papers](https://aleph.occrp.org/datasets/734). + +Reconciliation is semi-automated: OpenRefine matches your cell values to the reconciliation information as best it can, but human judgment is required to review and approve the results. Reconciling happens by default through string searching, so typos, whitespace, and extraneous characters will have an effect on the results. You may wish to [clean and cluster](cellediting) your data before reconciliaton. + +:::info Working iteratively +We recommend planning your reconciliation operations as iterative: reconcile multiple times with different settings, and with different subgroups of your data. +::: + +## Sources {#sources} + +Start with [this current list of reconcilable authorities](https://reconciliation-api.github.io/testbench/), which includes instructions for adding new services via Wikidata editing if you have one to add. + +OpenRefine maintains a [further list of sources on the wiki](https://github.com/OpenRefine/OpenRefine/wiki/Reconcilable-Data-Sources), which can be edited by anyone. This list includes ways that you can reconcile against a [local dataset](https://github.com/OpenRefine/OpenRefine/wiki/Reconcilable-Data-Sources#local-services). + +Other services may exist that are not yet listed in these two places: for example, the [310 datasets hosted by the Organized Crime and Corruption Reporting Project (OCCRP)](https://aleph.occrp.org/datasets/) each have their own reconciliation URL, or you can reconcile against their entire database with the URL [shared on the reconciliation API list](https://reconciliation-api.github.io/testbench/). For another example, you can reconcile against the entire Virtual International Authority File (VIAF) dataset, or [only the contributions from certain institutions](http://refine.codefork.com/). Search online to see if the authority you wish to reconcile against has an available service, or whether you can download a copy to reconcile against locally. + +OpenRefine includes Wikidata reconciliation in the installation package - see the [Wikibase](wikibase/reconciling) page for more information particular to that service. Extensions can add reconciliation services, and can also add enhanced reconciliation capacities. Check the list of extensions on the [Downloads page](https://openrefine.org/download.html) for more information. + +Each source will have its own documentation on how it provides reconciliation. The table on [the reconciliation API list](https://reconciliation-api.github.io/testbench/) indicates whether your chosen service supports the features described below. Refer to the service's documentation if you have questions about its behaviors and which OpenRefine features it supports. + +In addition to the reconciliation services mentioned above, you may also choose to build your own service. You can either start from scratch using the [API specification](https://reconciliation-api.github.io/specs/latest/) or use one of the frameworks mentioned in the [Reconciliation census](https://reconciliation-api.github.io/census/services/). + +Of particular note is [reconcile-csv](http://okfnlabs.org/reconcile-csv/) which allows you to build a reconciliation service from a simple CSV file. Thus if you wanted to reconcile one OpenRefine project against another, you'd simply need to export the target project as a CSV, point `reconcile-csv` at it and you're good to go. A somewhat newer port of this project written in Python can be found at [csv-reconcile](https://github.com/gitonthescene/csv-reconcile) which is more configurable and defaults to parsing tab separated files for convenience. + +Similiarly, you may choose to export some SPARQL output to a TSV to limit the scope of values you're reconciling against and/or for better peformance. + +## Getting started {#getting-started} + +Choose a column to reconcile and use its dropdown menu to select Reconcile → Start reconciling. If you want to reconcile only some cells in that column, first use filters and facets to isolate them. + +In the reconciliation window, you will see Wikidata offered as a default service. To add another service, click Add Standard Service... and paste in the URL of a [service](#sources). You should see the name of the service appear in the list of Services if the URL is correct. + +![The reconciliation window.](/img/reconcilewindow.png) + +Once you select a service, your selected column may be sampled in order to suggest [“types†(categories)](#reconciling-by-type) to reconcile against. Other services will suggest their available types without sampling, and some services have no types. + +For example, if you had a list of artists represented in a gallery collection, you could reconcile their names against the Getty Research Institute’s [Union List of Artist Names (ULAN)](https://www.getty.edu/research/tools/vocabularies/ulan/). The same [Getty reconciliation URL](https://services.getty.edu/vocab/reconcile/) will offer you ULAN, AAT (Art and Architecture Thesaurus), and TGN (Thesaurus of Geographic Names). + +![The reconciliation window with types.](/img/reconcilewindow2.png) + +Refer to the [documentation specific to the reconciliation service](https://reconciliation-api.github.io/testbench/) to learn whether types are offered, which types are offered, and which one is most appropriate for your column. You may wish to facet your data and reconcile batches against different types if available. + +Reconciliation can be a time-consuming process, especially with large datasets. We suggest starting with a small test batch. There is no throttle (delay between requests) to set for the reconciliation process. The amount of time will vary for each service, and vary based on the options you select during the process. + +When the process is done, you will see the reconciliation data in the cells. +If the cell was successfully matched, it displays text as a single dark blue link. In this case, the reconciliation is confident that the match is correct, and you should not have to check it manually. +If there is no clear match, one or more candidates are displayed, together with their reconciliation score, with the text in light blue links. You will need to select the correct one. + +For each matching decision you make, you have two options: match this cell only (one checkmark), or also use the same identifier for all other cells containing the same original string (two checkmarks). + +For services that offer the [“preview entities†feature](https://reconciliation-api.github.io/testbench/), you can hover your mouse over the suggestions to see more information about the candidates or matches. Each participating service (and each type) will deliver different structured data that may help you compare the candidates. + +For example, the Getty ULAN shows an artist’s discipline, nationality, and birth and death years: + +![Hovering over matches.](/img/reconcilehover.png) + +Hovering over the suggestion will also offer the two matching options as buttons. + +For matched values (those appearing as dark blue links), the underlying cell value has not been altered - the cell is storing both the original string and the matched entity link at the same time. If you were to copy your column to a new column at this point using `value`, for example, the reconcilation data would not transfer - only the original strings. You can learn more about how OpenRefine stores different pieces of information in each cell in [the Variables section specific to reconciliation data](expressions#reconciliation). + +For each cell, you can manually “Create new item,†which will take the cell’s original value and apply it, as though it is a match. This will not become a dark blue link, because at this time there is nothing to link to: it is a draft entity stored only in your project. You can use this feature to prepare these entries for eventual upload to an editable service such as [Wikibase](wikibase/overview), but most services do not yet support this feature. + +### Reconciliation facets {#reconciliation-facets} + +Under Reconcile → Facets there are a number of reconciliation-specific faceting options. OpenRefine automatically creates two facets when you reconcile some cells. + +One is a numeric facet for “best candidate's score,†the range of reconciliation scores of only the best candidate of each cell. Higher scores mean better matches, although each service calculates scores differently and has a different range. You can facet for higher scores using the numeric facet, and then approve them all in bulk, by using Reconcile → [Actions](#reconciliation-actions) → Match each cell to its best candidate. + +There is also a “judgment†facet created, which lets you filter for the cells that haven't been matched (pick “none†in the facet). As you process each cell, its judgment changes from “none†to “matched†and it disappears from the view. + +You can add other facets by selecting Reconcile → Facets on your reconciled column. You can facet by: + +* your judgments (“matched,†or “none†for unreconciled cells, or “new†for entities you've created) +* the action you’ve performed on that cell (chosen a “single†match, or set a “mass†match, or no action, which appears as “unknownâ€) +* the timestamps on the edits you’ve made so far (these appear as millisecond counts since an arbitrary point: they can be sorted alphabetically to move forward and back in time). + +You can facet only the best candidates for each cell, based on: +* the score (calculated based on each service's own methods) +* the edit distance (using the [Levenshtein distance](cellediting#nearest-neighbor), a number based on how many single-character edits would be required to get your original value to the candidate value, with a larger value being a greater difference) +* the word similarity. + +Word similarity is calculated as a percentage based on how many words (excluding [stop words](https://en.wikipedia.org/wiki/Stop_word)) in the original value match words in the candidate. For example, the value “Maria Luisa Zuloaga de Tovar†matched to the candidate “Palacios, Luisa Zuloaga de†results in a word similarity value of 0.6, or 60%, or 3 out of 5 words. Cells that are not yet matched to one candidate will show as 0.0). + +You can also look at each best candidate’s: +* type (the ones you have selected in successive reconciliation attempts, or other types returned by the service based on the cell values) +* type match (“true†if you selected a type and it succeeded, “false†if you reconciled against no particular type, and “(no type)†if it didn’t reconcile) +* name match (“true†if you’ve matched, “false†if you haven’t yet chosen from the candidates, or “(unreconciled)†if it didn’t reconcile). + +These facets are useful for doing successive reconciliation attempts, against different types, and with different supplementary information. The information represented by these facets are held in the cells themselves and can be called using the [reconciliation variables](expressions#reconciliation) available in expressions. + +### Reconciliation actions {#reconciliation-actions} + +You can use the Reconcile → Actions menu options to perform bulk changes (which will apply only to your currently viewed set of rows or records): +* Match each cell to its best candidate (by highest score) +* Create a new item for each cell (discard any suggested matches) +* Create one new item for similar cells (a new entity will be created for each unique string) +* Match all filtered cells to... (a specific item from the chosen service, via a search box; only works with services that support the “suggest entities†property) +* Discard all reconciliation judgments (reverts back to multiple candidates per cell, including cells that may have been auto-matched in the original reconciliation process) +* Clear reconciliation data, reverting all cells back to their original values. + +The other options available under Reconcile are: +* Copy reconciliation data... (to an existing column: if the original values in your reconciliation column are identical to those in your chosen column, the matched and new cells will copy over; unmatched values will not change) +* [Use values as identifiers](#reconciling-with-unique-identifiers) (if you are reconciling with unique identifiers instead of by doing string searches) +* [Add entity identifiers column](#add-entity-identifiers-column). + +## Reconciling with unique identifiers {#reconciling-with-unique-identifiers} + +Reconciliation services use unique identifiers for their entities. For example, the 14th Dalai Lama has the VIAF ID [38242123](https://viaf.org/viaf/38242123/) and the Wikidata ID [Q17293](https://www.wikidata.org/wiki/Q37349). You can supply these identifiers directly to your chosen reconciliation service in order to pull more data, but these strings will not be “reconciled†against the external dataset. + +Select the column with unique identifiers and apply the operation Reconcile → Use values as identifiers. This will bring up the list of reconciliation services you have already added (to add a new service, open the Start reconciling... window first). If you use this operation on a column of IDs, you will not have access to the usual reconciliation settings. + +Matching identifiers does not validate them. All cells will appear as dark blue “confirmed†matches. You should check before this operation that the identifiers in the column exist on the target service. + +You may get false positives, which you will need to hover over or click on to identify: + +![Hovering over an error.](/img/reconcileIDerror.png) + +## Reconciling by type {#reconciling-by-type} + +Reconciliation services, once added to OpenRefine, may suggest types from their databases. These types will usually be whatever the service specializes in: people, events, places, buildings, tools, plants, animals, organizations, etc. + +Reconciling against a type may be faster and more accurate, but may result in fewer matches. Some services have hierarchical types (such as “mammal†as a subtype of “animalâ€). When you reconcile against a more specific type, unmatched values may fall back to the broader type; other services will not do this, so you may need to perform successive reconciliation attempts against different types. Refer to the documentation specific to the reconciliation service to learn more. + +When you select a service from the list, OpenRefine will load some or all available types. Some services will sample the first ten rows of your column to suggest types (check the [“Suggest types†column](https://reconciliation-api.github.io/testbench/)). You will see a service’s types in the reconciliation window: + +![Reconciling using a type.](/img/reconcile-by-type.png) + +In this example, “Person†and “Corporate Name†are potential types offered by the reconciliation API for VIAF. You can also use the Reconcile against type: field to enter in another type that the service offers. When you start typing, this field may search and suggest existing types. For VIAF, you could enter “/book/book†if your column contained publications. You may need to enter the service's own strings precisely instead of attempting to search for a match. + +Types are structured to fit their content: the Wikidata “human†type, for example, can include fields for birth and death dates, nationality, etc. The VIAF “person†type can include nationality and gender. You can use this to [include more properties](#reconciling-with-additional-columns) and find better matches. + +If your column doesn’t fit one specific type offered, you can Reconcile against no particular type. This may take longer. + +We recommend working in batches and reconciling against different types, moving from specific to broad. You can create a facet for Best candidate’s types facet to see which types are being represented. Some candidates may return more than one type, depending on the service. Types may appear in facets by their unique IDs, rather than by their semantic labels (for example, Q5 for “human†in Wikidata). + +## Reconciling with additional columns {#reconciling-with-additional-columns} + +Some of your cells may be ambiguous, in the sense that a string can point to more than one entity: there are dozens of places called “Paris†and many characters, people, and pieces of culture, too. Selecting non-geographic or more localized types can help narrow that down, but if your chosen service doesn't provide a useful type, you can include more properties that make it clear whether you're looking for Paris, France. + +![Reconciling sometimes turns up ambiguous matches.](/img/reconcileParis.gif) + +Including supplementary information can be useful, depending on the service (such as including birthdate information about each person you are trying to reconcile). You can re-reconcile unmatched cells with additional properties, in the right side of the Start reconciling window, under “Also use relevant details from other columns.†The column names in your project will appear in the reconciliation window, with an Include? checkbox next to each one. + +Fill in the As Property field with the type of information you are including. When you start typing, potential fields may pop up (depending on the [“suggest properties†feature](https://reconciliation-api.github.io/testbench/)), such as “birthDate†in the case of ULAN or “Geburtsdatum†in the case of Integrated Authority File (GND). Use the documentation for your chosen service to identify the fields in their terms. + +Some services will not be able to search for the exact name of your desired As Property entry, but you can still manually supply the field name. Refer to the service to choose the most appropriate field, and make sure you enter it correctly. + +![Including a birth-date type.](/img/reconcile-with-property.png) + +## Fetching more data {#fetching-more-data} + +One reason to reconcile to some external service is that it allows you to pull data from that service into your OpenRefine project. There are three ways to do this: + +* Add identifiers for your values +* Add columns from reconciled values +* Add column by fetching URLs. + +### Add entity identifiers column {#add-entity-identifiers-column} + +Once you have selected matches for your cells, you can retrieve the unique identifiers for those cells and create a new column for these, with Reconcile → Add entity identifiers column. You will be asked to supply a column name. New items and other unmatched cells will generate null values in this column. + +### Add columns from reconciled values {#add-columns-from-reconciled-values} + +If the reconciliation service supports [data extension](https://reconciliation-api.github.io/testbench/), then you can augment your reconciled data with new columns using Edit column → Add columns from reconciled values.... + +For example, if you have a column of chemical elements identified by name, you can fetch categorical information about them such as their atomic number and their element symbol: + +![A screenshare of elements fetching related information.](/img/reconcileelements.gif) + +Once you have chosen reconciliation matches for your cells, selecting Add column from reconciled values... will bring up a window to choose which related information you’d like to import into new columns. You can manually enter desired properties, or select from a list of suggestions. + +The quality of the suggested properties will depend on how you have reconciled your data beforehand: reconciling against a specific type will provide you with the associated properties of that type. For example, GND suggests elements about the “people†type after you've reconciled with it, such as their parents, native languages, children, etc. + +![A screenshot of available properties from GND.](/img/reconcileGND.png) + +If you have left any values unreconciled in your column, you will see “<not reconciled>†in the preview. These will generate blank cells if you continue with the column addition process. + +This process may pull more than one property per row in your data (such as multiple occupations), so you may need to switch into records mode after you've added columns. + +### Add columns by fetching URLs {#add-columns-by-fetching-urls} + +If the reconciliation service cannot extend data, look for a generic web API for that data source, or a structured URL that points to their dataset entities via unique IDs (such as “https://viaf.org/viaf/000000â€). You can use the Edit column → [Add column by fetching URLs](columnediting#add-column-by-fetching-urls) operation to call this API or URL with the IDs obtained from the reconciliation process. This will require using [expressions](expressions). + +You may not want to pull the entire HTML content of the pages at the ends of these URLs, so look to see whether the service offers a metadata endpoint, such as JSON-formatted data. You can either use a column of IDs, or you can pull the ID from each matched cell during the fetching process. + +For example, if you have reconciled artists to the Getty's ULAN, and [have their unique ULAN IDs as a column](#add-entity-identifiers-column), you can generate a new column of JSON-formatted data by using Add column by fetching URLs and entering the GREL expression `"http://vocab.getty.edu/" + value + ".json"`. For this service, the unique IDs are formatted “ulan/000000†and so the generated URLs look like “http://vocab.getty.edu/ulan/000000.jsonâ€. + +Alternatively, you can insert the ID directly from the matched column's reconciliation variables, using a GREL expression like `“http://vocab.getty.edu/†+ cell.recon.match.id + “.jsonâ€` instead. + +Remember to set an appropriate throttle and to refer to the service documentation to ensure your compliance with their terms. See [the section about this operation](columnediting#add-column-by-fetching-urls) to learn more about the fetching process. + +## Keep all the suggestions made {#keep-all-the-suggestions-made} + +To generate a list of each suggestion made, rather than only the best candidate, you can use a [GREL expression](expressions#GREL). Go to Edit column → Add column based on this column. To create a list of all the possible matches, use something like + +``` +forEach(cell.recon.candidates,c,c.name).join(", ") +``` + +To get the unique identifiers of these matches instead, use + +``` +forEach(cell.recon.candidates,c,c.id).join(", ") +``` + +This information is stored as a string, without any attached reconciliation information. + +## Writing reconciliation expressions {#writing-reconciliation-expressions} + +OpenRefine supplies a number of variables related specifically to reconciled values. These can be used in GREL and Jython expressions. For example, some of the reconciliation variables are: + +* `cell.recon.match.id` or `cell.recon.match.name` for matched values +* `cell.recon.best.name` or `cell.recon.best.id` for best-candidate values +* `cell.recon.candidates` for all listed candidates of each cell +* `cell.recon.judgment` (the values used in the “judgment†facet) +* `cell.recon.judgmentHistory` (the values used in the “judgment action timestamp†facet) +* `cell.recon.matched` (a “true†or “false†value) + +You can find out more in the [reconciliaton variables](expressions#reconciliaton-variables) section. + +## Exporting reconciled data {#exporting-reconciled-data} + +Once you have data that is reconciled to existing entities online, you may wish to export that data to a user-editable service such as Wikidata. See the section on [uploading your edits to Wikidata or other Wikibase instances](wikibase/uploading) for more information, or the section on [exporting](exporting) to see other formats OpenRefine can produce. + +You can share reconciled data in progress through a [project export or import](exporting#export-a-project), with some preparation. The importing user needs to have the appropriate reconciliation services installed on their OpenRefine instance (by going to Start reconciling and clicking on Add Standard Service...) in advance of opening the project, in order to use candidate and match links. Otherwise, the links will be broken and the user will need to add the reconciliation service and re-reconcile the columns in question. [Wikidata](wikibase/reconciling) reconciliation data can be shared more easily as the service comes bundled with OpenRefine. diff --git a/OpenRefine/docs/docs/manual/running.md b/OpenRefine/docs/docs/manual/running.md new file mode 100644 index 000000000..e23317562 --- /dev/null +++ b/OpenRefine/docs/docs/manual/running.md @@ -0,0 +1,509 @@ +--- +id: running +title: Running OpenRefine +sidebar_label: Running +--- + +## Starting and exiting {#starting-and-exiting} + +OpenRefine does not require internet access to run its basic functions. Once you download and install it, it runs as a small web server on your own computer, and you access that local web server by using your browser. + +You will see a command line window open when you run OpenRefine. Ignore that window while you work on datasets in your browser. + +No matter how you start OpenRefine, it will load its interface in your computer’s default browser. If you would like to use another browser instead, start OpenRefine and then point your chosen browser at the home screen: [http://127.0.0.1:3333/](http://127.0.0.1:3333/). + +OpenRefine works best on browsers based on Webkit, such as: +* Google Chrome +* Chromium +* Opera +* Microsoft Edge + +We are aware of some minor rendering and performance issues on other browsers such as Firefox. We don't support Internet Explorer. + +You can view and work on multiple projects at the same time by simply having multiple tabs or browser windows open. From the Open Project screen, you can right-click on project names and open them in new tabs or windows. + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + + +#### With openrefine.exe {#with-openrefineexe} +You can run OpenRefine by double-clicking `openrefine.exe` or calling it from the command line. + +If you want to [modify the way `openrefine.exe` opens](#starting-with-modifications), you can edit the `openrefine.l4j.ini` file. + +#### With refine.bat {#with-refinebat} +On Windows, OpenRefine can also be run by using the file `refine.bat` in the program directory. If you start OpenRefine using `refine.bat`, you can do so by opening the file itself, or by calling it from the command line. + +If you call `refine.bat` from the command line, you can [start OpenRefine with modifications](#starting-with-modifications). +If you want to modify the way `refine.bat` opens through double-clicking or using a shortcut, you can edit the `refine.ini` file. + +#### Exiting {#exiting} + +To exit OpenRefine, close all the browser tabs or windows, then navigate to the command line window. To close this window and ensure OpenRefine exits properly, hold down `Control` and press `C` on your keyboard. This will save any last changes to your projects. + + + + + +You can find OpenRefine in your Applications folder, or you can open it using Terminal. + +To run OpenRefine using Terminal: +* Find the OpenRefine application / icon in Finder +* Control-click on the icon and select “Show Package Contents†from the context menu +* This should open a new Finder menu: navigate into the “MacOS†folder +* Control-click on “JavaAppLauncher†+* Choose “Open With†from the menu, and select “Terminal.†+ +To exit, close all your OpenRefine browser tabs, go back to the terminal window and press `Command` and `Q` to close it down. + +:::caution Problems starting? +If you are using an older version of OpenRefine or are on an older version of MacOS, [check our Wiki for solutions to problems with MacOS](https://github.com/OpenRefine/OpenRefine/wiki/Installation-Instructions#macos). +::: + + + + + +Use a terminal to launch OpenRefine. First, navigate to the installation folder. Then call the program: + +``` +cd openrefine-3.4.1 + ./refine +``` + +This will start OpenRefine and open your browser to the home screen. + +To exit, close all the browser tabs, and then press `control` and `C` in the terminal window. + +:::caution Did you get a JAVA_HOME error? +“Error: Could not find the ‘java’ executable at ‘’, are you sure your JAVA_HOME environment variable is pointing to a proper java installation?†+ +If you see this error, you need to [install and configure a JDK package](installing#linux), including setting up `JAVA_HOME`. +::: + + + + + +--- + +### Troubleshooting {#troubleshooting} + +If you are having problems connecting to OpenRefine with your browser, [check our Wiki for information about browser settings and operating-system issues](https://github.com/OpenRefine/OpenRefine/wiki/FAQ#i-am-having-trouble-connecting-to-openrefine-with-my-browser). + +### Starting with modifications {#starting-with-modifications} + +When you run OpenRefine from a command line, you can change a number of default settings. + + + + + +On Windows, use a slash: + +``` +C:>refine /i 127.0.0.2 /p 3334 +``` + +Get a list of all the commands with `refine /?`. + +|Command|Use|Syntax example| +|---|---|---| +|/w|Path to the webapp|refine /w /path/to/openrefine| +|/m|Memory maximum heap|refine /m 6000M| +|/p|Port|refine /p 3334| +|/i|Interface (IP address, or IP and port)|refine /i 127.0.0.2:3334| +|/H|HTTP host to expect on incoming requests|refine /H openrefine.internal| +|/d|Enable debugging (on port 8000)|refine /d| +|/x|Enable JMX monitoring for Jconsole and JvisualVM|refine /x| + + + + + +You cannot start the Mac version with modifications using Terminal, but you can modify the way the application starts with [settings within files](#modifications-set-within-files). + + + + + +To see the full list of command-line options, run `./refine -h`. + +|Command|Use|Syntax example| +|---|---|---| +|-w|Path to the webapp|./refine -w /path/to/openrefine| +|-d|Path to the workspace|./refine -d /where/you/want/the/workspace| +|-m|Memory maximum heap|./refine -m 6000M| +|-p|Port|./refine -p 3334| +|-i|Interface (IP address, or IP and port)|./refine -i 127.0.0.2:3334| +|-H|HTTP host to expect on incoming requests|./refine -H openrefine.internal| +|-k|Add a Google API key|./refine -k YOUR_API_KEY| +|-v|Verbosity (from low to high: error,warn,info,debug,trace)|./refine -v info| +|-x|Additional Java configuration parameters (see Java documentation)|| +|--debug|Enable debugging (on port 8000)|./refine --debug| +|--jmx|Enable JMX monitoring for Jconsole and JvisualVM|./refine --jmx| + + + + + +--- + +#### Modifications set within files {#modifications-set-within-files} + +On Windows, you can modify the way `openrefine.exe` runs by editing `openrefine.l4j.ini`; you can modify the way `refine.bat` runs by editing `refine.ini`. + +You can modify the Mac application by editing `info.plist`. + +On Linux, you can edit `refine.ini`. + +Some settings, such as changing memory allocations, are already set inside these files, and all you have to do is change the values. Some lines need to be un-commented to work. + +For example, inside `refine.ini`, you should see: +``` +no_proxy="localhost,127.0.0.1" +#REFINE_PORT=3334 +#REFINE_HOST=127.0.0.1 +#REFINE_WEBAPP=main\webapp + +# Memory and max form size allocations +#REFINE_MAX_FORM_CONTENT_SIZE=1048576 +REFINE_MEMORY=1400M + +# Set initial java heap space (default: 256M) for better performance with large datasets +REFINE_MIN_MEMORY=1400M +... +``` + +##### JVM preferences {#jvm-preferences} + +Further modifications can be performed by using JVM preferences. These JVM preferences are different options and have different syntax than the key/value descriptions used on the command line. + +Some of the most common keys (with their defaults) are: +* The project [autosave](starting#autosaving) frequency: `-Drefine.autosave` (5 [minutes]) +* The workspace director: `-Drefine.data_dir` (/) +* Development mode: `-Drefine.development` (false) +* Headless mode: `-Drefine.headless` (false) +* IP: `-Drefine.host` (127.0.0.1) +* Port: `-Drefine.port` (3333) +* The application folder: `-Drefine.webapp` (main/webapp) + +The syntax is as follows: + + + + + +Locate the `refine.l4j.ini` file, and insert lines in this way: + +``` +-Drefine.port=3334 +-Drefine.host=127.0.0.2 +-Drefine.webapp=broker/core +``` + +In `refine.ini`, use a similar syntax, but set multiple parameters within a single line starting with `JAVA_OPTIONS=`: + +``` +JAVA_OPTIONS=-Drefine.data_dir=C:\Users\user\Documents\OpenRefine\ -Drefine.port=3334 + +``` + + + + +Locate the `info.plist`, and find the `array` element that follows the line + +``` +JVMOptions +``` + +Typically this looks something like: + +``` +JVMOptions + +-Xms256M +-Xmx1024M +-Drefine.version=2.6-beta.1 +-Drefine.webapp=$APP_ROOT/Contents/Resource/webapp + +``` + +Add in values such as: + +``` +JVMOptions + +-Xms256M +-Xmx1024M +-Drefine.version=2.6-beta.1 +-Drefine.webapp=$APP_ROOT/Contents/Resource/webapp +-Drefine.autosave=2 +-Drefine.port=3334 + + +``` + + + + + +Locate the `refine.ini` file, and add `JAVA_OPTIONS=` before the `-Drefine.preference` declaration. You can un-comment and edit the existing suggested lines, or add lines: + +``` +JAVA_OPTIONS=-Drefine.autosave=2 +JAVA_OPTIONS=-Drefine.port=3334 +JAVA_OPTIONS=-Drefine.data_dir=usr/lib/OpenRefineWorkspace +``` + + + + + + +--- + +Refer to the [official Java documentation](https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html) for more preferences that can be set. + +## The home screen {#the-home-screen} + +When you first launch OpenRefine, you will see a screen with a menu on the left hand side that includes Create Project, Open Project, Import Project, and Language Settings. This is called the “home screen,†where you can manage your projects and general settings. + +In the lower left-hand corner of the screen, you'll see Preferences, Help, and About. + +### Language settings {#language-settings} + +From the home screen, look in the options to the left for Language Settings. You can set your preferred interface language here. This language setting will persist until you change it again in the future. Languages are translated as a community effort; some languages are partially complete and default back to English where unfinished. Currently OpenRefine supports the following languages for 75% or more of the interface: + +* Cebuano +* German +* English (UK) +* English (US) +* Spanish +* Filipino +* French +* Hebrew +* Magyar +* Italian +* Japanese (日本語) +* Portuguese (Brazil) +* Tagalog +* Chinese (简体中文) + +To leave the Language Settings screen, click on the diamond “OpenRefine†logo. + +:::info Help us Translate OpenRefine +We use Weblate to provide translations for the interface. You can check [our profile on Weblate](https://hosted.weblate.org/projects/openrefine/translations/) to see which languages are in the process of being supported. See [our technical reference if you are interested in contributing translation work](../technical-reference/translating-ui) to make OpenRefine accessible to people in other languages. +::: + +### Preferences {#preferences} + +In the bottom left corner of the screen, look for Preferences. At this time you can set preferences using a key/value pair: that is, selecting one of the keys below and setting a value for it. + +|Setting|Key|Value syntax|Default|Example|Version| +|---|---|---|---|---|---| +|Interface language|userLang|[ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) two-digit code|en|fr|—| +|Maximum facets|ui.browsing.listFacet.limit|Number|2000|5000|—| +|Timeout for Google Drive import|googleReadTimeOut|Number (microseconds)|180000|500000|—| +|Timeout for Google Drive authorization|googleConnectTimeOut|Number (microseconds)|180000|500000|—| +|Maximum lag for Wikibase edit retries|wikibase.upload.maxLag|Number (seconds)|5|10|—| +|Display of the reconciliation preview on hover|cell-ui.previewMatchedCells|Boolean|true|false|v3.2| +|Values for the choice of the number of rows to display|ui.browsing.pageSize|Array of number (JSON)|[ 5, 10, 25, 50 ]|[ 100,500,1000 ]|v3.4| +|Width of the panel for facets/history|ui.browsing.facetsHistoryPanelWidth|Number (pixel)|300|500|v3.5| + +To leave the Preferences screen, click on the diamond “OpenRefine†logo. + +If the preference you’re looking for isn’t here, look at the options you can set from the [command line or in an `.ini` file](#starting-with-modifications). + +## The project screen {#the-project-screen} + +The project screen (or work screen) is where you will spend most of your time once you have [begun to work on a project](starting). This is a quick walkthrough of the parts of the interface you should familiarize yourself with. + +![A screenshot of the project screen.](/img/projectscreen.png) + +### The project bar {#the-project-bar} + +The project bar runs across the very top of the project screen. It contains the the OpenRefine logo, the project title, and the project control buttons on the right side. + +At any time you can close your current project and go back to the home screen by clicking on the OpenRefine logo. If you’d like to open another project in a new browser tab or window, you can right-click on the logo and use “Open in a new tab.†You will lose [your current facets and view settings](#facetfilter) if you close your project (but data transformations will be saved in the [History](#history-undoredo) of the project). + +:::caution +Don’t click the “back†button on your browser - it will likely close your current project and you will lose your facets and view settings. +::: + +You can rename a project at any time by clicking inside the project title, which will turn into a text field. Project names don’t have to be unique, as OpenRefine organizes them based on a unique identifier behind the scenes. + +The Permalink allows you to return to a project at a specific view state - that is, with [facets and filters](facets) applied. The Permalink can help you pick up where you left off if you have to close your project while working with facets and filters. It puts view-specific information directly into the URL: clicking on it will load this current-view URL in the existing tab. You can right-click and copy the Permalink URL to copy the current view state to your clipboard, without refreshing the tab you’re using. + +The Open… button will open up a new browser tab showing the Create Project screen. From here you can change settings, start a new project, or open an existing project. + +Export is a dropdown menu that allows you to pick a format for exporting a dataset. Many of the export options will only export rows and records that are currently visible - the currently selected facets and filters, not the total data in the project. + +Help will open up a new browser tab and bring you to this user manual on the web. + +### The grid header {#the-grid-header} + +The grid header sits below the project bar and above the project grid (where the data of your project is displayed). The grid header will tell you the total number of rows or records in your project, and indicate whether you are in [rows or records mode](exploring#rows-vs-records). + +It will also tell you if you’re currently looking at a select number of rows via facets or filtering, rather than the entire dataset, by displaying either, for example, “180 rows†or “67 matching rows (180 total).†+ +Directly below the row number, you have the ability to switch between [row mode and records mode](exploring#rows-vs-records). OpenRefine stores projects persistently in one of the two modes, and displays your data as records by default if you are. + +To the right of the rows/records selection is the array of options for how many rows/records to view on screen at one time. At the far right of the screen you can navigate through your entire dataset one page at a time. + +### Extensions {#extensions} + +The Extensions dropdown offers you options for extending your data - most commonly by uploading your edited statements to Wikidata, or by importing or exporting schema. You can learn more about these functions on the [Wikibase section](wikibase/overview). Other extensions may also add functions to this dropdown menu. + +### The grid {#the-grid} + +The area of the project screen that displays your dataset is called the “grid†(or the “data grid,†or the “project gridâ€). The grid presents data in a tabular format, which may look like a normal spreadsheet program to you. + +Columns widths are automatically set based on their contents; some column headers may be cut off, but can be viewed by mousing over the headers. + +In each column header you will see a small arrow. Clicking on this arrow brings up a dropdown menu containing column-specific data exploration and transformation options. You will learn about each of these options in the [Exploring data](exploring) and [Transforming data](transforming) sections. + +The first column in every project will always be All, which contains options to flag, star, and do non-column-specific operations. The All column is also where rows/records are numbered. Numbering shows the permanent order of rows and records; a temporary sorting or facet may reorder the rows or show a limited set, but numbering will show you the original identifiers unless you make a permanent change. + +The project grid may display with both vertical and horizontal scrolling, depending on the number and width of columns, and the number of rows/records displayed. You can control the display of the project grid by using [Sort and View options](exploring#sort-and-view). + +Mousing over individual cells will allow you to [edit cells individually](cellediting#edit-one-cell-at-a-time). + +### Facet/Filter {#facetfilter} + +The Facet/Filter tab is one of the main ways of exploring your data: displaying the patterns and trends in your data, and helping you narrow your focus and modify that data. [Facets](facets) and [filters](facets#text-filter) are explained more in [Exploring data](exploring). + +![A screenshot of facets and filters in action.](/img/facetfilter.png) + +In the tab, you will see three buttons: Refresh, Reset all, and Remove all. + +Refreshing your facets will ensure you are looking at the latest information about each facet, for example if you have changed the counts or eliminated some options. + +Resetting your facets will remove any inclusion or exclusion you may have set - the facet options will stay in the sidebar, but your view settings will be undone. + +Removing your facets will clear out the sidebar entirely. If you have written custom facets using [expressions](expressions), these will be lost. + +You can preserve your facets and filters for future use by copying a [Permalink](#the-project-bar). + +### History (Undo/Redo) {#history-undoredo} + +In OpenRefine, any activity that changes the data can be undone. Changes are tracked from the very beginning, when a project is first created. The change history of each project is saved with the project's data, so quitting OpenRefine does not erase the steps you've taken. When you restart OpenRefine, you can view and undo changes that you made before you quit OpenRefine. OpenRefine [autosaves](starting#autosaving) your actions every five minutes by default, and when you close OpenRefine properly (using Ctrl + C). You can [change this interval](running#jvm-preferences). + +Project history gets saved when you export a project archive, and restored when you import that archive to a new installation of OpenRefine. + +![A screenshot of the History (Undo/Redo) tab with 13 steps.](/img/history.png "A screenshot of the History (Undo/Redo) tab with 13 steps.") + +When you click on the Undo / Redo tab in the sidebar of any project, that project’s history is shown as a list of changes in order, with the first “change†being the action of creating the project itself. (That first change, indexed as step zero, cannot be undone.) Here is a sample history with 3 changes: + +``` +0. Create project +1. Remove 7 rows +2. Create new column Last Name based on column Name with grel:value.split(" ") +3. Split 230 cell(s) in column Address into several columns by separator +``` + +The current state of the project is highlighted with a dark blue background. If you move back and forth on the timeline you will see the current state become highlighted, while the actions that came after that state will be grayed out. + +To revert your data back to an earlier state, simply click on the last action in the timeline you want to keep. In the example above, if we keep the removal of 7 rows but revert everything we did after that, then click on “Remove 7 rows.†The last 2 changes will be undone, in order to bring the project back to state #1. + +In this example, changes #2 and #3 will now be grayed out. You can redo a change by clicking on it in the history - everything up to and including it will be redone. + +If you have moved back one or more states, and then you perform a new operation on your data, the later actions (everything that’s greyed out) will be erased and cannot be re-applied. + +The Undo/Redo tab will indicate which step you’re on, and if you’re about to risk erasing work - by saying something like “4/5" or “1/7†at the end. + +#### Reusing operations {#reusing-operations} + +Operations that you perform in OpenRefine can be reused. For example, a formula you wrote inside one project can be copied and applied to another project later. + +To reuse one or more operations, first extract it from the project where it was first applied. Click to the Undo/Redo tab and click Extract…. This brings up a box that lists all operations up to the current state (it does not show undone operations). Select the operation or operations you want to extract using the checkboxes on the left, and they will be encoded as JSON on the right. Copy that JSON to the clipboard. + +Move to the second project, go to the Undo/Redo tab, click Apply… and paste in that JSON. + +Not all operations can be extracted. Edits to a single cell, for example, can’t be replicated. + +## Advanced OpenRefine uses {#advanced-openrefine-uses} + +### Running OpenRefine's Linux version on a Mac {#running-openrefines-linux-version-on-a-mac} + +You can run OpenRefine from the command line in Mac by using the Linux installation package. We do not promise support for this method. Follow the instructions in the Linux section. + +### Running as a server {#running-as-a-server} + +:::caution +Please note that if your machine has an external IP (is exposed to the Internet), you should not do this, or should protect it behind a proxy or firewall, such as nginx. Proceed at your own risk. +::: + +By default (and for security reasons), OpenRefine only listens to TCP requests coming from localhost (127.0.0.1) on port 3333. If you want to share your OpenRefine instance with colleagues and respond to TCP requests to any IP address of the machine, start it from the command line like this: +``` +./refine -i 0.0.0.0 +``` + +or set this option in `refine.ini`: +``` +REFINE_HOST=0.0.0.0 +``` + +or set this JVM option: +``` +-Drefine.host=0.0.0.0 +``` + +On Mac, you can add a specific entry to the `Info.plist` file located within the app bundle (`/Applications/OpenRefine.app/Contents/Info.plist`): +``` +JVMOptions + + + -Drefine.host=0.0.0.0 + … + +``` + +:::caution +OpenRefine has no built-in security or version control for multi-user scenarios. OpenRefine has a single data model that is not shared, so there is a risk of data operations being overwritten by other users. Care must be taken by users. +::: + +### Automating OpenRefine {#automating-openrefine} + +Some users may wish to employ OpenRefine for batch processing as part of a larger automated pipeline. Not all OpenRefine features can work without human supervision and advancement (such as clustering), but many data transformation tasks can be automated. + +:::caution +The following are all third-party extensions and code; the OpenRefine team does not maintain them and cannot guarantee that any of them work. +::: + +Some examples: + +* This project allows OpenRefine to be run from the command line using [operations saved in a JSON file](#reusing-operations): [OpenRefine batch processing](https://github.com/opencultureconsulting/openrefine-batch) +* A Python project for applying a JSON file of operations to a data file, outputting the new file, and deleting the temporary project, written by David Huynh and Max Ogden: [Python client library for Google Refine](https://github.com/maxogden/refine-python) +* And the same in Ruby: [Refine-Ruby](https://github.com/maxogden/refine-ruby) +* Another Python client library, by Paul Makepeace: [OpenRefine Python Client Library](https://github.com/PaulMakepeace/refine-client-py) + +To look for other instances, search our Google Groups [for users](https://groups.google.com/g/openrefine) and [for developers](https://groups.google.com/g/openrefine-dev), where [these projects were originally posted](https://groups.google.com/g/openrefine/c/GfS1bfCBJow/m/qWYOZo3PKe4J). diff --git a/OpenRefine/docs/docs/manual/sortview.md b/OpenRefine/docs/docs/manual/sortview.md new file mode 100644 index 000000000..fbb52717c --- /dev/null +++ b/OpenRefine/docs/docs/manual/sortview.md @@ -0,0 +1,41 @@ +--- +id: sortview +title: Sort and view +sidebar_label: Sort and view +--- + +## Sort {#sort} + +You can temporarily sort your rows by one column. You can sort based on [data type](exploring#data-types): +* text alphabetically or reverse +* numbers by largest or smallest +* dates by earliest or latest +* boolean values by false first or true first. + +You can also choose where to place errors and blank cells in the sorting. Text can be case-sensitive or not: if so, cells that start with lowercase characters will appear ahead of those that start with uppercase characters. + +![A screenshot of the Sort window.](/img/sort.png) + +After you apply a sorting method, you can make it permanent, remove it, reverse it, or apply a subsequent sorting. When it is applied, you’ll find Sort in the project grid header to the right of the rows-display setting, which will show all current sorting settings. + +If you have multiple sorting methods applied, they will work in the order you applied them (represented in order in the Sort menu). For example, you can sort an “authors†column alphabetically, and then sort their books by publication date, for those authors that have more than one book. If you apply those in a different order - sort all the publication dates in the dataset first, and then alphabetically by author - your dataset will look different. + +![Temporarily sorted rows.](/img/sort2.png) + +When the sorting method you've applied is temporary, you will see that the rows retain their original numbering. When you make that sorting method permanent, by selecting Reorder rows permanently, the row numbers will change and the Sort menu in the project grid header will disappear. This will apply all current sorting methods. + +## View {#view} + +You can control what data you view in the grid. On each column, you will see a View menu option. From there, you can “collapse†(hide) that specific column, all other columns, all columns to the left, and all columns to the right. Using the View option that appears in the All column’s dropdown menu, you can collapse all columns, and expand all the columns that you previously collapsed. + +### Show/hide “null†{#showhide-null} + +You can find, under All → View, the option to show and hide [“null†values](exploring#data-types). A small grey “null†will appear in each applicable cell. Remember that a null cell is not the same thing as an empty cell. + +![A screenshot of what a null value looks like.](/img/null.png) + +## Page navigation {#page-navigation} + +You can go directly to any page by changing the page number on the right-hand side. Using the up and down arrow keys in this input lets you go to the next and previous pages. You can also change the number of rows or records per page on the left-hand side of this view header bar. + +![A screenshot of the Page Navigation Feature.](/img/goto.png) diff --git a/OpenRefine/docs/docs/manual/starting.md b/OpenRefine/docs/docs/manual/starting.md new file mode 100644 index 000000000..f40ec237c --- /dev/null +++ b/OpenRefine/docs/docs/manual/starting.md @@ -0,0 +1,194 @@ +--- +id: starting +title: Starting a project +sidebar_label: Starting a project +--- + +## Overview {#overview} + +An OpenRefine project is started by importing in some existing data - OpenRefine doesn’t allow you to create a dataset from nothing. + +No matter where your data comes from, OpenRefine won’t modify your original data source. It copies all the information from your input, creates its own project file, and stores it in your [workspace directory](installing#set-where-data-is-stored). + +The data and all of your edits are [automatically saved](#autosaving) inside the project file. When you’re finished modifying the data, you can [export it back out](exporting) into the file format of your choice. + +You can also receive and open other people’s projects, or send them yours, by [exporting a project archive](exporting#export-a-project) and [importing it](#import-a-project). + +## Create a project by importing data {#create-a-project-by-importing-data} + +When you start OpenRefine, you’ll be taken to the Create Project screen. You’ll see on the left side of the screen that your options are to: + +* import data from one or more files on your computer +* import data from one or more links on the web +* import data by pasting in text from your clipboard +* import data from a database (using SQL), and +* import one or more Sheets from Google Drive. + +From these sources, you can load any of the following file formats: + +* comma-separated values (CSV) or text-separated values (TSV) +* Text files +* Fixed-width columns +* JSON +* XML +* OpenDocument spreadsheet (ODS) +* Excel spreadsheet (XLS or XLSX) +* PC-Axis (PX) +* MARC +* RDF data (JSON-LD, N3, N-Triples, Turtle, RDF/XML) +* Wikitext + +More formats can be imported by [adding extensions to provide that functionality](https://openrefine.org/download.html). + +If you supply two or more files for one project, the files’ rows will be loaded in the order that you specify, and OpenRefine will create a column at the beginning of the dataset with the source URL or file name in it to help you identify where each row came from. If the files have columns with identical names, the data will load in those columns; if not, the successive files will append all of their new columns to the end of the dataset: + +|File|Fruit|Quantity|Berry|Berry source| +|---|---|---|---|---| +|fruits.csv|Orange|4| +|fruits.csv|Apple|6| +|berries.csv||9|Mulberry|Greece| +|berries.csv||2|Blueberry|Canada| + +You cannot combine two datasets into one project by appending data within rows. You can, however, combine two projects later using functions such as [cross()](grelfunctions/#crosscell-s-projectname-s-columnname), or [fetch further data](columnediting) using other methods. + +For whichever method you choose to start your project, when you click Next >> you will be given a preview and a chance to configure the way OpenRefine interprets the data you input. + +### Get data from this computer {#get-data-from-this-computer} + +Click on Browse… and select a file (or several) on your hard drive. All files will be shown, not just compatible ones. + +If you import an archive file (something with the extension `.zip`, `.tar.gz`, `.tgz`, `.tar.bz2`, `.gz`, or `.bz2`), OpenRefine detects the files inside it, shows you a preview screen, and allows you to select which ones to load. This does not work with `.rar` files. When importing multiple archives you can store the name of the archive each file was extracted from by ticking the `Store archive file` option upon import. + +### Web addresses (URLs) {#web-addresses-urls} + +Type or paste the URL to a data file into the field provided. You can add as many fields as you want. OpenRefine will download the file and preview the project for you. + +If you supply two or more file URLs, OpenRefine will identify each one and ask you to choose which (or all) to load. + +Do not use this form to load a Google Sheet by its link; use [the Google Data form instead](#google-data). + +### Clipboard {#clipboard} + +You can copy and paste in data from anywhere. OpenRefine will recognize comma-separated, tab-separated, or table-formatted information copied from sources such as word-processing documents, spreadsheets, and tables in PDFs. You can also just paste in a list of items that you want to turn into rows. OpenRefine recognizes each new text line as a row. + +This can be useful if you want to pre-select a specific number of rows from your source data, or paste together rows from different places, rather than delete unwanted rows later in the project interace. + +This can also be useful if you would like to paste in a list of URLs, which you can use later to [fetch more data](columnediting). + +### Database (SQL) {#database-sql} + +If you are an administrator or have SQL access to a database of information, you may want to pull the latest dataset directly from there. This could include an online catalogue, a content management system, or a digital repository or collection management system. You can also load a database (`.db`) file saved locally. You will need to use an [SQL query](https://www.w3schools.com/sql/) to import your intended data. + +There are some publicly-accessible databases you can query, such as [one provided by Rfam](https://docs.rfam.org/en/latest/database.html). The instructions provided by Rfam can help you understand how to connect to and query from other databases. + +OpenRefine can connect to PostgreSQL, MySQL, MariaDB, and SQLite database systems. It will automatically populate the Port field based on which of these you choose, but you can manually edit this if needed. + +If you have a `.db` file, you can supply the path to the file on your computer in the Database field at the bottom of the form. You can leave the rest of the fields blank. + +To import data directly from a database, you will need the database type (such as MySQL), database name, the hostname (either an IP address or the domain that hosts the database), and the port on the host. You will need an account authorized for access, and you may need to add OpenRefine's IP address or host to the "allowable hosts" for that account. You can find that information by pressing Test and getting the IP address from the error message that results. + +You can either connect just once to gather data, or save the connection to use it again later. If you press Connect without saving, OpenRefine will forget all the information you just entered. If you’d like to save the connection, name your connection in a way you will recognize later. Click Save and it will appear in the Saved Connections list on the left. From now on, you can click on the ... ellipsis to the right of the connection you’ve saved, and click Connect. + +If your connection is successful, you will see a Query Editor where you can run your SQL query. OpenRefine will give you an error if you write a statement that tries to modify the source database in any way. + +### Google data {#google-data} + +You have two ways to load in data from Google Sheets: +* providing a link to an accessible Google Sheet (that is, one with link-sharing turned on), and +* selecting a Google Sheet in your Google Drive. + +#### Google Sheet by URL {#google-sheet-by-url} + +You can import data from any Google Sheet that has link-sharing turned on. Paste in a URL that looks something like + +``` +https://docs.google.com/spreadsheets/………/edit?usp=sharing +``` + +This will only work with Sheets, not with any other Google Drive file that might have an available link, including `.xls` and other valid files that are hosted in Google Drive. These links will not work when attempting to start a project [by URL](#web-addresses-urls) either, so you need to download those files to your computer. + +#### Google Sheet from Drive {#google-sheet-from-drive} + +You can authorize OpenRefine to access your Google Drive data and import data from any Google Sheet it finds there. This will include Sheets that belong to you and Sheets that are shared with you, as well as Sheets that are in your trash. + +When you select a Google option (either here, or [when exporting project data to Google Drive or Google Sheets](exporting), you will see a pop-up window that asks you to select a Google account to authorize with. You may see an error message when you authorize: if so, try your import or export operation again and it should succeed. + +OpenRefine will not show spreadsheets that are in your email inbox or stored in any other Google property - only in Drive. It also won’t show all compatible file formats, only Sheets files. + +OpenRefine will generate a list of all Sheets it finds, with the most recently modified Sheets at the top. If a file you’ve just added isn’t showing in this list, you can close and restart OpenRefine, or simply navigate to an existing project, open it, then head back to the Create Project window and check again. + +When you click Preview the Sheet will open in a new browser tab. When you click the Sheet title, OpenRefine will begin to process the data. + + +## Project preview {#project-preview} + +Once OpenRefine is ready to import the data, you will see a screen with Configure Parsing Options at the top. You’ll see a preview of the first 100 rows and all identified columns. + +At the bottom of the screen you will find options for telling OpenRefine how to process what it has found. You can tell it which row(s) to parse as column headers, as well as to ignore any number of rows at the top. You can also select a specific range of rows to work with, by discarding some rows at the top (excluding the header) and limiting the total number of rows it loads. + +OpenRefine tries to guess how to parse your data based on the file extension. For example, `.xml` files are going to be parsed as though they are formatted in XML. An unknown file extension (or your clipboard copy-paste) is assumed to be either tab-separated or comma-separated. OpenRefine looks for a tab character, and if one is found, it assumes you have imported tab-separated data. + +If OpenRefine isn’t certain what format you imported, it will provide a list of possibilities under Parse data as and some settings. You can specify a custom separator now, or split columns later while [transforming your data](transforming). + +If you imported a spreadsheet with multiple worksheets, they will be listed along with the number of rows they contain. You can only select data from one worksheet. + +Note that OpenRefine does not preserve any formatting, such as cell or text colour, that my have been in the original data file. Hyperlinked text will be input as plain text, but OpenRefine will recognize links and make them clickable inside the project interface. + +:::info Encoding issues? +Look for character encoding issues at this stage. You may want to manually select an encoding, such as UTF-8, UTF-16, or ASCII, if OpenRefine does not display some characters correctly in the preview. Once your project is created, you can specify another encoding for specific columns using the [reinterpret() function](grelfunctions#reinterprets-s-encoder). +::: + +You should create a project name at this stage. You can also supply tags to keep your projects organized. When you’re happy with the preview, click Create Project. + + +## Import a project {#import-a-project} + +Because OpenRefine only runs locally on your computer, you can’t have a project accessible to more than one person at the same time. + +The best way to collaborate with another person is to export and import projects that save all your changes, so that you can pick up where someone else left off. You can also [export projects](exporting#export-a-project) and import them to other computers, such as for working on the same project from the office and from home. + +An exported project will include all of the [history](running#history-undoredo), so you can see (and undo) all the changes from the previous user. It is essentially a point-in-time snapshot of their work. OpenRefine only exports projects as `.tar.gz` files at this time. +:::caution +If you wish to hide the original state of your data and your history of edits (for example, if you are using OpenRefine to anonymize information), export your cleaned dataset only and do not share your project archive. +::: + +Once someone has sent you a project archive file from their computer, you can save it anywhere. OpenRefine will import it like a new project and save its information to your workspace directory. + +In the left-hand menu of the home screen, click Import Project. Click Browse… and navigate to wherever you saved the file you were sent (for example, your Downloads folder). + +You can rename the project if you’d like - we recommend adding your name, a date, or a version number, if you’re planning to continue collaborating with another person (or working from multiple computers). + +Then, click Import Project. Your project should appear with a step count beside Undo/Redo if steps were saved by the exporter. + +OpenRefine will store the project in its own workspace directory, so you can now delete the original file that was sent to you. + + +## Project management {#project-management} + +You can access all of your created projects by clicking on Open Project. Your project list can be organized by modification date, title, row count, and other metadata you can supply (such as subject, descripton, tags, or creator). To edit the fields you see here, click About to the left of each project. There you can edit a number of available fields. You can also see the project ID that corresponds to the name of the folder in your work directory. + +### Naming projects {#naming-projects} + +You may have multiple projects from the same dataset, or multiple versions from sharing a project with another person. OpenRefine automatically generates a project name from the imported file, or “clipboard†when you use Clipboard importing. Project names don’t have to be unique, and OpenRefine will create many projects with the same name unless you intervene. + +You can edit a project's name when you create it or import it, and you can rename a project later by opening it and clicking on the project name at the top of the screen. + +### Autosaving {#autosaving} + +OpenRefine [saves all of your actions](running#history-undoredo) (everything you can see in the Undo/Redo panel). That includes flagging and starring rows. + +It doesn’t, however, save your facets, filters, or any kind of view you may have in place while you work. This includes the number of rows showing, and any sorting or column collapsing you may have done. A good rule of thumb is: if it’s not showing in Undo/Redo, you will lose it when you leave the project workspace. + +Autosaving happens by default every five minutes. You can [change this preference by following these directions](running#jvm-preferences). + +You can only save and share facets and filters, not any other type of view. To save current facets and filters, click Permalink. The project will reload with a different URL, which you can then copy and save elsewhere. This permalink will save both the facets and filters you’ve set, and the settings for each one (such as sorting by count rather than by name). + +### Deleting projects {#deleting-projects} + +You can delete projects, which will erase the project files from the workspace directory on your computer. This is immediate and cannot be undone. + +Go to Open Project and find the project you want to delete. Click on the X to the left of the project name. There will be a confirmation dialog. + +### Project files {#project-files} + +You can find all of your raw project files in your work directory. They will be named according to the unique “Project ID†that OpenRefine has assigned them, which you can find on the Open Project screen, under the “About†link for each project. diff --git a/OpenRefine/docs/docs/manual/transforming.md b/OpenRefine/docs/docs/manual/transforming.md new file mode 100644 index 000000000..53a436370 --- /dev/null +++ b/OpenRefine/docs/docs/manual/transforming.md @@ -0,0 +1,34 @@ +--- +id: transforming +title: Transforming data +sidebar_label: Overview +--- + +## Overview {#overview} + +OpenRefine gives you powerful ways to clean, correct, codify, and extend your data. Without ever needing to type inside a single cell, you can automatically fix typos, convert things to the right format, and add structured categories from trusted sources. + +This section of ways to improve data are organized by their appearance in the menu options in OpenRefine. You can: + +* change the order of [rows](#edit-rows) or [columns](columnediting#rename-remove-and-move) +* edit [cell contents](cellediting) within a particular column +* [transform](transposing) rows into columns, and columns into rows +* [split or join columns](columnediting#split-or-join) +* [add new columns](columnediting) based on existing data, with fetching new information, or through [reconciliation](reconciling) +* convert your rows of data into [multi-row records](exploring#rows-vs-records). + +## Edit rows {#edit-rows} + +Moving rows around is a permanent change to your data. + +You can [sort your data](sortview#sort) based on the values in one column, but that change is a temporary view setting. With that setting applied, you can make that new order permanent. + +![A screenshot of where to find the Sort menu with a sorting applied.](/img/sortPermanent.png) + +In the project grid header, the word “Sort†will appear when a sort operation is applied. Click on it to show the dropdown menu, and select Reorder rows permanently. You will see the numbering of the rows change under the All column. + +:::info Reordering all rows +Reordering rows permanently will affect all rows in the dataset, not just those currently viewed through [facets and filters](facets). +::: + +You can undo this action using the [History tab](running#history-undoredo). \ No newline at end of file diff --git a/OpenRefine/docs/docs/manual/transposing.md b/OpenRefine/docs/docs/manual/transposing.md new file mode 100644 index 000000000..6b5ec0dc8 --- /dev/null +++ b/OpenRefine/docs/docs/manual/transposing.md @@ -0,0 +1,234 @@ +--- +id: transposing +title: Transposing +sidebar_label: Transposing +--- + +## Overview {#overview} + +These functions were created to solve common problems with reshaping your data: pivoting cells from a row into a column, or pivoting cells from a column into a row. You can also transpose from a repeated set of values into multiple columns. + +## Transpose cells across columns into rows {#transpose-cells-across-columns-into-rows} + +Imagine personal data with addresses in this format: + +|Name|Street|City|State/Province|Country|Postal code| +|---|---|---|---|---|---| +|Jacques Cousteau|23, quai de Conti|Paris||France|75270| +|Emmy Noether|010 N Merion Avenue|Bryn Mawr|Pennsylvania|USA|19010| + +You can transpose the address information from this format into multiple rows. Go to the “Street†column and select Transpose → Transpose cells across columns into rows. From there you can select all of the five columns, starting with “Street†and ending with “Postal code,†that correspond to address information. Once you begin, you should put your project into [records mode](exploring#rows-vs-records) to associate the subsequent rows with “Name†as the key column. + +![A screenshot of the transpose across columns window.](/img/transpose1.png) + +### One column {#one-column} + +You can transpose the multiple address columns into a series of rows: + +|Name|Address| +|---|---| +|Jacques Cousteau|23, quai de Conti| +| |Paris| +| |France| +| |75270| +|Emmy Noether|010 N Merion Avenue| +||Bryn Mawr| +||Pennsylvania| +||USA| +||19010| + +You can choose one column and include the column-name information in each cell by prepending it to the value, with or without a separator: + +|Name|Address| +|---|---| +|Jacques Cousteau|Street: 23, quai de Conti| +| |City: Paris| +| |Country: France| +| |Postal code: 75270| +|Emmy Noether|Street: 010 N Merion Avenue| +||City: Bryn Mawr| +||State/Province: Pennsylvania| +||Country: USA| +||Postal code: 19010| + +### Two columns {#two-columns} + +You can retain the column names as separate cell values, by selecting Two new columns and naming the key and value columns. + +|Name|Address part|Address| +|---|---|---| +|Jacques Cousteau|Street|23, quai de Conti| +| |City|Paris| +| |Country|France| +| |Postal code|75270| +|Emmy Noether|Street|010 N Merion Avenue| +||City|Bryn Mawr| +||State/Province|Pennsylvania| +||Country|USA| +||Postal code|19010| + +## Transpose cells in rows into columns {#transpose-cells-in-rows-into-columns} + +Imagine employee data in this format: + +|Column| +|---| +|Employee: Karen Chiu| +|Job title: Senior analyst| +|Office: New York| +|Employee: Joe Khoury| +|Job title: Junior analyst| +|Office: Beirut| +|Employee: Samantha Martinez| +|Job title: CTO| +|Office: Tokyo| + +The goal is to sort out all of the information contained in one column into separate columns, but keep it organized by the person it represents: + +|Name |Job title |Office| +|---|---|---| +|Karen Chiu |Senior analyst |New York| +|Joe Khoury |Junior analyst |Beirut| +|Samantha Martinez |CTO |Tokyo| + +By selecting Transpose → Transpose cells in rows into columns... a window will appear that simply asks how many rows to transpose. In this case, each employee record has three rows, so input “3†(do not subtract one for the original column). The original column will disappear and be replaced with three columns, with the name of the original column plus a number appended. + +|Column 1 |Column 2 |Column 3| +|---|---|---| +|Employee: Karen Chiu |Job title: Senior analyst |Office: New York| +|Employee: Joe Khoury |Job title: Junior analyst |Office: Beirut| +|Employee: Samantha Martinez |Job title: CTO |Office: Tokyo| + +From here you can use Cell editing → Replace to remove “Employee: â€, “Job title: â€, and “Office: †if you wish, or use [expressions](expressions) with Edit cells → Transform... to clean out the extraneous characters: + +``` +value.replace("Employee: ", "") +``` + +If your dataset doesn't have a predictable number of cells per intended row, such that you cannot specify easily how many columns to create, try Columnize by key/value columns. + +## Columnize by key/value columns {#columnize-by-keyvalue-columns} + +This operation can be used to reshape a dataset that contains key and value columns: the repeating strings in the key column become new column names, and the contents of the value column are moved to new columns. This operation can be found at Transpose → Columnize by key/value columns. + +![A screenshot of the Columnize window.](/img/transpose2.png) + +Consider the following example, with flowers, their colours, and their International Union for Conservation of Nature (IUCN) identifiers: + +|Field |Data | +|--------|----------------------| +|Name |Galanthus nivalis | +|Color |White | +|IUCN ID |162168 | +|Name |Narcissus cyclamineus | +|Color |Yellow | +|IUCN ID |161899 | + +In this format, each flower species is described by multiple attributes on consecutive rows. The “Field†column contains the keys and the “Data†column contains the values. In the Columnize by key/value columns window you can select each of these from the available columns. It transforms the table as follows: + +| Name | Color | IUCN ID | +|-----------------------|----------|---------| +| Galanthus nivalis | White | 162168 | +| Narcissus cyclamineus | Yellow | 161899 | + +### Entries with multiple values in the same column {#entries-with-multiple-values-in-the-same-column} + +If a new row would have multiple values for a given key, then these values will be grouped on consecutive rows, to form a [record structure](exploring#rows-vs-records). + +For instance, flowers can have multiple colors: + +| Field | Data | +|-------------|-----------------------| +| Name | Galanthus nivalis | +| _Color_ | _White_ | +| _Color_ | _Green_ | +| IUCN ID | 162168 | +| Name | Narcissus cyclamineus | +| Color | Yellow | +| IUCN ID | 161899 | + +This table is transformed by the Columnize operation to: + +| Name | Color | IUCN ID | +|-----------------------|----------|---------| +| Galanthus nivalis | White | 162168 | +| | Green | | +| Narcissus cyclamineus | Yellow | 161899 | + +The first key encountered by the operation serves as the record key, so the “Green†value is attached to the “Galanthus nivalis†name. See the [Row order](#row-order) section for more details about the influence of row order on the results of the operation. + +### Notes column {#notes-column} + +In addition to the key and value columns, you can optionally add a column for notes. This can be used to store extra metadata associated to a key/value pair. + +Consider the following example: + +| Field | Data | Source | +|---------|---------------------|-----------------------| +| Name | Galanthus nivalis | IUCN | +| Color | White | Contributed by Martha | +| IUCN ID | 162168 | | +| Name | Narcissus cyclamineus | Legacy | +| Color | Yellow | 2009 survey | +| IUCN ID | 161899 | | + +If the “Source†column is selected as the notes column, this table is transformed to: + +| Name | Color | IUCN ID | Source: Name | Source: Color | +|-----------------------|----------|---------|---------------|-----------------------| +| Galanthus nivalis | White | 162168 | IUCN | Contributed by Martha | +| Narcissus cyclamineus | Yellow | 161899 | Legacy | 2009 survey | + +Notes columns can therefore be used to preserve provenance or other context about a particular key/value pair. + +### Row order {#row-order} + +The order in which the key/value pairs appear matters. The Columnize operation will use the first key it encounters as the delimiter for entries: every time it encounters this key again, it will produce a new row, and add the following key/value pairs to that row. + +Consider for instance the following table: + +| Field | Data | +|----------|-----------------------| +| _Name_ | Galanthus nivalis | +| Color | White | +| IUCN ID | 162168 | +| _Name_ | Crinum variabile | +| _Name_ | Narcissus cyclamineus | +| Color | Yellow | +| IUCN ID | 161899 | + +The occurrences of the “Name†value in the “Field†column define the boundaries of the entries. Because there is no other row between the “Crinum variabile†and the “Narcissus cyclamineus†rows, the “Color†and “IUCN ID†columns for the “Crinum variabile†entry will be empty: + +| Name | Color | IUCN ID | +|-----------------------|----------|---------| +| Galanthus nivalis | White | 162168 | +| Crinum variabile | | | +| Narcissus cyclamineus | Yellow | 161899 | + +This sensitivity to order is removed if there are extra columns: in that case, the first extra column will serve as the key for the new rows. + +### Extra columns {#extra-columns} + +If your dataset contains extra columns, that are not being used as the key, value, or notes columns, they can be preserved by the operation. For this to work, they must have the same value in all old rows corresponding to a new row. + +In the following example, the “Field†and “Data†columns are used as key and value columns respectively, and the “Wikidata ID†column is not selected: + +| Field | Data | Wikidata ID | +|---------|-----------------------|-------------| +| Name | Galanthus nivalis | Q109995 | +| Color | White | Q109995 | +| IUCN ID | 162168 | Q109995 | +| Name | Narcissus cyclamineus | Q1727024 | +| Color | Yellow | Q1727024 | +| IUCN ID | 161899 | Q1727024 | + +This will be transformed to: + +| Wikidata ID | Name | Color | IUCN ID | +|-------------|-----------------------|----------|---------| +| Q109995 | Galanthus nivalis | White | 162168 | +| Q1727024 | Narcissus cyclamineus | Yellow | 161899 | + +This actually changes the operation: OpenRefine no longer looks for the first key (“Nameâ€) but simply pivots all information based on the first extra column's values. Every old row with the same value gets transposed into one new row. If you have more than one extra column, they are pivoted as well but not used as the new key. + +You can use [Fill down](cellediting#fill-down-and-blank-down) to put identical values in the extra columns if you need to. \ No newline at end of file diff --git a/OpenRefine/docs/docs/manual/troubleshooting.md b/OpenRefine/docs/docs/manual/troubleshooting.md new file mode 100644 index 000000000..5388fc351 --- /dev/null +++ b/OpenRefine/docs/docs/manual/troubleshooting.md @@ -0,0 +1,31 @@ +--- +id: troubleshooting +title: Troubleshooting +sidebar_label: Troubleshooting +--- + +## Frequently asked questions {#frequently-asked-questions} + +We collect and share FAQs and responses on Github at [https://github.com/OpenRefine/OpenRefine/wiki/FAQ](https://github.com/OpenRefine/OpenRefine/wiki/FAQ). + +If you don’t find your problem and solution there, continue on to the resources in the Community section below to see more conversations and look for solutions. + +## Community {#community} + +### If you’re having a problem: {#if-youre-having-a-problem} +* Search the [User forum](https://groups.google.com/g/openrefine) to see if the problem is already reported +* Search [Github issues](https://github.com/OpenRefine/OpenRefine/issues) to see if the problem is already reported +* Read [Stack Overflow](https://stackoverflow.com/questions/tagged/openrefine) to see if others had a similar problem +* Check [Twitter](https://twitter.com/search?f=tweets&vertical=default&q=OpenRefine%20OR%20%22Open%20Refine%22%20OR%20%23OpenRefine&src=typd) to see if others are discussing the problem +* Report an issue: + * First as a new thread (conversation) in the [User forum](https://groups.google.com/g/openrefine). + * Then, if you wish, you can create a Github issue. + +### If you want to contribute: {#if-you-want-to-contribute} +* [Help us translate the tool into more languages](../technical-reference/translating-ui), using Weblate +* [We have a guide to contributing](../technical-reference/contributing) in the [Technical Reference](../technical-reference/technical-reference-index) section +* Contribute your feature requests in the [User forum](https://groups.google.com/g/openrefine) or as [Github issues](https://github.com/OpenRefine/OpenRefine/issues/new/choose) +* Join the User Forum and/or the [Developer Forum](https://groups.google.com/g/openrefine-dev) +* Share your successes and use cases with us, in the User forum +* Add your [blog posts, guides, tips, tricks, tutorials to our list](https://github.com/OpenRefine/OpenRefine/wiki/External-Resources) +* Keep an eye out for and respond to our biennial user survey. diff --git a/OpenRefine/docs/docs/manual/wikibase/advanced-schemas.md b/OpenRefine/docs/docs/manual/wikibase/advanced-schemas.md new file mode 100644 index 000000000..45f91800c --- /dev/null +++ b/OpenRefine/docs/docs/manual/wikibase/advanced-schemas.md @@ -0,0 +1,72 @@ +Sometimes your data is not as simple as a normal table, or the sort of +statements that you want to do varies on each row. This document +explains how to work around these cases. + +## Hierarchical data {#hierarchical-data} + +Sometimes your source provides data in a structured format, such as XML, +JSON or RDF. OpenRefine can import these files and will convert them to +tables. These tables will reflect some of the hierarchy in the file by +means of null cells, using the [records mode](/manual/exploring#rows-vs-records). + +The Wikibase extension always works in rows mode, so if we want to add +statements which reference both the artist and the song, we need to fill +the null cells with the corresponding artist. You can do this with the +**Fill down** operation (in the **Edit cells** menu for this column). +This function will copy not just cell values but also reconciliation +results. + +## Conditional additions {#conditional-additions} + +Sometimes you want to add a statement only in some conditions. + +The workflow to achieve this looks like this: +- Use facets to select the rows where you do not want to add any + information; +- Blank out the cells in the column that contain the information you + want to add. If you do not want to lose this information, you can + create a copy of the column beforehand; +- Remove your facets to see all rows again; +- Create a schema using the column you partially blanked out as + statement value. + +## Varying properties {#varying-properties} + +Sometimes you wish you could use column variables for properties in your +schema. It is currently not possible, first because we do not have a +reconciliation service for properties yet, but also because allowing +varying properties in a statement would mean that these properties could +potentially have different datatypes, which would break the structure of +the schema. + +If you only want to use a few properties, there is a way to go around +this problem. For instance, say you have a first column of altitudes and a +second column that indicates whether you should add it as +[operating altitude (P2254)](https://www.wikidata.org/wiki/Property:P2254) or as +[elevation above sea level (P2044)](https://www.wikidata.org/wiki/Property:P2044). + +Create a text facet on the first column. Filter to keep only the +*altitude* values. Add a new column based on the second column, by +keeping the default expression (`value`) which just copies the existing +values. Then, select the *maximum operating altitude* value in the facet +and do the same. Reset the facet, you should have obtained two new columns +which partition the original column. You can now create a schema which adds +two statements, with values taken from those columns. Since blank values are +ignored, exactly one statement will be added for each item, with the desired property. + +## Adapting to existing data on Wikibase {#adapting-to-existing-data-on-wikibase} + +Sometimes you want to create statements only if there are no such +statements on the item yet. Here is one way to achieve this: + +- first, retrieve the existing values from Wikidata first, using the + **Edit columns** → **Add columns from reconciled values** action; +- second, create a *facet by null* on the newly created column that + contains the information you want to control against; +- select the non-null rows (value **false**); +- clear the contents of the column where your source values are + (**Edit cells** → **Common transformations** → **To null**). + +You can now construct your schema as usual - null values will be ignored +when generating the statements. + diff --git a/OpenRefine/docs/docs/manual/wikibase/configuration.md b/OpenRefine/docs/docs/manual/wikibase/configuration.md new file mode 100644 index 000000000..aa7fd1d98 --- /dev/null +++ b/OpenRefine/docs/docs/manual/wikibase/configuration.md @@ -0,0 +1,149 @@ +--- +id: configuration +title: Connecting OpenRefine to a Wikibase instance +sidebar_label: Connecting to Wikibase +--- + +This page explains how to connect OpenRefine to any Wikibase instance. If you just want to work with [Wikidata](https://www.wikidata.org/), you can ignore this page as Wikidata is configured out of the box in OpenRefine. + +## For Wikibase end users {#for-wikibase-end-users} + +All you need to configure OpenRefine to work with a Wikibase instance is a *manifest* for that instance, which provides some metadata and links required for the integration to work. + +We offer some off-the-shelf manifests for some public Wikibase instances in the [wikibase-manifests](https://github.com/OpenRefine/wikibase-manifests) repository. But the administrators of your Wikibase instance should provide one that is potentially more +up to date, so it makes sense to request it to them first. + +## For Wikibase administrators {#for-wikibase-administrators} + +To let your users contribute to your Wikibase instance with OpenRefine, you will need to write a manifest as described above. There is currently no canonical location where this manifest should be hosted - just make sure can be found easily by your users. This section explains the format of the manifest. + +### Requirements {#requirements} + +To work with OpenRefine, your Wikibase instance needs an associated reconciliation service. For instance you can use [a Python wrapper](https://github.com/wetneb/openrefine-wikibase) for this. Also, in addition to Wikibase, the [UniversalLanguageSelector extension](https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:UniversalLanguageSelector) should be installed. + + +### The format of the manifest {#the-format-of-the-manifest} + +Here is the manifest of Wikidata: + +```json +{ + "version": "1.0", + "mediawiki": { + "name": "Wikidata", + "root": "https://www.wikidata.org/wiki/", + "main_page": "https://www.wikidata.org/wiki/Wikidata:Main_Page", + "api": "https://www.wikidata.org/w/api.php" + }, + "wikibase": { + "site_iri": "http://www.wikidata.org/entity/", + "maxlag": 5, + "properties": { + "instance_of": "P31", + "subclass_of": "P279" + }, + "constraints": { + "property_constraint_pid": "P2302", + "exception_to_constraint_pid": "P2303", + "constraint_status_pid": "P2316", + "mandatory_constraint_qid": "Q21502408", + "suggestion_constraint_qid": "Q62026391", + "distinct_values_constraint_qid": "Q21502410", + // ... + } + }, + "oauth": { + "registration_page": "https://meta.wikimedia.org/wiki/Special:OAuthConsumerRegistration/propose" + }, + "reconciliation": { + "endpoint": "https://wikidata.reconci.link/${lang}/api" + }, + "editgroups": { + "url_schema": "([[:toollabs:editgroups/b/OR/${batch_id}|details]])" + } +} +``` + +In general, there are several parts of the manifest: version, mediawiki, wikibase, oauth, reconciliation and editgroups. + +#### version {#version} + +The version should in the format "1.x". The minor version should be increased when you update the manifest in a backward-compatible manner. The major version should be "1" if the manifest is in the format specified by [wikibase-manifest-schema-v1.json](https://github.com/afkbrb/wikibase-manifest/blob/master/wikibase-manifest-schema-v1.json). + +#### mediawiki {#mediawiki} + +This part contains some basic information of the Wikibase. + +##### name {#name} + +The name of the Wikibase, should be unique for different Wikibase instances. + +##### root {#root} + +The root of the Wikibase. Typically in the form "https://foo.bar/wiki/". The trailing slash cannot be omitted. + +##### main_page {#main_page} + +The main page of the Wikibase. Typically in the form "https://foo.bar/wiki/Main_Page". + +##### api {#api} + +The MediaWiki API endpoint of the Wikibase. Typically in the form "https://foo.bar/w/api.php". + +#### wikibase {#wikibase} + +This part contains configurations of the Wikibase extension. + +##### site_iri {#site_iri} + +The IRI of the Wikibase, in the form 'http://foo.bar/entity/'. This should match the IRI prefixes used in RDF serialization. Be careful about using "http" or "https", because any variation will break comparisons at various places. The trailing slash cannot be omitted. + +##### maxlag {#maxlag} + +Maxlag is a parameter that controls how aggressive a mass-editing tool should be when uploading edits to a Wikibase instance. See https://www.mediawiki.org/wiki/Manual:Maxlag_parameter for more details. The value should be adapted according to the actual traffic of the Wikibase. + +##### properties {#properties} + +Some special properties of the Wikibase. + +###### instance_of {#instance_of} + +The ID of the property "instance of". + +###### subclass_of {#subclass_of} + +The ID of the property "subclass of". + +##### constraints {#constraints} + +Not required. Should be configured if the Wikibase has the [WikibaseQualityConstraints extension](https://www.mediawiki.org/wiki/Extension:WikibaseQualityConstraints) installed. Configurations of constraints consists of IDs of constraints related properties and items. For Wikidata, these IDs are retrieved from [extension.json](https://github.com/wikimedia/mediawiki-extensions-WikibaseQualityConstraints/blob/master/extension.json). To configure this for another Wikibase instance, you should contact an admin of the Wikibase instance to get the content of `extension.json`. + +#### oauth {#oauth} + +Not required. Should be configured if the Wikibase has the [OAuth extension](https://www.mediawiki.org/wiki/Extension:OAuth) installed. + +##### registration_page {#registration_page} + +The page to register an OAuth consumer of the Wikibase. Typically in the form "https://foo.bar/wiki/Special:OAuthConsumerRegistration/propose". + +#### reconciliation {#reconciliation} + +The Wikibase instance must have at least a reconciliation service endpoint linked to it. If there is no reconciliation service for the Wikibase, you can run one with [openrefine-wikibase](https://github.com/wetneb/openrefine-wikibase). + +##### endpoint {#endpoint} + +The default reconciliation service endpoint of the Wikibase instance. The endpoint must contain the "${lang}" variable such as "https://wikidata.reconci.link/${lang}/api", since the reconciliation service is expected to work for different languages. + +#### editgroups {#editgroups} + +Not required. Should be configured if the Wikibase instance has [EditGroups](https://github.com/Wikidata/editgroups) service(s). + +##### url_schema {#url_schema} + +The URL schema used in edits summary. This is used for EditGroups to extract the batch id from a batch of edits and for linking to the EditGroups page of the batch. The URL schema must contains the variable '${batch_id}', such as '([[:toollabs:editgroups/b/OR/${batch_id}|details]])' for Wikidata. + +#### Check the format of the manifest {#check-the-format-of-the-manifest} + +As mentioned above, the manifest should be in the format specified by [wikibase-manifest-schema-v1.json](https://github.com/afkbrb/wikibase-manifest/blob/master/wikibase-manifest-schema-v1.json). You can check the format by adding the manifest directly to OpenRefine, and OpenRefine will complain if there is anything wrong with the format. + +![test-validate-manifest-format](https://user-images.githubusercontent.com/29347603/90506110-52d85d00-e186-11ea-8077-683d2f234c46.gif) diff --git a/OpenRefine/docs/docs/manual/wikibase/new-entities.md b/OpenRefine/docs/docs/manual/wikibase/new-entities.md new file mode 100644 index 000000000..8dbc4f362 --- /dev/null +++ b/OpenRefine/docs/docs/manual/wikibase/new-entities.md @@ -0,0 +1,104 @@ +--- +id: new-entities +title: Creating new items +sidebar_label: New items +--- + +OpenRefine can create new items. This page explains how they are +generated. + +## Words of caution {#words-of-caution} + +- The fact that OpenRefine does not propose any item when reconciling + a cell does not mean that the item is not present in the Wikibase instance: + it can be missed for all sorts of reasons. Please make + sure that you are not creating any duplicates! + +- Make sure that the items that you want to create are admissible in + the Wikibase instance. For Wikidata, see the [notability guidelines](https://www.wikidata.org/wiki/Wikidata:Notability); + +- Deleting items generally requires special rights: if you want to revert an + edit group that includes new items in Wikidata, you will need to ask an + administrator to do it. + +## Workflow overview {#workflow-overview} + +Here is how you would typically create new items with OpenRefine: + +- Reconcile a column; +- Mark some of its cells as new items. This will not create items yet. + If you need to mark many rows as new items, use the **Reconcile** → + **Actions** → **Create a new item for each cell** operation. +- Create a Wikibase schema as usual, using the column where your new + items are marked; +- Perform the edits: the new items will be created on Wikidata at this + point; +- The cells that you had marked as new items will now be reconciled to + the newly-created items. + +It is often useful (but not mandatory) to treat new items in isolation +and use a dedicated schema for them. This helps you add many statements +on the new items (including labels and descriptions) without risking to +clutter existing items with redundant edits. Use a facet on the judgment +status of the reconciled column to isolate new items and perform their +edits separately. As always in OpenRefine, only the rows covered by your +facets will be considered when uploading the edits to Wikidata: if a +cell is reconciled to a new item but is excluded by the facet, no new +item will be created for it.[^1] + +Note that even if you know that all items in your column are new, you +will still need to make a first reconciliation pass by selecting the +Wikidata reconciliation service, and then setting all reconciliation +statuses to \"new\". If you skip the first part, OpenRefine will not +know that this column is reconciled against your Wikibase instance (it could be +reconciled to other services) so it will not let you use it in place of +an item in a Wikibase schema. + +You can also perform the edits with QuickStatements - in this case, your +OpenRefine project will not be updated with the newly created Qids. + +## Adding labels to new items {#adding-labels-to-new-items} + +The text that is in a cell reconciled to \"new\" is not automatically +used as label for the newly-created item. This is because OpenRefine has +no way to guess in which language this label should be. When adding new +items, you need to explicitly add a label in the schema. This label can +use the reconciled column as source, but if you have other cells matched +to existing items, be careful not to override the labels of these items +(if it is not your intention). + +OpenRefine will refuse to perform edits where new items are created +without any labels (as this is considered a critical issue). Other +issues will be raised if insufficient basic information is added on the +items (but these other warnings will not prevent you from performing the +edits). + +## Marking multiple cells as identical items {#marking-multiple-cells-as-identical-items} + +If you mark individual cells as new items, one new item per cell will be +created. Sometimes multiple rows refer to the same item. OpenRefine +makes it possible to mark all the corresponding cells as the *same* new +item. Two conditions have to be met: +- the reconciled cells must be in the same column (it is not possible + to mark two cells in different colums as the same new item); +- the cells must contain the same initial text value. + +If these two conditions are met, then isolate these cells with facets +and go to **Reconcile** → **Actions** → **Create one item for similar +cells**. This will mark the cells as new and referring to the same item. + +## Retrieving the Qids of the newly-created items {#retrieving-the-qids-of-the-newly-created-items} + +Once you have performed your edits with OpenRefine, any new cells +covered by the facet will be updated with their new Qids. You can +retrieve these Qids with the **Edit column** → **Add column based on +this column** action and using the `cell.recon.match.id` expression. +Note that you will no longer be able to isolate new items with a +judgment facet at this stage (because the judgment will be updated to +**matched**) so it can be worth marking these rows (for instance with a +star or flag) before performing the edits. + +[^1]: The only exception to this rule is when marking multiple cells as + identical items: in this case, if one of such cells are included in + the facet, then all the others will be updated with the newly + created Qid once the edits are made. diff --git a/OpenRefine/docs/docs/manual/wikibase/overview.md b/OpenRefine/docs/docs/manual/wikibase/overview.md new file mode 100644 index 000000000..a202101fd --- /dev/null +++ b/OpenRefine/docs/docs/manual/wikibase/overview.md @@ -0,0 +1,134 @@ +--- +id: overview +title: Overview of Wikibase support +sidebar_label: Overview +--- + +[Wikibase](https://wikiba.se/) is a platform for collaborative knowledge base editing. Its flagship instance [Wikidata](https://www.wikidata.org/) offers structured data about the world and can be edited by anyone. OpenRefine provides powerful ways to both pull data from Wikibase and add data to it. + +OpenRefine's Wikibase integration is provided by an extension which is available by default in OpenRefine. In this page, we present the functionalities for Wikidata, but [any Wikibase instance can be connected to OpenRefine](./configuration) to obtain a similar integration. + +## Editing Wikidata with OpenRefine {#editing-wikidata-with-openrefine} + +As a user-maintained data source, Wikidata can be edited by anyone. OpenRefine makes it simple to upload information in bulk. You simply need to get your information into the correct format, and ensure that it is new (not redundant to information already on Wikidata) and does not conflict with existing Wikidata information. + +You do not need a Wikidata account to reconcile your local OpenRefine project to Wikidata, but to upload your cleaned dataset to Wikidata, you will need an [autoconfirmed](https://www.wikidata.org/wiki/Wikidata:Autoconfirmed_users) account, and you must [authorize OpenRefine with that account](#manage-wikidata-account). + +Wikidata is built by creating entities (such as people, organizations, or places, identified with unique numbers starting with Q), defining properties (unique numbers starting with P), and using properties to define relationships between entities (a Q has a property P, with a value of another Q). + +For example, you may wish to create entities for local authors and the books they've set in your community. Each writer will be an entity with the occupation [author (Q482980)](https://www.wikidata.org/wiki/Q482980), each book will be an entity with the property “instance of†([P31](https://www.wikidata.org/wiki/Property:P31)) linking it to a class such as [literary work (Q7725634)](https://www.wikidata.org/wiki/Q7725634), and books will be related to authors through a property [author (P50)](https://www.wikidata.org/wiki/Property:P50). Books can have places where they are set, with the property [narrative location (P840)](https://www.wikidata.org/wiki/Property:P840). + +To do this with OpenRefine, you'll need a column of publication titles that you have reconciled (and create new items where needed); each publication will have one or more locations in a “setting†column, which is also reconciled to municipalities or regions where they exist (and create new items where needed). Then you can add those new relationships, and create new entities for authors, books, and places where needed. You do not need columns for properties; those are defined later, in the creation of your [schema](#edit-wikidata-schema). + +There is a list of [tutorials and walkthroughs on Wikidata](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing) that will allow you to see the full process. You can save your schemas and drafts in OpenRefine, and your progress stays in draft until you are ready to upload it to Wikidata. + +Batches of edits to Wikidata that are created with OpenRefine can be undone. You can test out the uploading process by reconciling to several “sandbox†entities created specifically for drafting edits and learning about Wikidata: +* https://www.wikidata.org/wiki/Q4115189 +* https://www.wikidata.org/wiki/Q13406268 +* https://www.wikidata.org/wiki/Q15397819 +* https://www.wikidata.org/wiki/Q64768399 + +If you upload edits that are redundant (that is, all the statements you want to make have already been made), nothing will happen. If you upload edits that conflict with existing information (such as a different birthdate than one already in Wikidata), it will be added as a second statement. OpenRefine produces no warnings as to whether your data replicates or conflicts with existing Wikidata elements. + +You can use OpenRefine's reconciliation preview to look at the target Wikidata elements and see what information they already have, and whether the elements' histories have had similar edits reverted in the past. + +### Wikidata schema {#wikidata-schema} + +A [schema](https://en.wikipedia.org/wiki/Database_schema) is a plan for how to structure information in a database. In OpenRefine, the schema operates as a template for how Wikidata edits should be applied: how to translate your tabular data into statements. With a schema, you can: +* preview the Wikidata edits and inspect them manually; +* analyze and fix any issues highlighted by OpenRefine; +* upload your changes to Wikidata by logging in with your own account; +* export the changes to the QuickStatements v1 format. + +For example, if your dataset has columns for authors, publication titles, and publication years, your schema can be conceptualized as: [publication title] has the author [author], and was published in [publication year]. To establish these facts, you need to establish one or more columns as “items,†for which you will make “statements†that relate them to other columns. + +You can export any schema you create, and import an existing schema for use with a new dataset. This can help you work in batches on a large amount of data while minimizing redundant labor. + +Once you select Edit Wikidata schema under the Extensions dropdown menu, your project interface will change. You’ll see new tabs added to the right of “X rows/records" in the grid header: “Schema,†“Issues,†and “Preview.†You can now switch between the tabular grid format of your dataset and the screens that allow you to prepare data for uploading. + +OpenRefine presents you with an easy visual way to map out the relationships in your dataset. Each of the columns of your project will appear at the top of the sceren, and you can simply drag and drop them into the appropriate slots. To get start, select one column as an item. + +![A screenshot of the schema construction window in OpenRefine.](/img/wikidata-schema.png) + +You may wish to refer to [this Wikidata tutorial on how OpenRefine handles Wikidata schema](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing/Tutorials/Basic_editing). For details about how each data type is handled in the Wikibase schema, see [Schema alignment](./schema-alignment). + +#### Editing terms with your schema {#editing-terms-with-your-schema} + +With OpenRefine, you can edit the terms (labels, aliases, descriptions, or sitelinks) of Wikidata entities as well as establish relationships between entities. For example, you may wish to upload pseudonyms, pen names, maiden names, or married names for authors. + +![An author with a number of aliases indicating pseudonyms.](/img/wikidata-terms.png) + +You can do so by putting the preferred names in one column of your dataset and alternative names in another column. In the schema interface, add an item for the preferred values, then click “Add term†on the right-hand side of the screen. Select “Alias†from the dropdown, enter in “English†in the language field, and drop your alternative names column into the space. For this example, you should also consider adding those alternative names to the authors' entries using the property [pseudonym (P742)](https://www.wikidata.org/wiki/Property:P742). The "description" and "label" terms can only contain one value, so there is an option to override existing values if needed. Aliases can be potentially infinite. + +![The schema window showing a term being edited.](/img/wikidata-terms2.png) + +Terms must always have an associated language. You can select the term's language by typing in the “lang†field, which will auto-complete for you. You cannot edit multiple languages at once, unless you supply a suitable column instead. For example, suppose you had translated publication titles, with data in the following format: + +|English title|Translated title|Translation language| +|---|---|---| +|Possession|Besessen|German| +||Обладать|Russian| +|Disgrace|Disgrâce|French| +||Vergogna|Italian| +|Wolf Hall|En la corte del lobo|Spanish| +||ウルフ・ホール|Japanese| + +You could upload the “Translated titles†to “Label†with the language specified by “Translation language.†You may wish to fetch the two-letter language code and use that instead for better language matches. + +![Constructing a schema with aliases and languages.](/img/wikidata-translated.png) + +### Manage Wikidata account {#manage-wikidata-account} + +To edit Wikidata directly from OpenRefine, you must log in with a Wikidata account. OpenRefine can only upload edits with Wikidata user accounts that are “[autoconfirmed](https://www.wikidata.org/wiki/Wikidata:Autoconfirmed_users)†- at this time, that means accounts that have more than 50 edits and have existed for longer than four days. + +Use the Extensions menu to select Manage Wikidata account and you will be presented with the following window: + +![The Wikidata authorization window in OpenRefine.](/img/wikidata-login.png) + +For security reasons, you should not use your main account authorization with OpenRefine. Wikidata allows you to set special passwords to access your account through software. You can find [this setting for your account here](https://www.wikidata.org/wiki/Special:BotPasswords) once logged in. Creating bot access will prompt you for a unique name. You should then enable the following required settings: +* High-volume editing +* Edit existing pages +* Create, edit, and move pages + +It will then generate a username (in the form of “yourwikidatausername@yourbotnameâ€) and password for you to use with OpenRefine. + +If your account or your bot is not properly authorized, OpenRefine will not display a warning or error when you try to upload your edits. + +You can store your unencrypted username and password in OpenRefine, saved locally to your computer and available for future use. For security reasons, you may wish to leave this box unchecked. You can also save your OpenRefine-specific bot password in your browser or with a password management tool. + +### Import and export schema {#import-and-export-schema} + +You can save time on repetitive processes by defining a schema on one project, then exporting it and importing for use on new datasets in the future. Or you and your colleagues can share a schema with each other to coordinate your work. + +You can export a schema from a project using Export → Wikidata schema, or by using Extensions → Export schema. OpenRefine will generate a JSON file for you to save and share. You may experience issues with pop-up windows in your browser: consider allowing pop-ups from the OpenRefine URL (`127.0.0.1`) from now on. + +You can import a schema using Extensions → Import schema. You can upload a JSON file, or paste JSON statements directly into a field in the window. An imported schema will look for columns with the same names, and you will see an error message if your project doesn't contain matching columns. + +### Upload edits to Wikidata {#upload-edits-to-wikidata} + +There are two menu options in OpenRefine for applying your edits to Wikidata, and the details of the differences between the two can be found in the [Uploading page](./uploading). Under Export you will see Wikidata edits... and under Extensions you will see Upload edits to Wikidata. Both will bring up the same window for you to [log in with a Wikidata account](#manage-wikidata-account). + +Once you are authorized, you will see a window with any outstanding issues. You can ignore these issues, but we recommend you resolve them. + +If you are ready to upload your edits, you can provide an “Edit summary†- a short message describing the batch of edits you are making. It can be helpful to leave notes for yourself, such as “batch 1: authors A-G†or other indicators of your workflow progress. OpenRefine will show the progress of the upload as it is happening, but does not show a confirmaton window. + +If your edits have been successful, you will see them listed on [your Wikidata user contributions page](https://www.wikidata.org/wiki/Special:Contributions/), and on the [Edit groups page](https://editgroups.toolforge.org/). All edits can be undone from this second interface. + +### QuickStatements export {#quickstatements-export} + +Your OpenRefine data can be exported in a format recognized by [QuickStatements](https://www.wikidata.org/wiki/Help:QuickStatements), a tool that creates Wikidata edits using text commands. OpenRefine generates “version 1†QuickStatements commands. + +There are advantages to using QuickStatements rather than uploading your edits directly to Wikidata, including the way QuickStatements resolves duplicates and redundancies. You can learn more on QuickStatements' [Help page](https://www.wikidata.org/wiki/Help:QuickStatements), and on OpenRefine's [Uploading page](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing/Uploading). + +In order to use QuickStatements, you must authorize it with a Wikidata account that is [autoconfirmed](https://www.wikidata.org/wiki/Wikidata:Autoconfirmed_users) (it may appear as “MediaWiki†when you authorize). + +Follow the [steps listed on this page](https://www.wikidata.org/wiki/Help:QuickStatements#Running_QuickStatements). +To prepare your OpenRefine data into QuickStatements, select Export → QuickStatements file, or Extensions → Export to QuickStatements. Exporting your schema from OpenRefine will generate a text file called `statements.txt` by default. Paste the contents of the text file into a new QuickStatements batch using version 1. You can find [version 1 of the tool (no longer maintained) here](https://wikidata-todo.toolforge.org/quick_statements.php). The text commands will be processed into Wikidata edits and previewed for you to review before submitting. + +### Issue detection {#issue-detection} + +This section is an overview of the [Quality assurance page](./quality-assurance). + +OpenRefine will analyze your schema and make suggestions. It does not check for conflicts in your proposed edits, or tell you about redundancies. + +One of the most common suggestions is to attach [a reference to your edits](https://www.wikidata.org/wiki/Help:Sources) - a citation for where the information can be found. This can be a book or newspaper citation, a URL to an online page, a reference to a physical source in an archival or special collection, or another source. If the source is itself an item on Wikidata, use the relationship [stated in (P248)](https://www.wikidata.org/wiki/Property:P248); otherwise, use [reference URL (P854)](https://www.wikidata.org/wiki/Property:P854) to identify an external source. diff --git a/OpenRefine/docs/docs/manual/wikibase/quality-assurance.md b/OpenRefine/docs/docs/manual/wikibase/quality-assurance.md new file mode 100644 index 000000000..a8ead43e3 --- /dev/null +++ b/OpenRefine/docs/docs/manual/wikibase/quality-assurance.md @@ -0,0 +1,48 @@ +--- +id: quality-assurance +title: Quality assurance for Wikibase uploads +sidebar_label: Quality assurance +--- + +This page explains how the Wikidata extension of OpenRefine analyzes edits before they are uploaded to the Wikibase +instance. Most of these checks rely on the use of the [Wikibase Quality Constraints](https://gerrit.wikimedia.org/g/mediawiki/extensions/WikibaseQualityConstraints) extension and the configuration of the property and item identifiers in the [Wikibase manifest](./configuration). + +## Overview {#overview} + +Changes are scrutinized before they are uploaded, but also before the current content of the corresponding items is retrieved and merged with the updates. This means that some constraint violations cannot be predicted by the software (for instance, adding a new statement that conflicts with an existing statement on the item). However, this makes it possible to run the checks quickly, even for relatively large batches of edits. Issues are therefore refreshed in real time while the user builds the schema. + +As a consequence, not all constraint violations can be detected: the ones that are supported are listed in the [Constraint violations](#constraint-violations) section. Conversely, not all issues reported will be flagged as constraint violations on the Wikibase site: see [Generic issues](#generic-issues) for these. + +## Reconciliation {#reconciliation} + +You should always assess the quality of your reconciliation results first. OpenRefine has various tools for quality assurance of reconciliation results. For instance: + +* you can analyze the string similarity between your original names and those of the reconciled items (for instance with Reconcile → Facets → Best candidate's name edit distance); +* you can compare the values in your table with those on the items (via a text facet defined by a custom expression); +* you can facet by type on the reconciled items (add a new column with the types and use a text facet ordered by counts to get a sense of the distribution of types in your reconciled items). + +## Constraint violations {#constraint-violations} + +Constraints are retrieved as defined on the properties, using [ (P2302)](https://www.wikidata.org/wiki/Property:P2302). + +The following constraints are supported: +* [format constraint (Q21502404)](https://www.wikidata.org/wiki/Q21502404), checked on all values +* [inverse constraint (Q21510855)](https://www.wikidata.org/wiki/Q21510855): OpenRefine assumes that the inverses of the candidate statements are not in Wikidata yet. If you know that the inverse statements are already in Wikidata, you can safely ignore this issue. +* [used for values only constraint (Q21528958)](https://www.wikidata.org/wiki/Q21528958), [used as qualifier constraint (Q21510863)](https://www.wikidata.org/wiki/Q21510863) and [used as reference constraint (Q21528959)](https://www.wikidata.org/wiki/Q21528959) +* [allowed qualifiers constraint (Q21510851)](https://www.wikidata.org/wiki/Q21510851) +* [required qualifier constraint (Q21510856)](https://www.wikidata.org/wiki/Q21510856) +* [single-value constraint (Q19474404)](https://www.wikidata.org/wiki/Q19474404): this will only trigger if you are adding more than one statement with the property on the same item, but will not detect any existing statement with this property. +* [distinct values constraint (Q21502410)](https://www.wikidata.org/wiki/Q21502410): similarly, this only checks for conflicts inside your edit batch. + +A comparison of the supported constraints with respect to other implementations is available [here](https://www.wikidata.org/wiki/Wikidata:WikiProject_property_constraints/reports/implementations). + +## Generic issues {#generic-issues} + +OpenRefine also detects issues that are not flagged (yet) by constraint violations on Wikidata: +* Statements without references. This does not rely on [citation needed constraint (Q54554025)](https://www.wikidata.org/wiki/Q54554025): all statements are expected to have references. (The idea is that when importing a dataset, every statement you add +* should link to this dataset - it does not hurt to do it even for generic properties such as [instance of (P31)](https://www.wikidata.org/wiki/Property:P31).) +* Spurious whitespace and non-printable characters in strings (including labels, descriptions and aliases); +* Self-referential statements (statements which mention the item they belong to); +* New items created without any label; +* New items created without any description; +* New items created without any [instance of (P31)](https://www.wikidata.org/wiki/Property:P31) or [subclass of (P279)](https://www.wikidata.org/wiki/Property:P279) statement. diff --git a/OpenRefine/docs/docs/manual/wikibase/reconciling.md b/OpenRefine/docs/docs/manual/wikibase/reconciling.md new file mode 100644 index 000000000..0e5625c9f --- /dev/null +++ b/OpenRefine/docs/docs/manual/wikibase/reconciling.md @@ -0,0 +1,45 @@ +--- +id: reconciling +title: Reconciling with Wikibase +sidebar_label: Reconciling with Wikibase +--- + +The Wikidata [reconciliation service](reconciling) for OpenRefine [supports](https://reconciliation-api.github.io/testbench/): +* A large number of potential types to reconcile against +* Previewing and viewing entities +* Suggesting entities, types, and properties +* Augmenting your project with more information pulled from Wikidata. + +You can find documentation and further resources on the reconciliation API [here](https://wikidata.reconci.link/). + +For the most part, Wikidata reconciliation behaves the same way other reconciliation services do, but there are a few processes and features specific to Wikidata. + +## Language settings {#language-settings} + +You can install a version of the Wikidata reconciliation service that uses your language. First, you need the language code: this is the [two-letter code found on this list](https://en.wikipedia.org/wiki/List_of_Wikipedias), or in the domain name of the desired Wikipedia/Wikidata (for instance, “fr†if your Wikipedia is https://fr.wikipedia.org/wiki/). + +Then, open the reconciliation window (under Reconcile → Start reconciling...) and click Add Standard Service. The URL to enter is `https://wikidata.reconci.link/fr/api`, where “fr†is your desired language code. + +When reconciling using this interface, items and properties will be displayed in your chosen language if the label is available. The matching score of the reconciliation is not influenced by your choice of language for the service: items are matched by considering all labels and returning the best possible match. The language of your dataset is also irrelevant to your choice of language for the reconciliation service; it simply determines which language labels to return based on the entity chosen. + +## Restricting matches by type {#restricting-matches-by-type} + +In Wikidata, types are items themselves. For instance, the [university of Ljubljana (Q1377)](https://www.wikidata.org/wiki/Q1377) has the type [public university (Q875538)](https://www.wikidata.org/wiki/Q875538), using the [instance of (P31)](https://www.wikidata.org/wiki/Property:P31) property. Types can be subclasses of other types, using the [subclass of (P279)](https://www.wikidata.org/wiki/Property:P279) property. For instance, [public university (Q875538)](https://www.wikidata.org/wiki/Q875538) is a subclass of [university (Q3918)](https://www.wikidata.org/wiki/Q3918). You can visualize these structures with the [Wikidata Graph Builder](https://angryloki.github.io/wikidata-graph-builder/). + +When you select or enter a type for reconciliation, OpenRefine will include that type and all of its subtypes. For instance, if you select [university (Q3918)](https://www.wikidata.org/wiki/Q3918), then [university of Ljubljana (Q1377)](https://www.wikidata.org/wiki/Q1377) will be a possible match, though that item isn't directly linked to Q3918 - because it is directly linked to Q875538, the subclass of Q3918. + +Some items and types may not yet be set as an instance or subclass of anything (because Wikidata is crowdsourced). If you restrict reconciliation to a type, items without the chosen type will not appear in the results, except as a fallback, and will have a lower score. + +## Reconciling via unique identifiers {#reconciling-via-unique-identifiers} + +You can supply a column of unique identifiers (in the form "Q###" for entities) directly to Wikidata in order to pull more data, but [these strings will not be “reconciled†against the external dataset](reconciling#reconciling-with-unique-identifiers). Apply the operation Reconcile → Use values as identifiers on your column of QIDs. All cells will appear as dark blue “confirmed†matches. Some of the “matches†may be errors, which you will need to hover over or click on to identify. You cannot use this to reconcile properties (in the form "P###"). + +If the identifier you submit is assigned to multiple Wikidata items (because Wikidata is crowdsourced), all of the items are returned as candidates, with none automatically matched. + +## Property paths, special properties, and subfields {#property-paths-special-properties-and-subfields} + +Wikidata's hierarchical property structure can be called by using property paths (using |, /, and . symbols). Labels, aliases, descriptions, and sitelinks can also be accessed. You can also match values against subfields, such as latitude and longitude subfields of a geographical coordinate. + +For information on how to do this, read the [documentation and further resources here](https://wikidata.reconci.link/#documentation). + + diff --git a/OpenRefine/docs/docs/manual/wikibase/schema-alignment.md b/OpenRefine/docs/docs/manual/wikibase/schema-alignment.md new file mode 100644 index 000000000..112c1a45c --- /dev/null +++ b/OpenRefine/docs/docs/manual/wikibase/schema-alignment.md @@ -0,0 +1,253 @@ +--- +id: schema-alignment +title: Schema alignment +sidebar_label: Schema alignment +--- + +A Wikibase schema is a template of Wikidata edits that is applied +to each row in the project. This page describes how each part of this +template works, and how it generates edits depending on the contents of +the table cells. + +## Items {#items} + +An item in the schema represents a set of changes on a particular +Wikidata item, generated by a single row. This item can contain changes +in [terms](#terms) (labels, descriptions and aliases) or +[statements](#statements). + +It is possible to make edits on different items for each row of your +table: just add multiple items in your schema. Each item has a subject, +which can be either entered manually (when the item on which the edits +should be made is the same for all rows), or any reconciled column can +be dropped in this field. In this case, the edits will depend on the +reconciliation status of each cell: + +- If the cell is matched to an item, edits will be made on that item; +- If the cell is marked as corresponding to a new item, a new item + will be created for it. See [New items](./new-entities) for more + details about how this works; +- If the cell has reconciliation candidates but has not been matched + to any of them, the edit will be skipped (even if there is only one + candidate with a high reconciliation score); +- If the cell is not reconciled or blank, the edit will be skipped. + +Do not worry about the ordering of items in the schema or the order of +your rows, as OpenRefine will rearrange your edits to optimize their +upload. If your project makes edits on the same item across multiple +rows, these edits will be merged together and performed in one edit. See +[Uploading your changes](./uploading) about that. + +## Terms {#terms} + +**Terms** are the language-specific strings that you find at the top of +Wikidata items: labels, descriptions and aliases. OpenRefine lets you +edit these terms via the Wikidata schema. + +### Languages {#languages} + +Each term belongs to a particular language. Wikidata supports [hundreds +of languages](https://www.wikidata.org/wiki/Help:Wikimedia_language_codes/lists/all), which +are designated by language codes. For each term that you want to add to +an item, you will need to specify the language for this term. There are +two cases: + +- Either the language is constant across your dataset: you know that + all the names in a given column are spelled in the same language. In + this case, type the name of the language in the input and select the + language in the drop-down suggestion dialog. This will place the + appropriate language code in the input. +- Or the language varies across your dataset. In this case, you need + to provide a column of Wikimedia language codes that indicates the + language for each term that you want to add. Just drag and drop this + column to the language field. If there are any invalid language + codes in this column, the corresponding terms will be ignored. + OpenRefine will translate any deprecated language codes to their + preferred values silently. + +### Labels {#labels} + +This is because Wikidata items can have at most one label per language, +so you need to choose whether to override any existing label (default +behaviour before 3.2) or only insert your label if there is no such +label in the given language (default behaviour starting from 3.2). When +the content of the cell providing the label is blank, nothing will be +changed (so, it is not possible to remove labels). + +### Descriptions {#descriptions} + +Descriptions work like labels: there is at most one description per +language, and OpenRefine can override existing descriptions or leave +them unchanged. It is not possible to remove descriptions either. + +### Aliases {#aliases} + +Aliases are added to the list of existing aliases in the given language. +When adding an alias in a language where no label has been added yet, +the alias is automatically promoted to a label for this language. It is +not possible to remove aliases or to override any existing aliases. + +## Statements {#statements} + +You can add statements in the schema: this will generate new statements +on the corresponding items. These statements will be merged with any +existing statements on the actual Wikidata items and [this merging process depends on the upload medium](./uploading#Merging-strategies-for-statements). +It is forecast to give more control over the merging strategy in the +near future. + +### Main values {#main-values} + +Statements must have main values: \"novalue\" or \"somevalue\" +statements are not supported yet. The main value of a statement is a +data value whose type depends on the property used for the statement. If +the main value cannot be evaluated (for instance because one of the +cells it depends on is empty), then the entire statement will be +skipped. + +See the [data values](#data-values) section for more details +about how to specify each type of data value and when they are skipped. + +### Qualifiers {#qualifiers} + +Qualifiers can be added on each statement. When their values are +skipped, only the qualifier will be discarded: the rest of the statement +will still be added. + +### References {#references} + +References can (and should) be added to back each statement. If values +inside the reference are skipped, the corresponding part of the +reference will be discarded but the reference will still be added +(unless the reference becomes empty). + +### Ranks {#ranks} + +All statements ranks are set to **Normal**. It is currently not possible +to set a different rank. + +## Data values {#data-values} + +Data values are the data that you can find as target of a statement (or +qualifier, or part of a reference). Each property dictates a particular +type of data value. In each case, OpenRefine uses a particular process +to translate cell contents to a data value of the appropriate type. This +section explains the process for all data types. + +### Items {#items-1} + +Items are evaluated in the same way as the subjects of items in the +schema. They can be input directly using the auto-suggest service +provided, or any column reconciled against Wikidata can be used. Refer to +[the first Items section](#items) to see how they are +evaluated. + +### Strings and external identifiers {#strings-and-external-identifiers} + +Bare strings and external identifiers can be input directly as constants +(if they do not change across rows) or using any column. If a reconciled +column is used for a string value, it is the value of the cell that is +going to be used, not the name of the reconciled item (which is what +OpenRefine displays). Values are skipped when the column is blank or +null. + +### Monolingual texts {#monolingual-texts} + +Monolingual texts consist of two parts: + +- the language: see [Languages](#languages) for their + structure; +- the value of the text: see [the section above](#strings-and-external-identifiers). + +A monolingual text is skipped when any of its parts is skipped (that is, +if the language or the text are invalid). + +### Dates {#dates} + +Dates are parsed from cell contents (or from any constant provided in +the schema) and the precision of the date is inferred from its format. +Here are the valid formats: + +- `YYYYM`, such as `2001M` (millenium precision) +- `YYYYC`, such as `1901C` (century precision) +- `YYYYD`, such as `1981D` (decade precision) +- `YYYY`, such as `1984` (year precision) +- `YYYY-MM`, such as `2019-03` (month precision) +- `YYYY-MM-DD`, such as `1897-08-14` (day precision) + +Any value that does not match any of these formats will be ignored. All +dates are represented in UTC, Gregorian calendar. + +In OpenRefine 3.3, the following new formats have been introduced: + +- `TODAY` returns today's date with day precision. This will be + evaluated when performing the edits (or exporting to + QuickStatements); +- `YYYY-MM-DD_QID` can be used to specify a date in a particular + calendar (such as the [proleptic Julian calendar (Q1985786)](https://www.wikidata.org/wiki/Q1985786). + +In OpenRefine 3.5, the following new format has been introduced: + +- `-234` represents the year 234 [BCE](https://en.wikipedia.org/wiki/Common_Era) + +### Quantities {#quantities} + +Quantities consist of two parts: the amount and the unit. + +- the amount is mandatory and must be a string, such as `18,229.1020`. + The precision that is displayed will be respected (the same number + of trailing zeros will be shown in Wikidata). By default, no upper + and lower bounds will be set. To define these, one needs to use the + engineering notation, such as `3.45E+3`, which will be interpreted + as `3,450±5`. As usual, the amount can be provided as a constant or + as a column variable. In the latter case, the values in the column + must be strings. +- the unit is optional. It is an item, so it can be provided either + with the auto-suggest dialog or as a reconciled column. It is + important to note that if a reconciled column is used, any + unreconciled cells will discard the entire quantity value. So a + template for a quantity value is either always unit-less, or always + has a unit. + +### Globe coordinates {#globe-coordinates} + +Geographic coordinates are specified as strings with the following +formats, where all components are floating point numbers in degrees: + +- `latitude,longitude` for a default precision of ten micro degrees + (for instance: + [`49.265278,4.028611`](https://tools.wmflabs.org/geohack/geohack.php?params=49.265277777778_N_4.0286111111111_E_globe:earth&language=en) + can be used indicate the position of Reims, France. + + +- `latitude,longitude,precision` when specifying an explicit precision + (for instance: `49.265278,4.028611,0.1` can be used indicate the + position of Reims within a tenth of a degree). + +All globe coordinates are on Earth ([Q2](https://www.wikidata.org/wiki/Q2)). + +If your coordinates are in a different format, such as +`49° 15′ 55″ N, 4° 1′ 43″ E`, you will need to convert them to decimal +format first. + +### Media on Commons {#media-on-commons} + +Media on Wikimedia Commons is treated like strings, whose values must +exactly match filenames on Commons. These values are not checked during +schema evaluations: if they are wrong, uploading the statements will +fail. + +Tabular data and Geoshapes must be prefixed with the `Data:` namespace. +This is indicated by the placeholder in the field that appears when +constructing the schema. + +### Properties {#properties} + +Properties are always constants: there is currently no way to reconcile +a column against properties. They have to be selected with the +auto-suggest dialog. + +### Other data types {#other-data-types} + +URLs, mathematical expressions and other textual datatypes are supported +and treated as strings. At the time of writing, all datatypes supported +by Wikidata are supported by OpenRefine. diff --git a/OpenRefine/docs/docs/manual/wikibase/uploading.md b/OpenRefine/docs/docs/manual/wikibase/uploading.md new file mode 100644 index 000000000..99da1259d --- /dev/null +++ b/OpenRefine/docs/docs/manual/wikibase/uploading.md @@ -0,0 +1,48 @@ +--- +id: uploading +title: Uploading edits to Wikibase +sidebar_label: Uploading edits +--- + +This page explains how to upload your edits to the target Wikibase. It assumes you already have a created a Wikibase schema in your OpenRefine project. + +## Uploading with OpenRefine {#uploading-with-openrefine} + +* Click Wikidata → Upload edits to Wikidata. +* Log in with your personal account or your bot account depending on which account you want to use to make the edits. It is a good practice to use a [bot password](https://www.mediawiki.org/wiki/Manual:Bot_passwords). +* Supply a meaningful edit summary. This is especially important because OpenRefine condenses all your changes on the same item as one edit: if you are making multiple changes, the edit summary generated by Wikibase will not indicate clearly what sort of change you made. If you are making atomic changes, such as adding a single alias or statement, the automatic edit summaries will be more meaningful. If supported by your Wikibase instance, OpenRefine will append a link to the [EditGroups](https://editgroups.toolforge.org/) tool, which lets you track and analyze your edit batch after upload. +* Click Perform edits and wait for the operation to complete. You can watch your edits being made by checking your wiki contributions or the EditGroups tool. + +Because performing edits in OpenRefine counts as an operation, you can extract this operation and reapply it to other projects. If you do so, you should also include the operation that saves the schema (only the last one is required), and make sure that the column names in the schema match those of the OpenRefine project where you are applying the operation. + +## Uploading with QuickStatements {#uploading-with-quickstatements} + +This requires that the Wikibase site has an associated [QuickStatements](https://meta.wikimedia.org/wiki/QuickStatements) tool. + +* Click Wikibase → Export to QuickStatements and copy the contents of the file; +* Go to QuickStatements (for Wikidata it can be found at https://quickstatements.toolforge.org/) and login to authorize the tool to use your account; +* Click Version 1 format; +* Paste the generated changes in the text area; +* Perform the edits with Run or Run in background. + +## Notable differences between the two methods {#notable-differences-between-the-two-methods} + +### Merging strategy for statements {#merging-strategy-for-statements} + +OpenRefine checks for existing statements which match not only the property and the target value, but also the qualifiers. On the other hand, QuickStatements ignores qualifiers when matching statements. +Both merging strategies can be useful depending on the properties. It is forecast to let the user configure the matching method in OpenRefine. + +If references are provided, both tools merge references in matching statements. + +### New item creation {#new-item-creation} + +OpenRefine supports creating new items with arbitrary relations between them. + +QuickStatements supports creating new items with the CREATE instruction, and subsequent instructions can use the LAST placeholder to use the Qid of the last created item. When generating QuickStatements instructions, OpenRefine reorders your edits so that this syntax can be used. In rare cases, such as when a statement links two newly-created items, it is impossible to use QuickStatements to perform the edit. In this case, no QuickStatements script will be generated. + +### Speed and number of edits {#speed-and-number-of-edits} + +OpenRefine generally performs one edit per item touched by an edit batch and at most two in general (in the case where new items contain links between them). This was chosen to minimize server load, speed up the upload and keep item histories compact. The downside is that the edit summaries can be less meaningful - it is therefore important that users supply informative summaries when uploading their batches. OpenRefine asymptotically edits at the rate of 60 edits per minute (so, usually 60 items per minute). The first edits are made more quickly, which is convenient for small batches. + +QuickStatements performs incremental edits (for instance, when adding a statement with a qualifier and a reference, it will make three edits). That generally means lower speed, but more explicit item histories. + diff --git a/OpenRefine/docs/docs/technical-reference/architecture.md b/OpenRefine/docs/docs/technical-reference/architecture.md new file mode 100644 index 000000000..e80d7015a --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/architecture.md @@ -0,0 +1,283 @@ +--- +id: architecture +title: Architecture +sidebar_label: Architecture +--- + +OpenRefine is a web application, but is designed to be run locally on your own machine. The server-side maintains states of the data (undo/redo history, long-running processes, etc.) while the client-side maintains states of the user interface (facets and their selections, view pagination, etc.). The client-side makes GET and POST ajax calls to cause changes to the data and to fetch data and data-related states from the server-side. + +This architecture provides a good separation of concerns (data vs. UI); allows the use of familiar web technologies (HTML, CSS, Javascript) to implement user interface features; and enables the server side to be called by third-party software through standard GET and POST operations. + +## Technology stack {#technology-stack} + +The server-side part of OpenRefine is implemented in Java as one single servlet which is executed by the [Jetty](http://jetty.codehaus.org/jetty/) web server + servlet container. The use of Java strikes a balance between performance and portability across operating systems (there is very little OS-specific code and has mostly to do with starting the application). + +OpenRefine has no database. It uses its own in-memory data-store that is built up-front to be optimized for the operations required by faceted browsing and infinite undo. + +The client-side part of OpenRefine is implemented in HTML, CSS and Javascript and uses the following libraries: +* [jQuery](http://jquery.com/) +* [jQueryUI](http:jqueryui.com/) +* [Recurser jquery-i18n](https://github.com/recurser/jquery-i18n) + +The functional extensibility of OpenRefine is provided by a fork of the [SIMILE Butterfly](https://github.com/OpenRefine/simile-butterfly) modular web application framework. + +Several projects provide the functionality to read and write custom format files (POI, opencsv, JENA, marc4j). + +String clustering is provided by the [SIMILE Vicino](http://code.google.com/p/simile-vicino/) project. + +OAuth functionality is provided by the [Signpost](https://github.com/mttkay/signpost) project. + +## Server-side architecture {#server-side-architecture} + +OpenRefine's server-side is written entirely in Java (`main/src/`) and its entry point is the Java servlet `com.google.refine.RefineServlet`. By default, the servlet is hosted in the lightweight Jetty web server instantiated by `server/src/com.google.refine.Refine`. Note that the server class itself is under `server/src/`, not `main/src/`; this separation leaves the possibility of hosting `RefineServlet` in a different servlet container. + +The web server configuration is in `main/webapp/WEB-INF/web.xml`; that's where `RefineServlet` is hooked up. `RefineServlet` itself is simple: it just reacts to requests from the client-side by routing them to the right `Command` class in the packages `com.google.refine.commands.**`. + +As mentioned before, the server-side maintains states of the data, and the primary class involved is `com.google.refine.ProjectManager`. + +### Projects {#projects} + +In OpenRefine there's the concept of a workspace similar to that in Eclipse. When you run OpenRefine it manages projects within a single workspace, and the workspace is embodied in a file directory with sub-directories. The default workspace directories are listed in the [FAQs](https://github.com/OpenRefine/OpenRefine/wiki/FAQ-Where-Is-Data-Stored). You can get OpenRefine to use a different directory by specifying a -d parameter at the command line. + +The class `ProjectManager` is what manages the workspace. It keeps in memory the metadata of every project (in the class `ProjectMetadata`). This metadata includes the project's name and last modified date, and any other information necessary to present and let the user interact with the project as a whole. Only when the user decides to look at the project's data would `ProjectManager` load the project's actual data. The separation of project metadata and data is to minimize the amount of stuff loaded into memory. + +A project's _actual_ data includes the columns, rows, cells, reconciliation records, and history entries. + +A project is loaded into memory when it needs to be displayed or modified, and it remains in memory until 1 hour after the last time it gets modified. Periodically the project manager tries to save modified projects, and it saves as many modified projects as possible within 30 seconds. + +### Data Model {#data-model} + +A project's data consists of + +- _raw data_: a list of rows, each row consisting of a list of cells +- _models_ on top of that raw data that give high-level presentation or interpretation of that data. This design lets the same raw data be viewed in different ways by different models, and let the models be changed without costly changes to the raw data. + +#### Column Model {#column-model} + +Cells in rows are not named and can only be addressed by their list position indices. So, a _column model_ is needed to give a name to each list position. The column model also stores other metadata for each column, including the type that cells in the column have been reconciled to and the overall reconciliation statistics of those cells. + +Each column also acts as a cache for data computed from the raw data related to that column. + +Columns in the column model can be removed and re-ordered without changing the raw data--the cells in the rows. This makes column removal and ordering operations really quick. + +##### Column Groups {#column-groups} + +Consider the following data: + +![Illustration of row groups in OpenRefine](https://raw.github.com/OpenRefine/OpenRefine/2.0/graphics/row-groups.png) + +Although the data is in a grid, we humans can understand that it is a tree. First of all, all rows contain data ultimately linked to the movie Austin Powers, although only one row contains the text "Austin Powers" in the "movie title" column. We also know that "USA" and "Germany" are not related to Elizabeth Hurley and Mike Myers respectively (say, as their nationality), but rather, "USA" and "Germany" are related to the movie (where it was released). We know that Mike Myers played both the character "Austin Powers" and the character "Dr. Evil"; and for the latter he received 2 awards. We humans can understand how to interpret the grid as a tree based on its visual layout as well as some knowledge we have about the movie domain but is not encoded in the table. + +OpenRefine can capture our knowledge of this transformation from grid to tree using _column groups_, also stored in the column model. Each column group illustrated as a blue bracket above specifies which columns are grouped together, as well as which of those columns is the key column in that group (blue triangle). One column group can span over columns grouped by another column group, and in this way, column groups form a hierarchy determined by which column group envelopes another. This hierarchy of column groups allows the 2-dimensional (grid-shaped) table of rows and cells to be interpreted as a list of hierarchical (tree-shaped) data records. + +Blank cells play a very important role. The blank cell in a key column of a row (e.g., cell "character" on row 4) makes that row (row 4) _depend_ on the first preceding row with that column filled in (row 3). This means that "Best Comedy Perf" on row 4 applies to "Dr. Evil" on row 3. Row 3 is said to be a _context row_ for row 4. Similarly, since rows 2 - 6 all have blank cells in the first column, they all depend on row 1, and all their data ultimately applies to the movie Austin Powers. Row 1 depends on no other row and is said to be a _record row_. Rows 1 - 6 together form one _record_. + +Currently (as of 12th December 2017) only the XML and JSON importers create column groups, and while the data table view does display column groups but it doesn't support modifying them. + +### Changes, History, Processes, and Operations {#changes-history-processes-and-operations} + +All changes to the project's data are tracked (N.B. this does not include changes to a project's metadata - such as the project name.) + +Changes are stored as `com.google.refine.history.Change` objects. `com.google.refine.history.Change` is an interface, and implementing classes are in `com.google.refine.model.changes.**`. Each change object stores enough data to modify the project's data when its `apply()` method is called, and enough data to revert its effect when its `revert()` method is called. It's only supposed to _store_ data, not to actually _compute_ the change. In this way, it's like a .diff patch file for a code base. + +Some change objects can be huge, as huge as the project itself. So change objects are not kept in memory except when they are to be applied or reverted. However, since we still need to show the user some information about changes (as displayed in the History panel in the UI), we keep metadata of changes separate from the change objects. For each change object there is one corresponding `com.google.refine.history.HistoryEntry` for storing its metadata, such as the change's human-friendly description and timestamp. + +Each project has a `com.google.refine.history.History` object that contains an ordered list of all `HistoryEntry` objects storing metadata for all changes that have been done since after the project was created. Actually, there are 2 ordered lists: one for done changes that can be reverted (undone), an done for undone changes that can be re-applied (redone). Changes must be done or redone in their exact orders in these lists because each change makes certain assumptions about the state of the project before and after it is applied. As changes cannot be undone/redone out of order, when one change fails to revert, it blocks the whole history from being reverted to any state preceding that change (as happened in [Issue #2](https://github.com/OpenRefine/OpenRefine/issues/2)). + +As mentioned before, a change contains only the diff and does not actually compute that diff. The computation is performed by a `com.google.refine.process.Process` object--every change object is created by a process object. A process can be immediate, producing its change object synchronously within a very short period of time (e.g., starring one row); or a process can be long-running, producing its change object after a long time and a lot of computation, including network calls (e.g., reconciling a column). + +As the user interacts with the UI on the client-side, their interactions trigger ajax calls to the server-side. Some calls are meant to modify the project. Those are handled by commands that instantiates processes. Processes are queued in a first-in-first-out basis. The first-in process gets run and until it is done all the other processes are stuck in the queue. + +A process can effect a change in one thing in the project (e.g., edit one particular cell, star one particular row), or a process can effect changes in _potentially_ many things in the project (e.g., edit zero or more cells sharing the same content, starring all rows filtered by some facets). The latter kind of process is generalizable: it is meaningful to apply them on another similar project. Such a process is associated with an _abstract operation_ `com.google.refine.model.AbstractOperation` that encodes the information necessary to create another instance of that process, but potentially for a different project. When you click "extract" in the History panel, these abstract operations are called to serialize their information to JSON; and when you click "apply" in the History panel, the JSON you paste in is used to re-construct these abstract operations, which in turn create processes, which get run sequentially in a queue to generate change object and history entry pairs. + +In summary, + +- change objects store diffs +- history entries store metadata of change objects +- processes compute diffs and create change object and history entry pairs +- some processes are long-running and some are immediate; processes are run sequentially in a queue +- generalizable processes can be re-constructed from abstract operations + +## Client-side architecture {#client-side-architecture} +The client-side part of OpenRefine is implemented in HTML, CSS and Javascript and uses the following Javascript libraries: +* [jQuery](http://jquery.com/) +* [jQueryUI](http:jqueryui.com/) +* [Recurser jquery-i18n](https://github.com/recurser/jquery-i18n) + +### Importing architecture {#importing-architecture} + +OpenRefine has a sophisticated architecture for accommodating a diverse and extensible set of importable file formats and work flows. The formats range from simple CSV, TSV to fixed-width fields to line-based records to hierarchical XML and JSON. The work flows allow the user to preview and tweak many different import settings before creating the project. In some cases, such as XML and JSON, the user also has to select which elements in the data file to import. Additionally, a data file can also be an archive file (e.g., .zip) that contains many files inside; the user can select which of those files to import. Finally, extensions to OpenRefine can inject functionalities into any part of this architecture. + +### The Index Page and Action Areas {#the-index-page-and-action-areas} + +The opening screen of OpenRefine is implemented by the file refine/main/webapp/modules/core/index.vt and will be referred to here as the index page. Its default implementation contains 3 finger tabs labeled Create Project, Open Project, and Import Project. Each tab selects an "action area". The 3 default action areas are for, obviously, creating a new project, opening an existing project, and importing a project .tar file. + +Extensions can add more action areas in Javascript. For example, this is how the Create Project action area is added (refine/main/webapp/modules/core/scripts/index/create-project-ui.js): + +```javascript +Refine.actionAreas.push({ + id: "create-project", + label: "Create Project", + uiClass: Refine.CreateProjectUI +}); +``` + +The UI class is a constructor function that takes one argument, a jQuery-wrapped HTML element where the tab body of the action area should be rendered. + +If your extension requires a very unique importing work flow, or a very novel feature that should be exposed on the index page, then add a new action area. Otherwise, try to use the existing work flows as much as possible. + +### The Create Project Action Area {#the-create-project-action-area} + +The Create Project action area is itself extensible. Initially, it embeds a set of finger tabs corresponding to a variety of "source selection UIs": you can select a source of data by specifying a file on your computer, or you can specify the URL to a publicly accessible data file or data feed, or you can paste in from the clipboard a chunk of data. + +There are actually 3 points of extension in the Create Project action area, and the first is invisible. + +#### Importing Controllers {#importing-controllers} + +The Create Project action area manages a list of "importing controllers". Each controller follows a particular work flow (in UI terms, think "wizard"). Refine comes with a "default importing controller" (refine/main/webapp/modules/core/scripts/index/default-importing-controller/controller.js) and its work flow assumes that the data can be retrieved and cached in whole before getting processed in order to generate a preview for the user to inspect. (If the data cannot be retrieved and cached in whole before previewing, then another importing controller is needed.) + +An importing controller is just programming logic, but it can manifest itself visually by registering one or more data source UIs and one or more custom panels in the Create Project action area. The default importing controller registers 3 such custom panels, which act like pages of a wizard. + +An extension can register any number of importing controller. Each controller has a client-side part and a server-side part. Its client-side part is just a constructor function that takes an object representing the Create Project action area (usually named `createProjectUI`). The controller (client-side) is expected to use that object to register data source UIs and/or create custom panels. The controller is not expected to have any particular interface method. The default importing controller's client-side code looks like this (refine/main/webapp/modules/core/scripts/index/default-importing-controller/controller.js): + +```javascript +Refine.DefaultImportingController = function(createProjectUI) { + this._createProjectUI = createProjectUI; // save a reference to the create project action area + + this._progressPanel = createProjectUI.addCustomPanel(); // create a custom panel + this._progressPanel.html('...'); // render the custom panel + ... do other stuff ... +}; +Refine.CreateProjectUI.controllers.push(Refine.DefaultImportingController); // register the controller +``` + +We will cover the server-side code below. + +#### Data Source Selection UIs {#data-source-selection-uis} + +Data source selection UIs are another point of extensibility in the Create Project action area. As mentioned previously, by default there are 3 data source UIs. Those are added by the default importing controller. + +Extensions can also add their own data source UIs. A data source selection UI object can be registered like so + +```javascript +createProjectUI.addSourceSelectionUI({ + label: "This Computer", + id: "local-computer-source", + ui: theDataSourceSelectionUIObject +}); +``` + +`theDataSourceSelectionUIObject` is an object that has the following member methods: + +- `attachUI(bodyDiv)` +- `focus()` + +If you want to install a data source selection UI that is managed by the default importing controller, then register its UI class with the default importing controller, like so (refine/main/webapp/modules/core/scripts/index/default-importing-sources/sources.js): + +```javascript +Refine.DefaultImportingController.sources.push({ + "label": "This Computer", + "id": "upload", + "uiClass": ThisComputerImportingSourceUI +}); +``` + +The default importing controller will assume that the `uiClass` field is a constructor function and call it with one argument--the controller object itself. That constructor function should save the controller object for later use. More specifically, for data source UIs that use the default importing controller, they can call the controller to kickstart the process that retrieves and caches the data to import: + +```javascript +controller.startImportJob(form, "... status message ..."); +``` + +The argument `form` is a jQuery-wrapped FORM element that will get submitted to the server side at the command /command/core/create-importing-job. That command and the default importing controller will take care of uploading or downloading the data, caching it, updating the client side's progress display, and then showing the next importing step when the data is fully cached. + +See refine/main/webapp/modules/core/scripts/index/default-importing-sources/sources.js for examples of such source selection UIs. While we write about source selection UIs managed by the default importing controller here, chances are your own extension will not be adding such a new source selection UI. Your extension probably adds with a new importing controller as well as a new source selection UI that work together. + +#### File Selection Panel {#file-selection-panel} +Documentation not currently available + +#### Parsing UI Panel {#parsing-ui-panel} +Documentation not currently available + +### Server-side Components {#server-side-components} + +#### ImportingController {#importingcontroller} +Documentation not currently available + +#### UrlRewriter {#urlrewriter} +Documentation not currently available + +#### FormatGuesser {#formatguesser} +Documentation not currently available + +#### ImportingParser {#importingparser} +Documentation not currently available + + +## Faceted browsing architecture {#faceted-browsing-architecture} + +Faceted browsing support is core to OpenRefine as it is the primary and only mechanism for filtering to a subset of rows on which to do something _en masse_ (ie in bulk). Without faceted browsing or an equivalent querying/browsing mechanism, you can only change one thing at a time (one cell or row) or else change everything all at once; both kinds of editing are practically useless when dealing with large data sets. + +In OpenRefine, different components of the code need to know which rows to process from the faceted browsing state (how the facets are constrained). For example, when the user applies some facet selections and then exports the data, the exporter serializes only the matching rows, not all rows in the project. Thus, faceted browsing isn't only hooked up to the data view for displaying data to the user, but it is also hooked up to almost all other parts of the system. + +### Engine Configuration {#engine-configuration} + +As OpenRefine is a web app, there might be several browser windows opened on the same project, each in a different faceted browsing state. It is best to maintain the faceted browsing state in each browser window while keeping the server side completely stateless with regard to faceted browsing. Whenever the client-side needs something done by the server, it transfers the entire faceted browsing state over to the server-side. The faceted browsing state behaves much like the `WHERE` clause in a SQL query, telling the server-side how to select the rows to process. + +In fact, it is best to think of the faceted browsing state as just a database query much like a SQL query. It can be passed around the whole system, to any component needing to know which rows to process. It is serialized into JSON to pass between the client-side and the server side, or to save in an abstract operation's specification. The job of the faceted browsing subsystem on the client-side is to let the user interactively modify this "faceted browsing query", and the job of the faceted browsing subsystem on the server side is to resolve that query. + +In the code, the faceted browsing state, or faceted browsing query, is actually called the *engine configuration* or *engine config* for short. It consists mostly of an array facet configurations. For each facet, it stores the name of the column on which the facet is based (or an empty string if there is no base column). Each type of facet has different configuration. Text search facets have queries and flags for case-sensitivity mode and regular expression mode. Text facets (aka list facets) and numeric range facets have expressions. Each list facet also has an array of selected choices, an invert flag, and flags for whether blank and error cells are selected. Each numeric range facet has, among other things, a "from" and a "to" values. If you trace the AJAX calls, you'd see the engine configs being shuttled, e.g., + +```json +{ + "facets" : [ + { + "type": "text", + "name": "Shrt_Desc", + "columnName": "Shrt_Desc", + "mode": "text", + "caseSensitive": false, + "query": "cheese" + }, + { + "type": "list", + "name": "Shrt_Desc", + "columnName": "Shrt_Desc", + "expression": "grel:value.toLowercase().split(\",\")", + "omitBlank": false, + "omitError": false, + "selection": [], + "selectBlank":false, + "selectError":false, + "invert":false + }, + { + "type": "range", + "name": "Water", + "expression": "value", + "columnName": "Water", + "selectNumeric": true, + "selectNonNumeric": true, + "selectBlank": true, + "selectError": true, + "from": 0, + "to": 53 + } + ], + "includeDependent": false + } +``` + +### Server-Side Subsystem {#server-side-subsystem} + +From an engine configuration like the one above, the server-side faceted browsing subsystem is capable of producing: + +- an iteration over the rows matching the facets' constraints +- information on how to render the facets (e.g., choice and count pairs for a list facet, histogram for a numeric range facet) + +When the engine config JSON arrives in an HTTP request on the server-side, a `com.google.refine.browsing.Engine` object is constructed and initialized with that JSON. It in turns constructs zero or more `com.google.refine.browsing.facets.Facet` objects. Then for each facet, the engine calls its `getRowFilter()` method, which returns `null` if the facet isn't constrained in anyway, or a `com.google.refine.browsing.filters.RowFilter` object. Then, to when iterating over a project's rows, the engine calls on all row filters' `filterRow()` method. If and only if all row filters return `true` the row is considered to match the facets' constraints. How each row filter works depends on the corresponding type of facet. + +To produce information on how to render a particular facet in the UI, the engine follows the same procedure described in the previous except it skips over the facet in question. In other words, it produces an iteration over all rows constrained by the other facets. Then it feeds that iteration to the facet in question by calling the facet's `computeChoices()` method. This gives the method a chance to compute the rendering information for its UI counterpart on the client-side. When all facets have been given a chance to compute their rendering information, the engine calls all facets to serialize their information as JSON and returns the JSON to the client-side. Only one HTTP call is needed to compute all facets. + +### Client-side subsystem {#client-side-subsystem} + +On the client-side there is also an engine object (implemented in Javascript rather than Java) and zero or more facet objects (also in Javascript, obviously). The engine is responsible for distributing the rendering information computed on the server-side to the right facets, and when the user interacts with a facet, the facet tells the engine to update the whole UI. To do so, the engine gathers the configuration of each facet and composes the whole engine config as a single JSON object. Two separate AJAX calls are made with that engine config, one to retrieve the rows to render, and one to re-compute the rendering information for the facets because changing one facet does affect all the other facets. diff --git a/OpenRefine/docs/docs/technical-reference/build-test-run.md b/OpenRefine/docs/docs/technical-reference/build-test-run.md new file mode 100644 index 000000000..300784ac8 --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/build-test-run.md @@ -0,0 +1,283 @@ +--- +id: build-test-run +title: How to build, test and run +sidebar_label: How to build, test and run +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; + + +You will need: +* [OpenRefine source code](https://github.com/OpenRefine/OpenRefine) +* [Java JDK](http://java.sun.com/javase/downloads/index.jsp) (Get [OpenJDK from here](https://jdk.java.net/15/).) +* [Apache Maven](https://maven.apache.org) (OPTIONAL) +* A Unix/Linux shell environment OR the Windows command line + +From the top level directory in the OpenRefine application you can build, test and run OpenRefine using the `./refine` shell script (if you are working in a \*nix shell), or using the `refine.bat` script from the Windows command line. Note that the `refine.bat` on Windows only supports a subset of the functionality, supported by the `refine` shell script. The example commands below are using the `./refine` shell script, and you will need to use `refine.bat` if you are working from the Windows command line. + +### Get OpenRefine source code + +With Git installed, use the `git clone` command to download the [project's repo](https://github.com/OpenRefine/OpenRefine) to a directory of your choice. + +### Set up JDK {#set-up-jdk} + +You must [install JDK](https://jdk.java.net/15/) and set the JAVA_HOME environment variable (please ensure it points to the JDK, and not the JRE). + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + + +1. On Windows 10, click the Start Menu button, type `env`, and look at the search results. Click Edit the system environment variables. (If you are using an earlier version of Windows, use the “Search†or “Search programs and files†box in the Start Menu.) + +![A screenshot of the search results for 'env'.](/img/env.png "A screenshot of the search results for 'env'.") + +2. Click Environment Variables… at the bottom of the Advanced window. +3. In the Environment Variables window that appears, click New… and create a variable with the key `JAVA_HOME`. You can set the variable for only your user account, as in the screenshot below, or set it as a system variable - it will work either way. + +![A screenshot of 'Environment Variables'.](/img/javahome.png "A screenshot of 'Environment Variables'.") + +4. Set the `Value` to the folder where you installed JDK, in the format `D:\Programs\OpenJDK`. You can locate this folder with the Browse directory... button. + + + + + +First, find where Java is on your computer with this command: + +``` +which java +``` + +Check the environment variable `JAVA_HOME` with: + +``` +$JAVA_HOME/bin/java --version +``` + +To set the environment variable for the current Java version of your MacOS: + +``` +export JAVA_HOME="$(/usr/libexec/java_home)" +``` + +Or, for Java 13.x: + +``` +export JAVA_HOME="$(/usr/libexec/java_home -v 13)" +``` + + + + + +##### With the terminal {#with-the-terminal} + +Enter the following: + +``` +sudo apt install default-jre +``` + +This probably won’t install the latest JDK package available on the Java website, but it is faster and more straightforward. (At the time of writing, it installs OpenJDK 11.0.7.) + +##### Manually {#manually} + +First, [extract the JDK package](https://openjdk.java.net/install/) to the new directory `usr/lib/jvm`: + +``` +sudo mkdir -p /usr/lib/jvm +sudo tar -x -C /usr/lib/jvm -f /tmp/openjdk-14.0.1_linux-x64_bin.tar.gz +``` + +Then, navigate to this folder and confirm the final path (in this case, `usr/lib/jvm/jdk-14.0.1`). Open a terminal and type + +``` +sudo gedit /etc/profile +``` + +In the text window that opens, insert the following lines at the end of the `profile` file, using the path above: + +``` +JAVA_HOME=/usr/lib/jvm/jdk-14.0.1 +PATH=$PATH:$HOME/bin:$JAVA_HOME/bin +export JAVA_HOME +export PATH +``` + +Note: OpenRefine on Linux currently supports jdk versions 8 to 15. Reference: [Issue 4106](https://github.com/OpenRefine/OpenRefine/issues/4106). + +Save and close the file. When you are back in the terminal, type + +``` +source /etc/environment +``` + +Exit the terminal and restart your system. You can then check that `JAVA_HOME` is set properly by opening another terminal and typing +``` +echo $JAVA_HOME +``` + +It should show the path you set above. + + + + + +--- + + + +### Maven (Optional) {#maven-optional} +OpenRefine's build script will download Maven for you and use it, if not found already locally installed. + +If you will be using your Maven installation instead of OpenRefine's build script download installation, then set the `MVN_HOME` environment variable. You may need to reboot your machine after setting these environment variables. If you receive a message `Could not find the main class: com.google.refine.Refine. Program will exit.` it is likely `JAVA_HOME` is not set correctly. + +Ensure that you set your `MAVEN_HOME` environment variable, for example: + +```shell +MAVEN_HOME=E:\Downloads\apache-maven-3.5.4-bin\apache-maven-3.5.4\ +``` + +NOTE: You can use Maven commands directly, but running some goals in isolation might fail (try adding the `compile test-compile` goals in your invocation if that is the case). + +### Building {#building} + +To see what functions are supported by OpenRefine's build system, type +```shell +./refine -h +``` + +To build the OpenRefine application from source type: +```shell +./refine clean +./refine build +``` + +### Testing {#testing} +Since OpenRefine is composed of two parts, a server and a in-browser UI, the testing system reflects that: + +* on the server side, it's powered by [TestNG](http://testng.org/) and the unit tests are written in Java; +* on the client side, we use [Cypress](https://www.cypress.io/) and the tests are written in Javascript + +To run all tests, use: +```shell +./refine test +``` +**this option is not available when using refine.bat** + + +If you want to run only the server side portion of the tests, use: +```shell +./refine server_test +``` + +If you are running the UI tests for the first time, [you must go through the installation process.](functional-tests) +If you want to run only the client side portion of the tests, use: +```shell +./refine ui_test chrome +``` + +## Running {#running} +To run OpenRefine from the command line (assuming you have been able to build from the source code successfully) +```shell +./refine +``` +By default, OpenRefine will use [refine.ini](https://github.com/OpenRefine/OpenRefine/blob/master/refine.ini) for configuration. You can copy it and rename it to `refine-dev.ini`, which will be used for configuration instead. `refine-dev.ini` won't be tracked by Git, so feel free to put your custom configurations into it. + +## Building Distributions (Kits) {#building-distributions-kits} + +The Refine build system uses Apache Ant to automate the creation of the installation packages for the different operating systems. The packages are currently optimized to run on Mac OS X which is the only platform capable of creating the packages for all three OS that we support. + +To build the distributions type + +```shell +./refine dist +``` +where 'version' is the release version. + +## Building, Testing and Running OpenRefine from Eclipse {#building-testing-and-running-openrefine-from-eclipse} +OpenRefine' source comes with Maven configuration files which are recognized by [Eclipse](http://www.eclipse.org/) if the Eclipse Maven plugin (m2e) is installed. + +At the command line, go to a directory **not** under your Eclipse workspace directory and check out the source: + +```shell +git clone https://github.com/OpenRefine/OpenRefine.git +``` + +In Eclipse, invoke the `Import...` command and select `Existing Maven Projects`. + +![Screenshot of Import a Maven project option](/img/eclipse-import-maven-project-1.png) + +Choose the root directory of your clone of the repository. You get to choose which modules of the project will be imported. You can safely leave out the `packaging` module which is only used to generate the Linux, Windows and MacOS distributions. + +Screenshot of Select maven projects to import + +To run and debug OpenRefine from Eclipse, you will need to add an execution configuration on the `server` sub-project. +Right click on the `server` subproject, click `Run as...` and `Run configurations...` and create a new `Maven Build` run configuration. Rename the run configuration `OpenRefine`. Enter the root directory of the project as `Base directory` and use `exec:java` as a Maven goal. + +![Screenshot of Add a run configuration with the exec:java goal](/img/eclipse-exec-config.png) + +This will add a run configuration that you can then use to run OpenRefine from Eclipse. + +## Code style in Eclipse + +You can apply the supplied Eclipse code style (in `IDEs/eclipse/Refine.style.xml`) to make sure Eclipse lints your files according to the existing style. +Pull requests deviating from this style will fail in the CI. + +You can manually apply the code style (regardless of your IDE) with the `mvn formatter:format` command. + +## Testing in Eclipse {#testing-in-eclipse} + +You can run the server tests directly from Eclipse. To do that you need to have the TestNG launcher plugin installed, as well as the TestNG M2E plugin (for integration with Maven). If you don't have it, you can get it by [installing new software](https://help.eclipse.org/2020-03/index.jsp?topic=/org.eclipse.platform.doc.user/tasks/tasks-129.htm) from this update URL http://dl.bintray.com/testng-team/testng-eclipse-release/ + +Once the TestNG launching plugin is installed in your Eclipse, right click on the source folder "main/tests/server/src", select `Run As` -> `TestNG Test`. This should open a new tab with the TestNG launcher running the OpenRefine tests. + +### Test coverage in Eclipse {#test-coverage-in-eclipse} + +It is possible to analyze test coverage in Eclipse with the `EclEmma Java Code Coverage` plugin. It will add a `Coverage as…` menu similar to the `Run as…` and `Debug as…` menus which will then display the covered and missed lines in the source editor. + +### Debug with Eclipse {#debug-with-eclipse} +Here's an example of putting configuration in Eclipse for debugging, like putting values for the Google Data extension. Other type of configurations that can be set are memory, Wikidata login information and more. + +![Screenshot of Eclipse debug configuration](/img/eclipse-debug-config.png) + +## Building, Testing and Running OpenRefine from IntelliJ idea {#building-testing-and-running-openrefine-from-intellij-idea} + +At the command line, go to a directory you want to save the OpenRefine project and execute the following command to clone the repository: + +```shell +git clone https://github.com/OpenRefine/OpenRefine.git +``` + +Then, open the IntelliJ idea and go to `file -> open` and select the location of the cloned repository. + +![Screenshot of Open option on the IntelliJ File menu](/img/intellij-setup-1.png) + +It will prompt you to add as a maven project as the source code contains a pom.xml file in it. Allow `auto-import` so that it can add it as a maven project. +If it doesn't prompt something like this then you can go on the right side of the IDE and click on maven then, click on `reimport all the maven projects` that will add all the dependencies and jar files required for the project. + +![Screenshot of Maven project controls in IntelliJ](/img/intellij-maven.png) + +After this, you will be able to properly build, test, and run the OpenRefine project from the terminal. +But if you will go to any of the test folders and open some file it will show you some import errors because the project isn't yet set up at the module level. + +For removing those errors, and enjoying the features of the IDE like ctrl + click, etc you need to set up the project at the module level too. Open the different modules like `extensions/wikidata`, `main` as a project in the IDE. Then, right-click on the project folder and open the module settings. + +![Screenshot of open module settings menu in IntelliJ](/img/intellij-open-module-settings.png) + +In the module settings, add the source folder and test source folders of that module. + +![Screenshot of module settings in IntelliJ](/img/intellij-module-settings.png) + +Then, do the same thing for the main OpenRefine project and now you are good to go. diff --git a/OpenRefine/docs/docs/technical-reference/contributing.md b/OpenRefine/docs/docs/technical-reference/contributing.md new file mode 100644 index 000000000..a9151abf7 --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/contributing.md @@ -0,0 +1,70 @@ +--- +id: contributing +title: Contributing +sidebar_label: Contributing +--- + +Please read the general [guidelines on contributing to OpenRefine](https://github.com/OpenRefine/OpenRefine/blob/master/CONTRIBUTING.md) first, then review the information on [reporting and tracking issues](#reporting-and-tracking-issues), and on making your [first pull request](#your-first-pull-request) below) + +## Reporting and tracking issues {#reporting-and-tracking-issues} + +If you need to file a bug or request a feature, [create an Issue in the OpenRefine Github repository](https://github.com/OpenRefine/OpenRefine/issues). Github issues should be used for reporting specific bugs and requesting specific features. If you just don't know how to do something using OpenRefine, or want to discuss some ideas, please: + +- [Try the user manual](/) +- [post to our OpenRefine mailing list](http://groups.google.com/group/openrefine/) + +## Contributing to the documentation {#contributing-to-the-documentation} + +We use [Docusaurus](https://docusaurus.io/) for our docs. For small documentation changes, you should be able to edit the Markdown files directly and submit them as a pull request. A preview of the docs will be generated automatically. But it is also +possible to preview your changes locally. Assuming you have [Node.js](https://nodejs.org/en/download/) installed (which includes npm), you can install Docusaurus with: + +You will need to install [Yarn](https://yarnpkg.com/getting-started/install) before you can build the site. +```sh +npm install -g yarn +``` + +Once you have installed yarn, navigate to docs directory & set-up the dependencies. + +```sh +cd docs +yarn +``` + +Once this is done, generate the docs with: + +```sh +yarn build +``` + +You can also spin a local web server to serve the docs for you, with auto-refresh when you edit the source files, with: +```sh +yarn start +``` + +## Your first code pull request {#your-first-code-pull-request} + +This describes the overall steps to your first code contribution in OpenRefine. If you have trouble with any of these steps feel free to reach out on the [developer mailing list](https://groups.google.com/forum/#!forum/openrefine-dev) or the [Gitter channel](https://gitter.im/OpenRefine/OpenRefine). + +- Install OpenRefine, learn to use it by following some tutorials or watching [some videos](http://openrefine.org/). That will ensure you understand the user workflows and get familiar with the terminology used in the tool. + +- Fork the GitHub repository, clone it on your machine and set up your IDE to work on it. We have [instructions for this](https://github.com/OpenRefine/OpenRefine/wiki/Building-OpenRefine-From-Source). + +- Browse through the list of issues to find an issue that you find interesting. You should pick one where you understand what the problem is as a user, you can see why fixing it would be an improvement to the tool. It is also a good idea to pick an issue that matches your technical skills: some require work on the backend (in Java) or in the frontend (Javascript), often both. We try to maintain a list of [good first issues](https://github.com/OpenRefine/OpenRefine/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) which should be easier than others and should not require any difficult design decision. + +- Reproduce the issue locally, by following the steps described in the issue. You might need to locate a particular dialog, use a specific importer on a sample file, or follow any other user workflow. If you have followed all the steps described in the issue and cannot observe the issue mentioned, write a comment on the issue explaining that you are not able to reproduce it (perhaps it was fixed by another change). + +- Locate the code that is relevant for the issue you want to solve. Text search across files is often useful for that. For instance, if the issue you want to solve is about a dialog entitled "Columnize by key/values", you can search for "Columnize" in the entire source code. For more details about this technique, see [this comment](https://github.com/OpenRefine/OpenRefine/issues/3137#issuecomment-691649962). + +- Study how the current code works. You might want to use a debugger to put breakpoints at the relevant locations (for inspecting the backend, use your IDE's debugger, for the frontend, use your browser's developer tools). + +- Create a git branch for your fix. The name of your branch should contain the issue number, and a few words to describe the topic of the fix, for instance "issue-1234-columnize-layout". + +- Make changes to the code to fix the issue. If you are changing backend code, it would be great if you could also write a test in Java to demonstrate the fix. You can imitate existing tests for that. We currently do not have frontend tests. + +- If you made Java changes, run linting to make sure they conform to our code style, with `mvn formatter:format`. + +- commit your changes, using a message that contains one of the special words "closes" and "fixes" which are detected by Github, followed by the issue number, e.g. "closes #1234" or "fixes #1234", this will link the commit to the issue you are working on. + +- push your branch to your fork and create a pull request for it, explaining the approach you have used, any design decisions you have made. + +Thank you! diff --git a/OpenRefine/docs/docs/technical-reference/development-roadmap.md b/OpenRefine/docs/docs/technical-reference/development-roadmap.md new file mode 100644 index 000000000..da35f2f77 --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/development-roadmap.md @@ -0,0 +1,29 @@ +--- +id: development-roadmap +title: Development roadmap +sidebar_label: Development roadmap +--- + +Please be aware that the OpenRefine roadmap is subject to change at any time, so please check back regularly, and monitor [milestones](https://github.com/OpenRefine/OpenRefine/milestones), [projects](https://github.com/OpenRefine/OpenRefine/projects) and [issues](https://github.com/OpenRefine/OpenRefine/issues) in Github to keep up to date with current plans. + +If there are features you would like to see that are not currently listed here or in current [milestones](https://github.com/OpenRefine/OpenRefine/milestones), [projects](https://github.com/OpenRefine/OpenRefine/projects) and [issues](https://github.com/OpenRefine/OpenRefine/issues), please add them to the [issue tracker](https://github.com/OpenRefine/OpenRefine/issues). + + +## Planned releases {#planned-releases} + +### 4.0 {#40} +[New backend storage option to allow using much bigger datasets at the expense of real-time feedback.](https://github.com/OpenRefine/OpenRefine/milestone/7) + +New UI (possibly Vue or React based) + +## Work in progress {#work-in-progress} +Alongside the planned releases there are often smaller pieces of work in progress. Check for [recently updated issues](https://github.com/OpenRefine/OpenRefine/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) and [pull requests](https://github.com/OpenRefine/OpenRefine/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc) to see what is currently in the works. + +## On the back burner {#on-the-back-burner} +Some aspects of OpenRefine have previously been targeted for release, but have not made it into a release and have not been worked on recently. If you would like to see features in these areas, please create an issue the describes what development you would like to see: + +- Streamlining traditional features +- Views: map, timeline, protovis (D3.js) charts +- Better machinery to guess and re-encode cell values (useful for fixing encoding issues) +- Collaborative editing support (see documentation on the '[broker protocol](https://github.com/OpenRefine/OpenRefine/wiki/Broker-Protocol)' to see where this work was going) +- Column groups diff --git a/OpenRefine/docs/docs/technical-reference/functional-tests.md b/OpenRefine/docs/docs/technical-reference/functional-tests.md new file mode 100644 index 000000000..afdfbe43c --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/functional-tests.md @@ -0,0 +1,241 @@ +--- +id: functional-tests +title: Functional tests +sidebar_label: Functional tests +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; + +## Introduction {#introduction} + +OpenRefine interface is tested with the [Cypress framework](https://www.cypress.io/). +With Cypress, tests are performing assertions using a real browser, the same way a real user would use the software. + +Cypress tests can be ran + +- using the Cypress test runner (development mode) +- using a command line (CI/CD mode) + +If you are writing tests, the Cypress test runner is good enough, and the command-line is mainly used by the CI/CD platform (Github actions) + +## Cypress brief overview {#cypress-brief-overview} + +Cypress operates insides a browser, it's internally using NodeJS. +That's a key difference with tools such as Selenium. + +**From the Cypress documentation:** + +> But what this also means is that your test code **is being evaluated inside the browser**. Test code is not evaluated in Node, or any other server side language. The **only** language we will ever support is the language of the web: JavaScript. + +Good starting points with Cypress are the [Getting started guide](https://docs.cypress.io/guides/getting-started/writing-your-first-test.html#Write-your-first-test), and the [Trade-offs](https://docs.cypress.io/guides/references/trade-offs.html#Permanent-trade-offs-1) + +The general workflow of a Cypress test is to + +- Start a browser (yarn run cypress open) +- Visit a URL +- Trigger user actions +- Assert that the DOM contains expected texts and elements using selectors + +## Getting started {#getting-started} + +If this is the first time you use Cypress, it is recommended for you to get familiar with the tool. + +- [Cypress overview](https://docs.cypress.io/guides/overview/why-cypress.html) +- [Cypress examples of tests and syntax](https://example.cypress.io/) + +### 1. Install Cypress {#1-install-cypress} + +You will need: + +- [Node.js 10 or 12 and above](https://nodejs.org) +- [Yarn or NPM](https://yarnpkg.com/) +- A Unix/Linux shell environment or the Windows command line + +To install Cypress and dependencies, run : + +```shell +cd ./main/tests/cypress +yarn install +``` + +### 2. Start the test runner {#2-start-the-test-runner} + +The test runner assumes that OpenRefine is up and running on the local machine, the tests themselves do not launch OpenRefine, nor restarts it. + +Start OpenRefine with + +```shell +./refine +``` + +Then start Cypress + +```shell +yarn --cwd ./main/tests/cypress run cypress open +``` + +### 3. Run the existing tests {#3-run-the-existing-tests} + +Once the test runner is up, you can choose to run one or several tests by selecting them from the interface. +Click on one of them and the test will start. + +### 4. Add your first test {#4-add-your-first-test} + +- Add a `test.spec.js` into the `main/tests/cypress/cypress/integration` folder. +- The test is instantly available in the list +- Click on the test +- Start to add some code + +## Tests technical documentation {#tests-technical-documentation} + +### A typical test {#a-typical-test} + +A typical OpenRefine test starts with the following code + +```javascript +it('Ensure cells are blanked down', function () { + cy.loadAndVisitProject('food.mini'); + cy.get('.viewpanel-sorting a').contains('Sort').click(); + cy.get('.viewpanel').should('to.contain', 'Something'); +}); +``` + +The first noticeable thing about a test is the description (`Ensure cells are blanked down`), which describes what the test is doing. +Lines usually starts with `cy.something...`, which is the main way to interact with the Cypress framework. + +A few examples: + +- `cy.get('a.my-class')` will retrieve the `` element +- `cy.click()` will click on the element +- eventually, `cy.should()` will perform an assertion, for example that the element contains an expected text with `cy.should('to.contains', 'my text')` + +On top of that, OpenRefine contributors have added some functions for common OpenRefine interactions. +For example + +- `cy.loadAndVisitProject` will create a fresh project in OpenRefine +- `cy.assertCellEquals` will ensure that a cell contains a given value + +See below on the dedicated section 'Testing utilities' + +### Testing guidelines {#testing-guidelines} + +- `cy.wait` should be used in the last resort scenario. It's considered a bad practice, though sometimes there is no other choice +- Tests should remain isolated from each other. It's best to try one feature at the time +- A test should always start with a fresh project +- The name of the files should mirror the OpenRefine UI organization + +### Testing utilities {#testing-utilities} + +OpenRefine contributors have added some utility methods on the top of the Cypress framework. +Those methods perform some common actions or assertions on OpenRefine, to avoid code duplication. + +Utilities can be found in `cypress/support/commands.js`. + +The most important utility method is `loadAndVisitProject`. +This method will create a fresh OpenRefine project based on a dataset given as a parameter. +The fixture parameter can be + +- An arbitrary array, the first row is for the column names, other rows are for the values + Use an arbitrary array **only** if the test requires some specific grid values + **Example:** + + ```javascript + const fixture = [ + ['Column A', 'Column B', 'Column C'], + ['0A', '0B', '0C'], + ['1A', '1B', '1C'], + ['2A', '2B', '2C'], + ]; + cy.loadAndVisitProject(fixture); + ``` + +- A referenced dataset: `food.small` or `food.mini` + Most of the time, tests does not require any specific grid values + Use food.mini as much as possible, it loads 2 rows and very few columns in the grid + Use food.small if the test requires a few hundred rows in the grid + + Those datasets live in `cypress/fixtures` + +### Browsers {#browsers} + +In terms of browsers, Cypress is using what is installed on your operating system. +See the [Cypress documentation](https://docs.cypress.io/guides/guides/launching-browsers.html#Browsers) for a list of supported browsers + +### Folder organization {#folder-organization} + +Tests are located in `main/tests/cypress/cypress` folder. +The test should not use any file outside the cypress folder. + +- `/fixtures` contains CSVs and OpenRefine project files used by the tests +- `/integration` contains the tests +- `/plugins` contains custom plugins for the OR project +- `/screenshots` and `/videos` contains the recording of the tests, Git ignored +- `/support` is a custom library of assertion and common user actions, to avoid code duplication in the tests themselves + +### Configuration {#configuration} + +Cypress execution can be configured with environment variables, they can be declared at the OS level, or when running the test + +Available variables are + +- OPENREFINE_URL, determine on which scheme://url:port to access OpenRefine, default to http://localhost:333 +- DISABLE_PROJECT_CLEANUP, If set to 1, projects will not be deleted after each run. Default to 0 to keep the OpenRefine instance clean + + +Cypress contains [exaustive documentation](https://docs.cypress.io/guides/guides/environment-variables.html#Setting) about configuration, but here are two simple ways to configure the execution of the tests: + +#### Overriding with a cypress.env.json file {#overriding-with-a-cypressenvjson-file} + +This file is ignored by Git, and you can use it to configure Cypress locally + +#### Command-line {#command-line} + +You can pass variables at the command-line level + +```shell +yarn --cwd ./main/tests/cypress run cypress open --env OPENREFINE_URL="http://localhost:1234" +``` + +### Visual testing {#visual-testing} + +Tests generally ensure application behavior by making assertions against the DOM, to ensure specific texts or css attributes are present in the document body. +Visual testing, on the contrary, is a way to test applications by comparing images. +A reference screenshot is taken the first time the test runs, and subsequent runs will compare a new screenshot against the reference, at the pixel level. + +Here is an [introduction to visual testing by Cypress](https://docs.cypress.io/plugins/directory#visual-testing). + +In some cases, we are using visual testing. +We are using [Cypress Image Snapshot](https://github.com/jaredpalmer/cypress-image-snapshot) + +Identified cases are so far: + +- testing images created by OpenRefine backend (scatterplots for example) + +Reference screenshots (Called snapshots), are stored in /cypress/snapshots. +And a snapshot can be taken for the whole page, or just a single part of the page. + +#### When a visual test fails {#when-a-visual-test-fails} + +First, Cypress will display the following error message: + +![Diff image when a visual test fails](/img/visual-test-cypress-failure.png) + +Then, a diff image will be created in /cypress/snapshots, this directory is ignored by Git. +The diff images shows the reference image on the left, the image that was taken during the test run on the right, and the diff in the middle. + +![Diff image when a visual test fails](/img/failed-visual-test.png) + +## CI/CD {#cicd} + +In CI/CD, tests are run headless, with the following command-line + +```shell +./refine ui_test chrome +``` + +Results are displayed in the standard output + +## Resources {#resources} + +[Cypress command line options](https://docs.cypress.io/guides/guides/command-line.html#Installation) +[Lots of good Cypress examples](https://example.cypress.io/) diff --git a/OpenRefine/docs/docs/technical-reference/homebrew-cask-process.md b/OpenRefine/docs/docs/technical-reference/homebrew-cask-process.md new file mode 100644 index 000000000..650af5ccf --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/homebrew-cask-process.md @@ -0,0 +1,5 @@ +--- +id: homebrew-cask-process +title: Maintaining OpenRefine's Homebrew cask +sidebar_label: Maintaining OpenRefine's Homebrew cask +--- diff --git a/OpenRefine/docs/docs/technical-reference/maintainer-guidelines.md b/OpenRefine/docs/docs/technical-reference/maintainer-guidelines.md new file mode 100644 index 000000000..b4ca7b20f --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/maintainer-guidelines.md @@ -0,0 +1,89 @@ +--- +id: maintainer-guidelines +title: Guidelines for maintaining OpenRefine +sidebar_label: Maintainer guidelines +--- + +This page describes our practices to review issues and pull requests in the OpenRefine project. + +## Reviewing issues {#reviewing-issues} + +When people create new issues, they automatically get assigned [the "to be reviewed" tag](https://github.com/OpenRefine/OpenRefine/issues?q=is%3Aissue+is%3Aopen+label%3A%22to+be+reviewed%22). + +Ideally, for each of these issues, someone familiar with OpenRefine (not necessarily a developer!) should read the issue and try to determine if there is a genuine bug to fix, or if the enhancement request is legitimate. In those cases, we can remove the "to be reviewed" tag and leave the issue open. In the others, the issue should be politely closed. + +### Bugs {#bugs} + +For a bug, we should first check if it is a real unexpected behaviour or if just comes from a misunderstanding of the intended behaviour of the tool (which could suggest an improvement to the documentation). Then, if it sounds like a genuine problem, we need to check if it can be reproduced independently on the master branch. If the issue does not give enough details about the bug to reproduce it on master, mark it as "not reproducible" and ask the reporter for more information. After some time without any information from the reporter, we can close the issue. + +### Enhancement requests {#enhancement-requests} + +For an enhancement, we need to make a judgment call of whether the proposed functionality is in the scope of the project. There is no universal rule for this of course, so just use your own intuition: do you think this would improve the tool? Would it be consistent with the spirit of the project? Trust your own opinion - if people disagree, they can have a discussion on the issue. + +### Tagging good first issues {#tagging-good-first-issues} + +Adding [the "good first issue" tag](https://github.com/OpenRefine/OpenRefine/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) is something that requires a bit more familiarity with the development process. This tag is used by GitHub to showcase issues in some project lists and we point interested potential contributors to it. It is therefore important that tackling these issues gives them a nice onboarding experience, with as few hurdles as possible. + +Develepers should add the "good first issue" tag when they are confident that they can provide a good pull request for the issue with at most a few hours of work. Also, solving the issue should not require any difficult design decision. The issue should be uncontentious: it should be clear that the proposed solution should be accepted by the team. + +## Reviewing pull requests {#reviewing-pull-requests} + +### Process {#process} + +1. A committer reviews the PR to check for the requirements below and tests it. Each PR should be linked to one or more corresponding issues and the reviewer should check that those are correctly addressed by the PR. The reviewer should be someone else than the PR author. For PRs with an important impact or contentious issues, it is important to leave enough time for other contributors to give their opinion. + +2. The reviewer merges the pull request by squashing its commits into one (except for Weblate PRs which should be merged without squashing). + +3. The reviewer adds the linked issues to the milestone for the next release (such as [the 3.5 milestone](https://github.com/OpenRefine/OpenRefine/milestone/17)) + +4. If the change is worth noting for users or developers, the reviewer adds an entry in the changelog for the next release (such as [Changes for 3.5](https://github.com/OpenRefine/OpenRefine/wiki/Changes-for-3.5)) + +### Requirements {#requirements} + +#### Code style {#code-style} + +Currently, only our code style for integration tests (using Cypress) is codified and enforced by the CI. +For the rest, we rely on imitating the surrounding code. [We should decide on a code style and check it in the CI for other areas of the tool](https://github.com/OpenRefine/OpenRefine/issues/2338). + +#### Testing {#testing} + +We currently rely have two sorts of tests: +* Backend tests, in Java, written with the TestNG framework. Their granularity varies, but generally speaking they are unit tests which test components in isolation. +* UI tests, in Javascript, written with the Cypress framework. They are integration tests which test both the frontend and the backend at the same time. + +Changes to the backend should generally come with the accompanying TestNG tests. +Functional changes to the UI should ideally come with corresponding Cypress tests as well. + +Those tests should be supplied in the same PR as the one that touches the product code. + +#### Documentation {#documentation} + +Changes to user-facing functionality should be reflected in the docs. Those documentation changes should happen in the same PR as the one that touches the product code. + +#### UI style {#ui-style} + +We do not have formally defined UI style guidelines. Contributors are invited to imitate the existing style. + +#### Licensing and dependencies {#licensing-and-dependencies} + +Dependencies can only be added if they are released under a license that is compatible with our BSD Clause-3 license. +One should pay attention to the size of the dependencies since they inflate the size of the release bundles. + +#### Continuous integration {#continuous-integration} + +The various check statuses reported by our continuous integration suite should be green. + +### Special pull requests {#special-pull-requests} + +#### Weblate PRs {#weblate-prs} + +Weblate PRs should not be squashed as it prevents Weblate from recognizing that the corresponding changes have been made in master. They should be merged without squashing. + +Reviewing Weblate PRs only amonuts to a quick visual sanity check as maintainers are not expected to master the languages involved. If corrections need to be made, they should be done in Weblate itself. + +#### Dependabot PRs {#dependabot-prs} + +When reviewing a Dependabot PR it is generally useful to pay attention to: +* the type of version change: most libraries follow the "semver" versioning convention, which indicates the nature of the change. +* the library's changelog, especially if the version change is more significant than a patch release + diff --git a/OpenRefine/docs/docs/technical-reference/migrating-older-extensions.md b/OpenRefine/docs/docs/technical-reference/migrating-older-extensions.md new file mode 100644 index 000000000..75f40015e --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/migrating-older-extensions.md @@ -0,0 +1,169 @@ +--- +id: migrating-older-extensions +title: Migrating older Extensions +sidebar_label: Migrating older Extensions +--- + +## Migrating from Ant to Maven {#migrating-from-ant-to-maven} + +### Why are we doing this change? {#why-are-we-doing-this-change} + +Ant is a fairly old (antique?) build system that does not incorporate any dependency management. +By migrating to Maven we are making it easier for developers to extend OpenRefine with new libraries, and stop having to ship dozens of .jar files in the repository. Using the Maven repository also encourages developers to add dependencies to released versions of libraries instead of custom snapshots that are hard to update. + +### When was this change made? {#when-was-this-change-made} + +The migration was done between 3.0 and 3.1-beta with this commit: +https://github.com/OpenRefine/OpenRefine/commit/47323a9e750a3bc9d43af606006b5eb20ca397b8 + +### How to migrate an extension {#how-to-migrate-an-extension} + +You will need to write a `pom.xml` in the root folder of your extension to configure the compilation process with Maven. Sample `pom.xml` files for extensions can be found in the extensions that are shipped with OpenRefine (`gdata`, `database`, `jython`, `pc-axis` and `wikidata`). A sample extension (`sample`) is also provided, with a minimal build file. + +For any library that your extension depends on, you should try to find a matching artifact in the Maven Central repository. If you can find such an artifact, delete the `.jar` file from your extension and add the dependency in your `pom.xml` file. If you cannot find such an artifact, it is still possible to incorporate your own `.jar` file using `maven-install-plugin` that you can configure in your `pom.xml` file as follows: + + + + org.apache.maven.plugins + maven-install-plugin + 2.5.2 + + + install-wdtk-datamodel + process-resources + + ${basedir}/lib/my-proprietary-library.jar + default + com.my.company + my-library + 0.5.3-SNAPSHOT + jar + true + + + install-file + + + + + + +And add the dependency to the `` section as usual: + + + com.my.company + my-library + 0.5.3-SNAPSHOT + + +## Migrating to Wikimedia's i18n jQuery plugin {#migrating-to-wikimedias-i18n-jquery-plugin} + +### Why are we doing this change? {#why-are-we-doing-this-change-1} + +This adds various important localization features, such as the ability to handle plurals or interpolation. This also restores the language fallback (displaying strings in English if they are not available in the target language) which did not work with the previous set up. + +### When was the migration made? {#when-was-the-migration-made} + +The migration was made between 3.1-beta and 3.1, with this commit: https://github.com/OpenRefine/OpenRefine/commit/22322bd0272e99869ab8381b1f28696cc7a26721 + +### How to migrate an extension {#how-to-migrate-an-extension-1} + +You will need to update your translation files, merging nested objets in one global object, concatenating keys. You can do this by running the following Python script on all your JSON translation files: + + import json + import sys + + with open(sys.argv[1], 'r') as f: + j = json.loads(f.read()) + + result = {} + def translate(obj, path): + res = {} + if type(obj) == str: + result['/'.join(path)] = obj + else: + for k, v in obj.items(): + new_path = path + [k] + translate(v, new_path) + + translate(j, []) + + with open(sys.argv[1], 'w') as f: + f.write(json.dumps(result, ensure_ascii=False, indent=4)) + +Then your javascript files which retrieve the translated strings should be updated: `$.i18n._('core-dialogs')['cancel']` becomes `$.i18n('core-dialogs/cancel')`. You can do this with the following `sed` script: + + sed -i "s/\$\.i18n._(['\"]\([A-Za-z0-9/_\\-]*\)['\"])\[['\"]\([A-Za-z0-9\-\_]*\)[\"']\]/$.i18n('\1\/\2')/g" my_javascript_file.js + +You can then chase down the places where you are concatenating translated strings, and replace that with more flexible patterns using [the plugin's features](https://github.com/wikimedia/jquery.i18n#jqueryi18n-plugin). + +## Migrating from org.json to Jackson {#migrating-from-orgjson-to-jackson} + +### Why are we doing this change? {#why-are-we-doing-this-change-2} + +The org.json (or json-java) library has multiple drawbacks. +* First, it has limited functionality - all the serialization and deserialization has to be done explicitly - an important proportion of OpenRefine's code was dedicated to implementing these; +* Second, its implementation is not optimized for speed - multiple projects have reported speedups when migrating to more modern JSON libraries; +* Third, and this was the decisive factor to initiate the migration: [its license](https://json.org/license) is the MIT license with an additional condition which makes it non-free. Getting rid of this dependency was required by the Software Freedom Conservancy as a prerequisite to become a fiscal sponsor for the project. + +### When was the migration made? {#when-was-the-migration-made-1} + +This change was made between 3.1 and 3.2-beta, with this commit: https://github.com/OpenRefine/OpenRefine/commit/5639f1b2f17303b03026629d763dcb6fef98550b + +### How to migrate an extension or fork {#how-to-migrate-an-extension-or-fork} + +You will need to use the Jackson library to serialize the classes that implement interfaces or extend classes exposed by OpenRefine. +The interface `Jsonizable` was deleted. Any class that used to implement this now needs to be serializable by Jackson, producing the same format as the previous serialization code. This applies to any operation, facet, overlay model or GREL function. If you are new to Jackson, have a look at [this tutorial](https://www.baeldung.com/jackson) to learn how to annotate your class for serialization. Once this is done, you can remove the `void write(JSONWriter writer, Properties options)` method from your class. Note that it is important that you do this migration for all classes implementing the `Jsonizable` interface that are exposed to OpenRefine's core. + +We encourage you to migrate out of org.json completely, but this is only required for the classes that interact with OpenRefine's core. + +#### General notes about migrating {#general-notes-about-migrating} + +OpenRefine's ObjectMapper is available at `ParsingUtilities.mapper`. It is configured to only serialize the fields and getters that have been explicitly marked with `@JsonProperty` (to avoid accidental JSON format changes due to refactoring). On deserialization it will ignore any field in the JSON payload that does not correspond to a field in the Java class. It has serializers and deserializers for `OffsetDateTime` and `LocalDateTime`. + +Useful snippets to use in tests: +* deserialize an instance: `MyClass instance = ParsingUtilities.mapper.readValue(jsonString, MyClass.class);` (replaces calls to `Jsonizable.write`); +* serialize an instance: `String json = ParsingUtilities.mapper.writeValueAsString(myInstance);` (replaces calls to static methods such as `load`, `loadStreaming` or `reconstruct`); +* the equivalent of `JSONObject` is `ObjectNode`, the equivalent of `JSONArray` is `ArrayNode`; +* create an empty JSON object: `ParsingUtilities.mapper.createObjectNode()` (replaces `new JSONObject()`); +* create an empty JSON array: `ParsingUtilities.mapper.createArrayNode()` (replaces `new JSONArray()`). + +Before undertaking the migration, we recommend that you write some tests which serialize and deserialize your objects. This will help you make sure that the JSON format is preserved during the migration. One way to do this is to collect some sample JSON representations of your objects, and check in your tests that deserializing these JSON payloads and serializing them back to JSON preserves the JSON payload. Some utilities are available to help you with that in [`TestUtils`](https://github.com/OpenRefine/OpenRefine/blob/master/main/tests/server/src/com/google/refine/tests/util/TestUtils.java) (we had [some to test org.json serialization](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/tests/server/src/com/google/refine/tests/util/TestUtils.java) before we got rid of the dependency, feel free to copy them). + +#### For functions {#for-functions} + +Before the migration, you had to explicitly define JSON serialization of functions with a `write` method. You should now override the getters returning the various documentation fields. + +Example: `Cos` function [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/expr/functions/math/Cos.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/expr/functions/math/Cos.java). + +#### For operations {#for-operations} + +Before the JSON migration we refactored engine-dependent operations so that the engine configuration is represented by an `EngineConfig` object instead of a `JSONObject`. Therefore the constructor for your operation should be updated to use this new class. Your constructor should also be annotated to be used during deserialization. + +Note that you do not need to explicitly serialize the operation type, this is already done for you by `AbstractOperation`. + +Example: `ColumnRemovalOperation` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/operations/column/ColumnRemovalOperation.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/operations/column/ColumnRemovalOperation.java). + +#### For changes {#for-changes} + +Changes are serialized in plain text but often relies on JSON serialization for parts of the data. Just use the methods above with `ParsingUtilities.mapper` to maintain this behaviour. + +Example: `ReconChange` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/model/changes/ReconChange.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/operations/column/ColumnRemovalOperation.java). + +#### For importers {#for-importers} + +The importing options have been migrated from `JSONObject` to `ObjectNode`. Your compiler should help you propagate this change. Utility functions in `JSONUtilities` have been migrated to Jackson so you should have minimal changes if you used them. + +Example: `TabularImportingParserBase` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/importers/TabularImportingParserBase.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/importers/TabularImportingParserBase.java). + +#### For overlay models {#for-overlay-models} + +Migrate serialization and deserialization as for other objects. + +Example: `WikibaseSchema` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/extensions/wikidata/src/org/openrefine/wikidata/schema/WikibaseSchema.java#L203) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/extensions/wikidata/src/org/openrefine/wikidata/schema/WikibaseSchema.java#L60) + +#### For preference values {#for-preference-values} + +Any class that is stored in OpenRefine's preference now needs to implement the `com.google.refine.preferences.PreferenceValue` interface. The static `load` method and the `write` method used previously for deserialization should be deleted and regular Jackson serialization and deserialization should be implemented instead. Note that you do not need to explicitly serialize the class name, this is already done for you by the interface. + +Example: `TopList` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/preference/TopList.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/preference/TopList.java) diff --git a/OpenRefine/docs/docs/technical-reference/openrefine-api.md b/OpenRefine/docs/docs/technical-reference/openrefine-api.md new file mode 100644 index 000000000..7d1a4c402 --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/openrefine-api.md @@ -0,0 +1,285 @@ +--- +id: openrefine-api +title: OpenRefine API +sidebar_label: OpenRefine API +--- + +This is a generic API reference for interacting with OpenRefine's HTTP API. + +**NOTE:** This protocol is subject to change without warning at any time (and has in the past) and is not versioned. Use at your own risk! + +For OpenRefine 3.3 and later, all POST requests need to include a CSRF token as described here: https://github.com/OpenRefine/OpenRefine/wiki/Changes-for-3.3#csrf-protection-changes + +## Create project: {#create-project} + +> **Command:** _POST /command/core/create-project-from-upload_ + +When uploading files you will need to send the data as `multipart/form-data`. This is different to all other API calls which use a mixture of query string and POST parameters. + +multipart form-data: + + 'project-file' : file contents + 'project-name' : project name + 'format' : format of data in project-file (e.g. 'text/line-based/*sv') [optional] + 'options' : json object containing options relevant to the file format [optional - however, some importers may have required options, such as `recordPath` for the JSON & XML importers]. + +The formats supported will depend on the version of OpenRefine you are using and any Extensions you have installed. The common formats include: + +* 'text/line-based': Line-based text files +* 'text/line-based/*sv': CSV / TSV / separator-based files [separator to be used in specified in the json submitted to the options parameter] +* 'text/line-based/fixed-width': Fixed-width field text files +* 'binary/text/xml/xls/xlsx': Excel files +* 'text/json': JSON files +* 'text/xml': XML files + +If the format is omitted OpenRefine will try to guess the format based on the file extension and MIME type. +The values which can be specified in the JSON object submitted to the 'options' parameter will vary depending on the format being imported. If not specified the options will either be guessed at by OpenRefine (e.g. separator being used in a separated values file) or a default value used. The import options for each file format are not currently documented, but can be seen in the OpenRefine GUI interface when importing a file of the relevant format. + +If the project creation is successful, you will be redirected to a URL of the form: + + http://127.0.0.1:3333/project?project= + +From the project parameter you can extract the project id for use in future API calls. The content of the response is the HTML for the OpenRefine interface for viewing the project. + +### Get project models: {#get-project-models} + +> **Command:** _GET /command/core/get-models?_ + + 'project' : project id + +Recovers the models for the specific project. This includes columns, records, overlay models, scripting. In the columnModel a list of the columns is displayed, key index and name, and column groupings. + +### Response: {#response} +**On success:** +```JSON +{ + "columnModel":{ + "columns":[ + { + "cellIndex":0, + "originalName":"email", + "name":"email" + }, + { + "cellIndex":1, + "originalName":"name", + "name":"name" + }, + { + "cellIndex":2, + "originalName":"state", + "name":"state" + }, + { + "cellIndex":3, + "originalName":"gender", + "name":"gender" + }, + { + "cellIndex":4, + "originalName":"purchase", + "name":"purchase" + } + ], + "keyCellIndex":0, + "keyColumnName":"email", + "columnGroups":[ + + ] + }, + "recordModel":{ + "hasRecords":false + }, + "overlayModels":{ + + }, + "scripting":{ + "grel":{ + "name":"General Refine Expression Language (GREL)", + "defaultExpression":"value" + }, + "jython":{ + "name":"Python / Jython", + "defaultExpression":"return value" + }, + "clojure":{ + "name":"Clojure", + "defaultExpression":"value" + } + } +} +``` + + + +## Apply operations {#apply-operations} + +> **Command:** _POST /command/core/apply-operations?_ + +In the parameter + + 'project' : project id + +In the form data + + 'operations' : Valid JSON **Array** of OpenRefine operations + +Example of a Valid JSON **Array** +```JSON +'[ + { + "op":"core/column-addition", + "description":"Create column zip type at index 15 based on column Zip Code 2 using expression grel:value.type()", + "engineConfig":{ + "mode":"row-based", + "facets":[] + }, + "newColumnName":"zip type", + "columnInsertIndex":15, + "baseColumnName":"Zip Code 2", + "expression":"grel:value.type()", + "onError":"set-to-blank" + }, + { + "op":"core/column-addition", + "description":"Create column testing at index 15 based on column Zip Code 2 using expression grel:value.toString()0,5]", + "engineConfig":{ + "mode":"row-based", + "facets":[] + }, + "newColumnName":"testing", + "columnInsertIndex":15, + "baseColumnName":"Zip Code 2", + "expression":"grel:value.toString()[0,5]", + "onError":"set-to-blank" + } +] +``` + +On success returns JSON response +`{ "code" : "ok" }` + +## Export rows {#export-rows} + +> **Command:** _POST /command/core/export-rows_ + +In the parameter + + 'project' : project id + 'format' : format... (e.g 'tsv', 'csv') + +In the form data + + 'engine' : JSON string... (e.g. '{"facets":[],"mode":"row-based"}') + +Returns exported row data in the specified format. The formats supported will depend on the version of OpenRefine you are using and any Extensions you have installed. The common formats include: + +* csv +* tsv +* xls +* xlsx +* ods +* html + +## Delete project {#delete-project} + +> **Command:** _POST /command/core/delete-project_ + + 'project' : project id... + +Returns JSON response + +## Check status of async processes {#check-status-of-async-processes} + +> **Command:** _GET /command/core/get-processes_ + + 'project' : project id... + +Returns JSON response + +## Get all projects metadata: {#get-all-projects-metadata} + +> **Command:** _GET /command/core/get-all-project-metadata_ + +Recovers the meta data for all projects. This includes the project's id, name, time of creation and last time of modification. + +### Response: {#response-1} +```json +{ + "projects":{ + "[project_id]":{ + "name":"[project_name]", + "created":"[project_creation_time]", + "modified":"[project_modification_time]" + }, + ...[More projects]... + } +} +``` + +## Expression Preview {#expression-preview} +> **Command:** _POST /command/core/preview-expression_ + +Pass some expression (GREL or otherwise) to the server where it will be executed on selected columns and the result returned. + +### Parameters: {#parameters} +* **cellIndex**: _[column]_ +The cell/column you wish to execute the expression on. +* **rowIndices**: _[rows]_ +The rows to execute the expression on as JSON array. Example: `[0,1]` +* **expression**: _[language]_:_[expression]_ +The expression to execute. The language can either be grel, jython or clojure. Example: grel:value.toLowercase() +* **project**: _[project_id]_ +The project id to execute the expression on. +* **repeat**: _[repeat]_ +A boolean value (true/false) indicating whether or not this command should be repeated multiple times. A repeated command will be executed until the result of the current iteration equals the result of the previous iteration. +* **repeatCount**: _[repeatCount]_ +The maximum amount of times a command will be repeated. + +### Response: {#response-2} +**On success:** +```json +{ + "code": "ok", + "results" : [result_array] +} +``` + +The result array will hold up to ten results, depending on how many rows there are in the project that was specified by the [project_id] parameter. Each result is the string that would be put in the cell if the GREL command was executed on that cell. Note that any expression that would return an array or JSon object will be jsonized, although the output can differ slightly from the jsonize() function. + +**On error:** +```JSON +{ + "code": "error", + "type": "[error_type]", + "message": "[error message]" +} +``` + +## Third-party software libraries {#third-party-software-libraries} +Libraries using the [OpenRefine API](openrefine-api): + +### Python {#python} +* [refine-client-py](https://github.com/PaulMakepeace/refine-client-py/) + * Or this fork of the above with an extended CLI [openrefine-client](https://github.com/felixlohmeier/openrefine-client) +* [refine-python](https://github.com/maxogden/refine-python) + +### Ruby {#ruby} +* [refine-ruby](https://github.com/distillytics/refine-ruby) + * The above is a maintained fork of [google-refine](https://github.com/maxogden/refine-ruby) +* [google_refine](https://github.com/chengguangnan/google_refine) + +### NodeJS {#nodejs} +* [node-openrefine](https://github.com/pm5/node-openrefine) + +### R {#r} +* [rrefine](https://cran.r-project.org/web/packages/rrefine/index.html) + +### PHP {#php} +* [openrefine-php-client](https://github.com/keboola/openrefine-php-client) + +### Java {#java} +* [refine-java](https://github.com/dtap-gmbh/refine-java) + +### Bash {#bash} +* [bash-refine.sh](https://gist.github.com/felixlohmeier/d76bd27fbc4b8ab6d683822cdf61f81d) (templates for shell scripts) diff --git a/OpenRefine/docs/docs/technical-reference/reconciliation-api.md b/OpenRefine/docs/docs/technical-reference/reconciliation-api.md new file mode 100644 index 000000000..7649a6ebb --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/reconciliation-api.md @@ -0,0 +1,24 @@ +--- +id: reconciliation-api +title: Reconciliation API +sidebar_label: Reconciliation API +--- + +_This is a technical description of the mechanisms behind the reconciliation system in OpenRefine. For usage instructions, see [Reconciliation](/manual/reconciling)._ + +A reconciliation service is a web service that, given some text which is a name or label for something, and optionally some additional details, returns a ranked list of potential entities matching the criteria. The candidate text does not have to match each entity's official name perfectly, and that's the whole point of reconciliation--to get from ambiguous text name to precisely identified entities. For instance, given the text "apple", a reconciliation service probably should return the fruit apple, the Apple Inc. company, and New York city (also known as the Big Apple). + +Entities are identified by strong identifiers in some particular identifier space. In the same identifier space, identifiers follow the same syntax. For example, given the string "apple", a reconciliation service might return entities identified by the strings " [Q89](https://www.wikidata.org/wiki/Q89)", "[Q312](https://www.wikidata.org/wiki/Q312)", and "[Q60](https://www.wikidata.org/wiki/Q60)", in the Wikidata ID space. Each reconciliation service can only reconcile to one single identifier space, but several reconciliation services can reconcile to the same identifier space. + +OpenRefine can connect to any reconciliation service which follows the [reconciliation API v0.1](https://reconciliation-api.github.io/specs/0.1/). This was formerly a specification edited by the OpenRefine project, which has now transitioned to its own +[W3C Entity Reconciliation Community Group](https://www.w3.org/community/reconciliation/). + +Informally, the main function of any reconciliation service is to find good candidates in the underlying database, given the following data: + +* A string, which is normally the name or title of the entity, in some language. +* Optionally, a type which can be used to narrow down the search to entities of this type. OpenRefine does not define a particular set of acceptable types: this choice is left to the reconciliation service (see the suggest API for that). +* Optionally, a list of properties and their values, which can be used to refine the search. For instance, when reconciling a database of books, the author name or the publication date are useful bits of information that can be transferred to the reconciliation service. This information will be sent to the reconciliation service if the user binds columns to properties. Again, the notion of property is not predefined in OpenRefine: its definition depends on the reconciliation service. + +See [the specifications of the protocol](https://reconciliation-api.github.io/specs/0.1) for more details about the protocol. You can suggest changes on its [issues tracker](https://github.com/reconciliation-api/specs/issues) or on the [group mailing +list](https://lists.w3.org/Archives/Public/public-reconciliation/). + diff --git a/OpenRefine/docs/docs/technical-reference/technical-reference-index.md b/OpenRefine/docs/docs/technical-reference/technical-reference-index.md new file mode 100644 index 000000000..170b60958 --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/technical-reference-index.md @@ -0,0 +1,7 @@ +--- +id: technical-reference-index +title: OpenRefine technical reference +sidebar_label: Technical Reference Index +--- + +Technical reference index diff --git a/OpenRefine/docs/docs/technical-reference/translating-docs.md b/OpenRefine/docs/docs/technical-reference/translating-docs.md new file mode 100644 index 000000000..eb8482e5f --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/translating-docs.md @@ -0,0 +1,19 @@ +--- +id: translating-docs +title: Translate OpenRefine's documentation +sidebar_label: Translate OpenRefine's documentation +--- + +Our user manual can be translated using [Crowdin](https://crowdin.com/project/openrefine). + +## Getting access to Crowdin + +You need to request access to Crowdin on [our developers mailing list](https://groups.google.com/forum/#!forum/openrefine-dev). You will then be granted translator access on the platform. + +## Publication of translations + +Only the user manual for the current development version is being translated. When we publish a new stable version, we take a snapshot of this and publish it on the website. + +In the meantime the pages you translate will be visible under https://docs.openrefine.org/next/ after a few days. + + diff --git a/OpenRefine/docs/docs/technical-reference/translating-ui.md b/OpenRefine/docs/docs/technical-reference/translating-ui.md new file mode 100644 index 000000000..2ca3a811e --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/translating-ui.md @@ -0,0 +1,105 @@ +--- +id: translating-ui +title: Translate OpenRefine's interface +sidebar_label: Translate OpenRefine's interface +--- + +Currently supported languages include English, Spanish, Chinese, French, Hebrew, Italian and Japanese. + +![Translation status](https://hosted.weblate.org/widgets/openrefine/-/287x66-grey.png) + +You can help translate OpenRefine into your language by visiting [Weblate](https://hosted.weblate.org/engage/openrefine/?utm_source=widget) which provides a web based UI to edit and add translations and sends automatic pull requests back to our project. + +Click to help translate --> [Weblate](https://hosted.weblate.org/engage/openrefine/?utm_source=widget) + +## Manual translation process {#manual-translation-process} + +Localized strings are entered in a .json file, one per language. They are located in the folder `main/webapp/modules/core/langs/` in a file named `translation-xx`.json, where xx is the language code (i.e. fr for French). + +### Simple case of localized string {#simple-case-of-localized-string} +This is an example of a simple string, with the start of the JSON file. This example is for French. +``` +{ + "name": "Français", + "core-index/help": "Aide", + (… more lines) +} +``` + +So the key `core-index/help` will render as `"Aide"` in French. + +### Localization with a parameterized value {#localization-with-a-parameterized-value} +In this example, the name of the column (represented by `$1` in this example), will be substituted with the string of the name of the column. + +`"core-facets/edit-facet-title": "Cliquez ici pour éditer le nom de la facette\nColonne : $1",` + +### Localization with a singular/plural value {#localization-with-a-singularplural-value} +In this example, one of the parameter will have a different string depending if the value is 1 or another value. +In this example, the string for page, the second parameter, `$2`, will have an « s » or not depending on the value of `$2`. + +`"core-views/goto-page": "$1 de $2 {{plural:$2|page|pages}}"` + +## Front-end development {#front-end-development} + +The OpenRefine front end has been localized using the [Wikidata jquery.i18n library](https://github.com/OpenRefine/OpenRefine/pull/1285. The localized text is stored in a JSON dictionary on the server and retrieved with a new OpenRefine command. + +### Adding a new string {#adding-a-new-string} + +There should be no hard-coded language strings in the HTML or JSON used for the front end. If you need a new string, first check the existing strings to make sure there isn't an equivalent string, **in an equivalent context**, that you can reuse. Context is important because it can affect how the same literal English text is translated. This cuts down on the amount of text which needs to be translated. + +Strings should be entire sentences or phrases and should include substitution variables for any parameters. Do not concatenate strings in either Java or Javascript (or implicitly by laying them out in a specific order). So, instead of `"You have " + count + " row(s)"` (or worse `count != 1 ? " rows" : " row"`), internationalize everything together so that it can be translated taking into account word ordering and plurals for different languages, ie `"You have $1 {{plural $1: row|rows}}"`, passing the parameter(s) into the `$.i18n` call. + +If there's no string you can reuse, allocate an available key in the appropriate translation dictionary and add the default string, e.g. + +```json +..., +"section/newkey": "new default string for this key", +... +``` + +and then set the text (or HTML) of your HTML element using i18n helper method. So given an HTML fragment like: +```html + +``` +we could set its text using: +``` +$('#new-html-element-id').text($.i18n('section/newkey'])); +``` +or, if you need to embed HTML tags: +``` +$('#new-html-element-id').html($.i18n('section/newkey']); +``` + +### Adding a new language {#adding-a-new-language} + +The language dictionaries are stored in the `langs` subdirectory for the module e.g. + +* https://github.com/OpenRefine/OpenRefine/tree/master/main/webapp/modules/core/langs for the main interface +* https://github.com/OpenRefine/OpenRefine/tree/master/extensions/gdata/module/langs for google spreadsheet connection +* https://github.com/OpenRefine/OpenRefine/tree/master/extensions/database/module/langs for database via JDBC +* https://github.com/OpenRefine/OpenRefine/tree/master/extensions/wikidata/module/langs for Wikidata + +To add support for a new language, the easiest way is to do it directly in Weblate. To do it manually, copy `translation-en.json` to `translation-.json` and have your translator translate all the value strings (ie right hand side). + +#### Main interface {#main-interface} + The translation is best done [with Weblate](https://hosted.weblate.org/engage/openrefine/?utm_source=widget). Files are periodically merged by the developer team. + +Run the latest (hopefully cloned from github) version and check whether translated words fit to the layout. Not all items can be translated word by word, especially into non-IÌ€ndo-European languages. + +If you see any text which remains in English even when you have checked all items, please create bug report in the issue tracker so that the developers can fix it. + +#### Extensions {#extensions} + +Extensions can be translated via Weblate just like the core software. + +The new extension for Wikidata contains lots of domain-specific concepts, with which you may not be familiar. The Wikidata may not have reconciliation service for your language. I recommend checking the glossary(https://www.wikidata.org/wiki/Wikidata:Glossary) to be consistent. + +By default, the system tries to load the language file corresponding to the currently in-use browser language. To override this setting a new menu item ("Language Settings") has been added at the index page. +To support a new language file, the developer should add a corresponding entry to the dropdown menu in this file: `/OpenRefine/main/webapp/modules/core/scripts/index/lang-settings-ui.html`. The entry should look like: +```javascript + +``` + +## Server-side localisation {#server--backend-coding} + +Currently no back end functions are translated, so things like error messages, undo history, etc may appear in English form. Rather than sending raw error text to the front end, it's better to send an error code which is translated into text on the front end. This allows for multiple languages to be supported. diff --git a/OpenRefine/docs/docs/technical-reference/version-release-process.md b/OpenRefine/docs/docs/technical-reference/version-release-process.md new file mode 100644 index 000000000..3f86ab7d6 --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/version-release-process.md @@ -0,0 +1,51 @@ +--- +id: version-release-process +title: How to do an OpenRefine version release +sidebar_label: How to do an OpenRefine version release +--- + +When releasing a new version of Refine, the following steps should be followed: + +1. Make sure the `master` branch is stable and nothing has broken since the previous version. We need developers to stabilize the trunk and some volunteers to try out `master` for a few days. +2. Change the version number in [RefineServlet.java](http://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/RefineServlet.java#L62) and in the POM files using `mvn versions:set -DnewVersion=2.6-beta -DgenerateBackupPoms=false`. Commit the changes. +3. Compose the list of changes in the code and on the wiki. If the issues have been updated with the appropriate milestone, the Github issue tracker should be able to provide a good starting point for this. +4. Set up build machine. This needs to be Mac OS X or Linux. +5. Download Windows and Mac JREs to bundle them in the Windows and Mac packages from [AdoptOpenJDK](https://adoptopenjdk.net/). You only need the JREs, not the JDKs. Use the lowest version of Java supported (Java 11 currently). Configure the location of these JREs in the `settings.xml` file at the root of the repository. It is important to download recent versions of the JREs as this impacts which HTTPS certificates are accepted by the tool. +6. Insert the production Google credentials in https://github.com/OpenRefine/OpenRefine/blob/bc540a880eceb88e54f85ca43eb54769de3bfa4f/extensions/gdata/src/com/google/refine/extension/gdata/GoogleAPIExtension.java#L36-L39 without committing the changes. +7. [Build the release candidate kits using the shell script (not just Maven)](https://github.com/OpenRefine/OpenRefine/wiki/Building-OpenRefine-From-Source). This must be done on Mac OS X or Linux to be able to build all 3 kits. On Linux you will need to install the `genisoimage` program first. +```shell +./refine dist 2.6-beta.2 +``` +To build the Windows version with embedded JRE, use `mvn package -s settings.xml -P embedded-jre -DskipTests=true`. + +8. On a Mac machine, compress the Mac `.dmg` (`genisoimage` does not compress it by default) with the following command on a mac machine: `hdiutil convert openrefine-uncompressed.dmg -format UDZO -imagekey zlib-level=9 -o openrefine-3.1-mac.dmg`. If running OS X in a VM, it's probably quicker and more reliable to transfer the kits to the host machine first and then to Github. Finder -> Go -> Connect -> smb://10.0.2.2/. You can then sign the generated DMG file with `codesign -s "Apple Distribution: Code for Science and Society, Inc." openrefine-3.1-mac.dmg`. This requires that you have installed the appropriate certificate on your Mac, see below. + +9. Tag the release candidate in git and push the tag to Github. For example: +```shell +git tag -a -m "Second beta" 2.6-beta.2 + git push origin --tags +``` +10. Upload the kits to Github releases [https://github.com/OpenRefine/OpenRefine/releases/](https://github.com/OpenRefine/OpenRefine/releases/) Mention the SHA sums of all uploaded artifacts. +11. Announce the beta/release candidate for testing +12. Repeat build/release candidate/testing cycle, if necessary. +13. Tag the release in git. Build the distributions and upload them. +14. [Update the OpenRefine Homebrew cask](https://github.com/OpenRefine/OpenRefine/wiki/Maintaining-OpenRefine's-Homebrew-Cask) or coordinate an update via the [developer list](https://groups.google.com/forum/#!forum/openrefine-dev) +15. Verify that the correct versions are shown in the widget at [http://openrefine.org/download](http://openrefine.org/download) +16. Announce on the [OpenRefine mailing list](https://groups.google.com/forum/#!forum/openrefine). +17. Update the version in master to the next version number with `-SNAPSHOT` (such as `4.3-SNAPSHOT`) +```shell +mvn versions:set -DnewVersion=4.3-SNAPSHOT +``` +18. If releasing a new major or minor version, create a snapshot of the docs, following [Docusaurus' versioning procedure](https://docusaurus.io/docs/versioning). + +Apple code signing +================== + +We have code signing certificates for our iOS distributions. To use them, follow these steps: +* Request advisory.committee@openrefine.org to be added to the Apple team: you need to provide the email address that corresponds to your AppleID account; +* Create a certificate signing request from your Mac: https://help.apple.com/developer-account/#/devbfa00fef7 +* Go to https://developer.apple.com/account/resources/certificates/add and select "Apple Distribution" as certificate type +* Upload the certificate signing request in the form +* Download the generated certificate +* Import this certificate in the "Keychain Access" app on your mac +* You can now sign code on behalf of the team using the `codesign` utility, such as `codesign -s "Apple Distribution: Code for Science and Society, Inc." openrefine-3.1-mac.dmg`. diff --git a/OpenRefine/docs/docs/technical-reference/writing-extensions.md b/OpenRefine/docs/docs/technical-reference/writing-extensions.md new file mode 100644 index 000000000..3511cc31f --- /dev/null +++ b/OpenRefine/docs/docs/technical-reference/writing-extensions.md @@ -0,0 +1,326 @@ +--- +id: writing-extensions +title: Writing Extensions +sidebar_label: Writing Extensions +--- + +## Introduction {#introduction} + +This is a very brief overview of the structure of OpenRefine extensions. For more detailed documentation and step-by-step guides please see the following external documentation/tutorials: + +* Giuliano Tortoreto has [written documentation detailling how to build extension for OpenRefine](https://github.com/giTorto/OpenRefineExtensionDoc/raw/master/main.pdf) +* Owen Stephens has written [a guide to developing an extension which adds new GREL functions to OpenRefine](http://www.meanboyfriend.com/overdue_ideas/2017/05/writing-an-extension-to-add-new-grel-functions-to-openrefine/). + +OpenRefine makes use of a modified version of the [Butterfly framework](https://github.com/OpenRefine/simile-butterfly/tree/openrefine) to provide an extension architecture. OpenRefine extensions are Butterfly modules. You don't really need to know about Butterfly itself, but you might encounter "butterfly" here and there in the code base. + +Extensions that come with the code base are located under [the extensions subdirectory](https://github.com/OpenRefine/OpenRefine/tree/master/extensions), but when you develop your own extension, you can put its code anywhere as long as you point Butterfly to it. That is done by any one of the following methods + +* refer to your extension's directory in [the butterfly.properties file](https://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/WEB-INF/butterfly.properties) through a `butterfly.modules.path` setting. +* specify the butterfly.modules.path property on the command line when you run OpenRefine. This overrides the values in the property file, so you need to include the default values first e.g. `-Dbutterfly.modules.path=modules,../../extensions,/path/to/your/extension` + +Please note that you should bundle any dependencies yourself, so you are insulated from OpenRefine packaging changes over time. + +### Directory Layout {#directory-layout} + +A OpenRefine extension sits in a file directory that contains the following files and sub-directories: + +``` +pom.xml + src/ + com/foo/bar/... *.java source files + module/ + *.html, *.vt files + scripts/... *.js files + styles/... *.css and *.less files + images/... image files + MOD-INF/ + lib/*.jar files + classes/... java class files + module.properties + controller.js +``` + +The file named module.properties (see [example](https://github.com/OpenRefine/OpenRefine/blob/master/extensions/sample/module/MOD-INF/module.properties)) contains the extension's metadata. Of importance is the name field, which gives the extension a name that's used in many other places to refer to it. This can be different from the extension's directory name. + +``` +name = my-extension-name +``` + +Your extension's client-side resources (.html, .js, .css files) stored in the module/ subdirectory will be accessible from http://127.0.0.1:3333/extension/my-extension-name/ when OpenRefine is running. + +Also of importance is the dependency + +``` +requires = core +``` + +which makes sure that the core module of OpenRefine is loaded before the extension attempts to hook into it. + +The file named controller.js is responsible for registering the extension's hooks into OpenRefine. Look at the sample-extension extension's [controller.js](https://github.com/OpenRefine/OpenRefine/blob/master/extensions/sample/module/MOD-INF/controller.js) file for an example. It should have a function called init() that does the hook registrations. + +The `pom.xml` file is an [Apache Maven](http://maven.apache.org/) build file. You can make a copy of the sample extension's `pom.xml` file to get started. The important point here is that the Java classes should be built into the `module/MOD-INF/classes` sub-directory. + +Note that your extension's Java code would need to reference some libraries used in OpenRefine and OpenRefine's Java classes themselves. These dependencies are reflected in the Maven configuration for the extension. + +## Sample extension {#sample-extension} + +The sample extension is included in the code base so that you can copy it and get started on writing your own extension. After you copy it, make sure you change its name inside its `module/MOD-INF/controller.js` file. + +### Basic Structure {#basic-structure} + +The sample extension's code is in `refine/extensions/sample/`. In that directory, Java source code is contained under the `src` sub-directory, and webapp code is under the `module` sub-directory. Here is the full directory layout: + +``` +refine/extensions/sample/ + build.xml (ant build script) + src/ + com/google/refine/sampleExtension/ + ... Java source code ... + module/ + MOD-INF/ + module.properties (module settings) + controller.js (module init and routing logic in Javascript) + classes/ + ... compiled Java classes ... + lib/ + ... Java jars ... + ... velocity templates (.vt) ... + ... LESS css files ... + ... client-side files (.html, .css, .js, image files) ... +``` + +The sub-directory `MOD-INF` contains the Butterfly module's metadata and is what Butterfly looks for when it scans directories for modules. `MOD-INF` serves similar functions as `WEB-INF` in other web frameworks. + +Java code is built into the sub-directory `classes` inside `MOD-INF`, and supporting external Java jars are in the `lib` sub-directory. Those will be automatically loaded by Butterfly. (The build.xml script is wired to compile into the `classes` sub-directory.) + +Client-side code is in the inner `module` sub-directory. They can be plain old .html, .css, .js, and image files, or they can be [LESS](http://lesscss.org/) files that get processed into CSS. There are also Velocity .vt files, but they need to be routed inside `MOD-INF/controller.js`. + +`MOD-INF/controller.js` lets you configure the extension's initialization and URL routing in Javascript rather than in Java. For example, when the requested URL path is either `/` or an empty string, we process and return `MOD-INF/index.vt` ( [see http://127.0.0.1:3333/extension/sample/](http://127.0.0.1:3333/extension/sample/) if OpenRefine is running). + +The `init()` function in `controller.js` allows the extension to register various client-side handlers for augmenting pages served by Refine's core. These handlers are feature-specific. For example, [this is where the jython extension adds its parser](https://github.com/OpenRefine/OpenRefine/blob/master/extensions/jython/module/MOD-INF/controller.js#L46). As for the sample extension, it adds its script `project-injection.js` and style `project-injection.less` into the `/project` page. If you [view the source of the /project page](http://127.0.0.1:3333/project), you will see references to those two files. + +### Wiring Up the Extension {#wiring-up-the-extension} + +The Extensions are loaded by the Butterfly framework. Butterfly refers to these as 'modules'. [The location of modules is set in the `main/webapp/butterfly.properties` file](https://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/WEB-INF/butterfly.properties#L27). Butterfly simply descends into each of those paths and looks for any `MOD-INF` directories. + +For more information, see [Extension Points](https://github.com/OpenRefine/OpenRefine/wiki/Extension-Points). + +## Extension points {#extension-points} + +### Client-side: Javascript and CSS {#client-side-javascript-and-css} + +The UI in OpenRefine for working with a project is coded in [the /main/webapp/modules/core/project.vt file](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/project.vt). The file is quite small, and that's because almost all of its content is to be expanded dynamically through the Velocity variables $scriptInjection and $styleInjection. So that your own Javascript and CSS files get loaded, you need to register them with the ClientSideResourceManager, which is done in the /module/MOD-INF/controller.js file. See [the controller.js file in this sample extension code](http://github.com/OpenRefine/OpenRefine/blob/master/extensions/sample/module/MOD-INF/controller.js) for an example. + +In the registration call, the variable `module` is already available to your code by default, and it refers to your own extension. + +``` +ClientSideResourceManager.addPaths( + "project/scripts", + module, + [ + "scripts/foo.js", + "scripts/subdir/bar.js" + ] + ); +``` + +You can specify one or more files for registration, and their paths are relative to the `module` subdirectory of your extension. They are included in the order listed. + +Javascript Bundling: Note that `project.vt` belongs to the core module and is thus under the control of the core module's [controller.js file](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/MOD-INF/controller.js). The Javascript files to be included in `project.vt` are by default bundled together for performance. When debugging, you can prevent this bundling behavior by setting `bundle` to `false` near the top of that `controller.js` file. (If you have commit access to this code base, be sure not to check that change in.) + +### Client-side: Images {#client-side-images} + +We recommend that you always refer to images through your CSS files rather than in your Javascript code. URLs to images will thus be relative to your CSS files, e.g., + +``` +.foo { + background: url(../images/x.png); + } +``` + +If you really really absolutely need to refer to your images in your Javascript code, then look up your extension's URL path in the global Javascript variable `ModuleWirings`: + +``` +ModuleWirings["my-extension"] + "images/x.png" +``` + +### Client-side: HTML Templates {#client-side-html-templates} + +Beside Javascript, CSS, and images, your extension might also include HTML templates that get loaded on the fly by your Javascript code and injected into the page's DOM. For example, here is [the Cluster edit dialog template](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/scripts/dialogs/clustering-dialog.html), which gets loaded by code in [the equivalent javascript file 'clustering-dialog.js'](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/scripts/dialogs/clustering-dialog.js): + +``` +var dialog = $(DOM.loadHTML("core", "scripts/dialogs/clustering-dialog.html")); +``` + +`DOM.loadHTML` returns the content of the file as a string, and `$(...)` turns it into a DOM fragment. Where `"core"` is, you would want your extension's name. The path of the HTML file is relative to your extension's `module` subdirectory. + +### Client-side: Project UI Extension Points {#client-side-project-ui-extension-points} + +Getting your extension's Javascript code included in `project.vt` doesn't accomplish much by itself unless your code also registers hooks into the UI. For example, you can surely implement an exporter in Javascript, but unless you add a corresponding menu command in the UI, your user can't use your exporter. + +#### Main Menu {#main-menu} + +The main menu can be extended by calling any one of the methods `MenuBar.appendTo`, `MenuBar.insertBefore`, and `MenuBar.insertAfter`. Each method takes 2 arguments: an array of strings that identify a particular existing menu item or submenu, and one new single menu item or submenu or an array of menu items and submenus. For example, to insert 2 menu items and a menu separator before the menu item Project > Export Filtered Rows > Templating..., write this Javascript code wherever that would execute when your Javascript files get loaded: + +``` +MenuBar.insertBefore( + ["core/project", "core/export", "core/export-templating"], + [ + { + "label":"Menu item 1", + "click": function() { ... } + }, + { + "label":"Menu item 2", + "click": function() { ... } + }, + {} // separator + ] + ); +``` + +The array `["core/project", "core/export", "core/export-templating"]` pinpoints the reference menu item. + +See the beginning of [/main/webapp/modules/core/scripts/project/menu-bar.js](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/scripts/project/menu-bar.js) for IDs of menu items and submenus. + +#### Column Header Menu {#column-header-menu} + +The drop-down menu of each column can also be extended, but the mechanism is slightly different compared to the main menu. Because the drop-down menu for a particular column is constructed on the fly when the user actually clicks the drop-down menu button, extending the column header menu can't really be done once at start-up time, but must be done every time a column header menu gets created. So, registration in this case involves providing a function that gets called each such time: + +``` +DataTableColumnHeaderUI.extendMenu(function(column, columnHeaderUI, menu) { ... do stuff to menu ... }); +``` + +That function takes in the column object (which contains the column's name), the column header UI object (generally not so useful), and the menu to extend. In the previous code line where it says "do stuff to menu", you can write something like this: + +``` +MenuSystem.appendTo(menu, ["core/facet"], [ + { + id: "core/text-facet", + label: "My Facet on " + column.name, + click: function() { + ... use column.name and do something ... + } + }, + ]); +``` + +In addition to `MenuSystem.appendTo`, you can also call `MenuSystem.insertBefore` and `MenuSystem.insertAfter` which the same 3 arguments. To see what IDs you can use, see the function `DataTableColumnHeaderUI.prototype._createMenuForColumnHeader` in [/main/webapp/modules/core/scripts/views/data-table/column-header-ui.js](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/scripts/views/data-table/column-header-ui.js). + +### Server-side: Ajax Commands {#server-side-ajax-commands} + +The client-side of OpenRefine gets things done by calling AJAX commands on the server-side. These commands must be registered with the OpenRefine servlet, so that the servlet knows how to route AJAX calls from the client-side. This can be done inside the `init` function in your extension's `controller.js` file, e.g., + +``` +function init() { + var RefineServlet = Packages.com.google.refine.RefineServlet; + RefineServlet.registerCommand(module, "my-command", new Packages.com.foo.bar.MyCommand()); + } +``` + +Your command will then be accessible at [http://127.0.0.1:3333/command/my-extension/my-command](http://127.0.0.1:3333/command/my-extension/my-command). + +### Server-side: Operations {#server-side-operations} + +Most commands change the project's data. Most of them do so by creating abstract operations. See the Changes, History, Processes, and Operations section of the [Server Side Architecture](https://github.com/OpenRefine/OpenRefine/wiki/Server-Side-Architecture) document. + +You can register an operation **class** in the `init` function as follows: + +``` +Packages.com.google.refine.operations.OperationRegistry.registerOperation( + module, + "operation-name", + Packages.com.foo.bar.MyOperation + ); +``` + +Do not call `new` to construct an operation instance. You must register the class itself. The class should have a static function for reconstructing an operation instance from a JSON blob: + +``` +static public AbstractOperation reconstruct(Project project, JSONObject obj) throws Exception { + ... + } +``` + +### Server-side: GREL {#server-side-grel} + +GREL can be extended with new functions. This is also done in the `init` function in `controller.js`, e.g., + +``` +Packages.com.google.refine.grel.ControlFunctionRegistry.registerFunction( + "functionName", new Packages.com.foo.bar.TheFunctionClass()); +``` + +You might also want to provide new variables (beyond just `value`, `cells`, `row`, etc.) available to expressions. This is done by registering a binder that implements the interface `com.google.refine.expr.Binder`: + +``` +Packages.com.google.refine.expr.ExpressionUtils.registerBinder( + new Packages.com.foo.bar.MyBinder()); +``` + +### Server-side: Importers {#server-side-importers} + +You can register an importer as follows: + +``` +Packages.com.google.refine.importers.ImporterRegistry.registerImporter( + "importer-name", new Packages.com.foo.bar.MyImporter()); +``` + +The string `"importer-name"` isn't important at all. It's not really related to file extension or mime-type. Just use something unique. Your importer will be explicitly called to test if it can import something. + +### Server-side: Exporters {#server-side-exporters} + +You can register an exporter as follows: + +``` +Packages.com.google.refine.exporters.ExporterRegistry.registerExporter( + "exporter-name", new Packages.com.foo.bar.MyExporter()); +``` + +The string `"exporter-name"` isn't important at all. It's only used by the client-side to tell the server-side which exporter to use. Just use something unique and, of course, relevant. + +### Server-side: Overlay Models {#server-side-overlay-models} + +Overlay models are objects attached onto a core Project object to store and manage additional data for that project. For example, the schema alignment skeleton is managed by the Protograph overlay model. An overlay model implements the interface `com.google.refine.model.OverlayModel` and can be registered like so: + +``` +Packages.com.google.refine.model.Project.registerOverlayModel( + "model-name", + Packages.com.foo.bar.MyOverlayModel); +``` + +Note that you register the **class** , not an instance. The class should implement the following static method for reconstructing an overlay model instance from a JSON blob: + +``` +static public OverlayModel reconstruct(JSONObject o) throws JSONException { + ... + } +``` + +When the project gets saved, the overlay model instance's `write` method will be called: + +``` +public void write(JSONWriter writer, Properties options) throws JSONException { + ... + } +``` + +### Server-side: Scripting Languages {#server-side-scripting-languages} + +A scripting language (such as Jython) can be registered as follows: + +``` +Packages.com.google.refine.expr.MetaParser.registerLanguageParser( + "jython", + "Jython", + Packages.com.google.refine.jython.JythonEvaluable.createParser(), + "return value" + ); +``` + +The first string is the prefix that gets prepended to each expression so that we know which language the expression is in. This should be short, unique, and identifying. The second string is a user-friendly name of the language. The third is an object that implements the interface `com.google.refine.expr.LanguageSpecificParser`. The final string is the default expression in that language that would return the cell's value. + +In 2018 we are making important changes to OpenRefine to modernize it, for the benefit of users and contributors. This page describes the changes that impact developers of extensions or forks and is intended to minimize the effort required on their end to follow the transition. The instructions are written specifically with extension maintainers in mind, but fork maintainers should also find it useful. + +This document describes the migrations in the order they are committed to the master branch. This means that it should be possible to perform each migration in turn, with the ability to run the software between each stage by checking out the appropriate git commit. diff --git a/OpenRefine/docs/docusaurus.config.js b/OpenRefine/docs/docusaurus.config.js new file mode 100644 index 000000000..778b3cd17 --- /dev/null +++ b/OpenRefine/docs/docusaurus.config.js @@ -0,0 +1,129 @@ +module.exports = { + onBrokenLinks: 'throw', + onBrokenMarkdownLinks: 'throw', + title: 'OpenRefine', + tagline: 'A power tool for working with messy data.', + url: 'https://docs.openrefine.org/', + baseUrl: '/', + favicon: 'img/openrefine_logo.png', + organizationName: 'OpenRefine', // Usually your GitHub org/user name. + projectName: 'OpenRefine', // Usually your repo name. + i18n: { + defaultLocale: 'en', + locales: ['en', 'jp', 'fr'], + }, + themeConfig: { + navbar: { + title: 'OpenRefine Documentation', + logo: { + alt: 'OpenRefine diamond logo', + src: 'img/openrefine_logo.png', + }, + items: [ + { + to: '/', + activeBasePath: 'docs', + label: 'User Manual', + position: 'left', + }, + { + to: 'technical-reference/technical-reference-index', + label: 'Technical Reference', + position: 'left' + }, + { + type: 'localeDropdown', + position: 'right', + }, + { + href: 'https://github.com/OpenRefine/OpenRefine/edit/master/docs', + 'aria-label': 'GitHub', + className: 'header-github-link', + position: 'right', + }, + ], + }, + algolia: { + apiKey: '591fc612419d2e5b6bee6822cc17064f', + indexName: 'openrefine', + contextualSearch: true, + }, + footer: { + logo: { + alt: 'OpenRefine diamond logo', + src: 'img/openrefine_logo.png', + href: 'https://docs.openrefine.org', + }, + style: 'dark', + links: [ + { + title: 'Community', + items: [ + { + label: 'Mailing List', + href: 'http://groups.google.com/group/openrefine/' + }, + { + label: 'Gitter Chat', + href: 'https://gitter.im/OpenRefine/OpenRefine', + }, + { + label: 'Twitter', + href: 'https://twitter.com/openrefine', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'Official Website', + href: 'https://openrefine.org', + }, + { + label: 'GitHub', + href: 'https://github.com/OpenRefine/OpenRefine', + }, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} OpenRefine contributors`, + }, + }, + themes: [], + plugins: [], + presets: [ + [ + '@docusaurus/preset-classic', + { + docs: { + // Docs folder path relative to website dir. Equivalent to `customDocsPath`. + // path: 'docs', + // Sidebars file relative to website dir. + sidebarPath: require.resolve('./sidebars.js'), + // Equivalent to `editUrl` but should point to `website` dir instead of `website/docs`. + editUrl: 'https://github.com/OpenRefine/OpenRefine/edit/master/docs', + // Equivalent to `docsUrl`. + routeBasePath: '/', + // Remark and Rehype plugins passed to MDX. Replaces `markdownOptions` and `markdownPlugins`. + remarkPlugins: [], + rehypePlugins: [], + // Equivalent to `enableUpdateBy`. + showLastUpdateAuthor: true, + // Equivalent to `enableUpdateTime`. + showLastUpdateTime: true, + }, + theme: { + customCss: require.resolve('./src/css/custom.css'), + }, + }, + ], + ], + scripts: [ + { + src: '/js/fix-location.js', + async: false, + defer: false, + }, + ], +}; diff --git a/OpenRefine/docs/netlify.toml b/OpenRefine/docs/netlify.toml new file mode 100644 index 000000000..da425af8b --- /dev/null +++ b/OpenRefine/docs/netlify.toml @@ -0,0 +1,9 @@ + +# Note: this file's config overrides the Netlify UI admin config + +[context.production] + command = "yarn netlify:build:production" + +[context.deploy-preview] + command = "yarn netlify:build:deployPreview" + diff --git a/OpenRefine/docs/package.json b/OpenRefine/docs/package.json new file mode 100644 index 000000000..70a80a852 --- /dev/null +++ b/OpenRefine/docs/package.json @@ -0,0 +1,25 @@ +{ + "name": "OpenRefine-Documentation", + "version": "1.0.0", + "description": "Documentation for OpenRefine", + "license": "BSD-3-Clause", + "author": "OpenRefine", + "private": true, + "scripts": { + "start": "docusaurus start", + "build": "docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "crowdin": "crowdin", + "netlify:build:production": "docusaurus write-translations && crowdin upload && crowdin download && yarn build", + "netlify:build:deployPreview": "docusaurus write-translations && yarn build" + }, + "dependencies": { + "@crowdin/cli": "3", + "@docusaurus/core": "^2.0.0-beta.10", + "@docusaurus/preset-classic": "^2.0.0-beta.759298296", + "clsx": "^1.1.1", + "react": "^17.0.2", + "react-dom": "^17.0.2" + } +} diff --git a/OpenRefine/docs/sidebars.js b/OpenRefine/docs/sidebars.js new file mode 100644 index 000000000..b6f16d838 --- /dev/null +++ b/OpenRefine/docs/sidebars.js @@ -0,0 +1,53 @@ +module.exports = { + docs: { + 'User Manual': [ + 'index', + 'manual/installing', + 'manual/running', + 'manual/starting', + { + type: 'category', + label: 'Exploring data', + items: ['manual/exploring', 'manual/facets', 'manual/sortview'], + }, + { + type: 'category', + label: 'Transforming data', + items: ['manual/transforming', 'manual/cellediting','manual/columnediting','manual/transposing'], + }, + 'manual/reconciling', + { + type: 'category', + label: 'Wikibase', + items: ['manual/wikibase/overview', 'manual/wikibase/configuration', 'manual/wikibase/reconciling', 'manual/wikibase/schema-alignment', + 'manual/wikibase/new-entities', 'manual/wikibase/quality-assurance', 'manual/wikibase/uploading'], + }, + { + type: 'category', + label: 'Expressions', + items: ['manual/expressions', 'manual/grel', 'manual/grelfunctions', 'manual/jythonclojure'], + }, + 'manual/exporting', + 'manual/troubleshooting' + ], + 'GREL Reference': [ + 'manual/grelfunctions'], + 'Technical Reference': [ + 'technical-reference/technical-reference-index', + 'technical-reference/architecture', + 'technical-reference/openrefine-api', + 'technical-reference/reconciliation-api', + 'technical-reference/contributing', + 'technical-reference/build-test-run', + 'technical-reference/development-roadmap', + 'technical-reference/version-release-process', + 'technical-reference/homebrew-cask-process', + 'technical-reference/writing-extensions', + 'technical-reference/migrating-older-extensions', + 'technical-reference/translating-ui', + 'technical-reference/translating-docs', + 'technical-reference/functional-tests', + 'technical-reference/maintainer-guidelines' + ] + }, +}; diff --git a/OpenRefine/docs/src/css/custom.css b/OpenRefine/docs/src/css/custom.css new file mode 100644 index 000000000..22e632746 --- /dev/null +++ b/OpenRefine/docs/src/css/custom.css @@ -0,0 +1,87 @@ +/** + * You can override the default Infima variables here. + * Note: this is not a complete list of --ifm- variables. + */ + + /** + * Colors extracted from our OpenRefine logo + */ + :root { + --ifm-color-primary: #00a0ff; + --ifm-color-primary-dark: #0078ff; + --ifm-color-primary-darker: #0050ac; + --ifm-color-primary-darkest: #003b7e; + --ifm-color-primary-light: #00b4ff; + --ifm-color-primary-lighter: #2da6d1; + --ifm-color-primary-lightest: #00dcff; + --ifm-color-secondary: #999999; + --ifm-alert-border-width: 0.375em; + --ifm-alert-background-color: #ffffff; + --ifm-panel-background-color: #ffffff; + --ifm-panel-box-shadow-color: #999999; + --ifm-code-color: var(--ifm-color-primary-darkest); + } + + /******* COMMON *******/ + + html[data-theme='dark'] { + --ifm-panel-background-color: rgb(41, 45, 62); + --ifm-panel-box-shadow-color: var(--ifm-panel-background-color); + --ra-admonition-color: var(--ifm-color-black); + --ra-admonition-icon-color: var(--ifm-color-black); + --ifm-code-color: var(--ifm-color-primary-light); + } + + /******* MARKDOWN STYLES *******/ + + .alert { + border-radius: 0; + border: 0; + box-shadow: 0em 0em 0.625em 0em var(--ifm-panel-box-shadow-color); + border-width: 1em; + border-left: var(--ifm-alert-border-width) solid var(--ifm-alert-border-color); + background-color: var(--ifm-panel-background-color); + color: var(--ifm-font-color-secondary); + } + + .admonition-icon svg { + fill: var(--ifm-font-color-secondary); + } + + .alert a { + color: var(--ifm-font-color-secondary); + } + + .markdown h4{ + margin-top: 1.025em; + font-size: 1.25em; + } + + .markdown h3{ + margin-top: 1.325em; + font-size: 1.8125em; + } + + .markdown h2{ + margin-top: 1.525em; + font-size: 2.1875em; + } + + .markdown .menuItems, .markdown .fieldLabels, .markdown .tabLabels, .markdown .buttonLabels { + font-size: var(--ifm-code-font-size); + display: inline-block; + border: 0.125em solid #4dc6e1; + border-radius: var(--ifm-code-border-radius); + margin: 0.0625em 0em; + padding: 0em 0.25em; + } + + .markdown img { + display: block; + margin-left: auto; + margin-right: auto; + } + + code { + color: var(--ifm-code-color); + } diff --git a/OpenRefine/docs/src/theme/Footer/Footer.js b/OpenRefine/docs/src/theme/Footer/Footer.js new file mode 100644 index 000000000..11d153e89 --- /dev/null +++ b/OpenRefine/docs/src/theme/Footer/Footer.js @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const React = require('react'); + +class Footer extends React.Component { + docUrl(doc, language) { + const baseUrl = this.props.config.baseUrl; + const docsUrl = this.props.config.docsUrl; + const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`; + const langPart = `${language ? `${language}/` : ''}`; + return `${baseUrl}${docsPart}${langPart}${doc}`; + } + + pageUrl(doc, language) { + const baseUrl = this.props.config.baseUrl; + return baseUrl + (language ? `${language}/` : '') + doc; + } + + render() { + return ( + + ); + } +} + +module.exports = Footer; diff --git a/OpenRefine/docs/static/css/custom.css b/OpenRefine/docs/static/css/custom.css new file mode 100644 index 000000000..55da82683 --- /dev/null +++ b/OpenRefine/docs/static/css/custom.css @@ -0,0 +1,2 @@ +/* custom CSS can be added here */ + diff --git a/OpenRefine/docs/static/img/cluster.png b/OpenRefine/docs/static/img/cluster.png new file mode 100644 index 0000000000000000000000000000000000000000..408c4a256f3a7029782146984c0fe44d861982bf GIT binary patch literal 52046 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 L59J)V81jDr$i0u? literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/columnjoin.png b/OpenRefine/docs/static/img/columnjoin.png new file mode 100644 index 0000000000000000000000000000000000000000..6b49798cd4163248457c824f1ce0027b4f41ccc9 GIT binary patch literal 27571 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�L2u7H?8#KKf3X0nEFo;=5kT5375b7j)D6agd% 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/columnsplit.png b/OpenRefine/docs/static/img/columnsplit.png new file mode 100644 index 0000000000000000000000000000000000000000..b65d5291f459c67b9e284aaf79d2c7c20c48b6ce GIT binary patch literal 14243 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 U?Mom(1syv0!-2YeKmPQ;0A6hf)Bpeg literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/eclipse-debug-config.png b/OpenRefine/docs/static/img/eclipse-debug-config.png new file mode 100644 index 0000000000000000000000000000000000000000..9463261ea798c4433de274a1e998f1095e0ad371 GIT binary patch literal 49671 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 W$`h3h(JY~VKmwkwelF{r5}E*{8m1lq literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/eclipse-import-maven-project-1.png b/OpenRefine/docs/static/img/eclipse-import-maven-project-1.png new file mode 100644 index 0000000000000000000000000000000000000000..7c473682537f1b915aa04ee28385672ab038c0b5 GIT binary patch literal 32942 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

-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 GJpKo-^-RG4 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/eclipse-import-maven-project-2.png b/OpenRefine/docs/static/img/eclipse-import-maven-project-2.png new file mode 100644 index 0000000000000000000000000000000000000000..a847c73360f6ca8b75774269af3a89eb958edd25 GIT binary patch literal 57614 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 VsctgDd{s+V@VwV5_ literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/error.png b/OpenRefine/docs/static/img/error.png new file mode 100644 index 0000000000000000000000000000000000000000..5de4a84bdc03d19af3912d4baeef9804138125d0 GIT binary patch literal 10132 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 V!k={$e@O?p_#^0i^||YD{{yuZvA_TT literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/export-menu.png b/OpenRefine/docs/static/img/export-menu.png new file mode 100644 index 0000000000000000000000000000000000000000..ad02db554911ebb4560bc04f7a6f0c64bf2205e5 GIT binary patch literal 12993 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 DpcDV> literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/expression-editor.png b/OpenRefine/docs/static/img/expression-editor.png new file mode 100644 index 0000000000000000000000000000000000000000..51a1674c370881d6cd458b2836e53967a8719bf8 GIT binary patch literal 16230 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 b@MZ1cpQ;K$2Eg8U9oPMy`zrUGxct8WTE!G4 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/facetfilter.png b/OpenRefine/docs/static/img/facetfilter.png new file mode 100644 index 0000000000000000000000000000000000000000..91f02528b2fb59ef0bf99e336a2dac92ebc96131 GIT binary patch literal 14301 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/failed-visual-test.png b/OpenRefine/docs/static/img/failed-visual-test.png new file mode 100644 index 0000000000000000000000000000000000000000..3792b2b225e7c3fc0d01367d088d4daaa169dc6d GIT binary patch literal 34013 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/fetchingURLs.png b/OpenRefine/docs/static/img/fetchingURLs.png new file mode 100644 index 0000000000000000000000000000000000000000..204b367a98e23c89f807b62aaed7bbe44ec3b0a3 GIT binary patch literal 48979 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 AA^-pY literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/goto.png b/OpenRefine/docs/static/img/goto.png new file mode 100644 index 0000000000000000000000000000000000000000..256ff9b9ea2e412ba1a0e22193357ca229bac3fb GIT binary patch literal 18361 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 I#FlX7PnC}(I{*Lx literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/intellij-maven.png b/OpenRefine/docs/static/img/intellij-maven.png new file mode 100644 index 0000000000000000000000000000000000000000..89fb6e95deffab25beeff74bdaebe154b7aaf7c6 GIT binary patch literal 42942 zcma&NcQ~7G_&%(v)zDT;jn>|qqH2cPL~XHGiz=$r7OQsEh^?)PT1D)=rAp1B)Lt=* z*dta%-pA*Ayzlq-$NR@G$B{!Gd2-*+eO>psuJb&vXkBf!J7kZ@h=_>pXs9de6A=-^ zfw$qUo4|iO9e<|-f3A7xt0@wd4Ki#17bFe}S_(u&m2mQl7dL=wkej-x2N4ma=hge# z{3~W(BBBBV4P^yGU#smoP=MiTtNi5<#|v(f&~L<54$s?Jc$|{?pd>S$cWB?V*16-S zxJu1j+=s1#Pe!s%MhIA^#%P>)kyVUknV^$njK+xlyt_DkceFiY z43D54sH(K_FBhLK2A(XL*Ux<~ zxOoy|eMt$I-{+XO#Cneqa}<|GfA~c)?Mr7T1#DDtnKG|wz;63Kxi|F&2ISrl^H#!sI z&wUF#CI|nGJc&fjag(kLa-OIb{Bf+wL;hwe}=6wyS}6@`VTp z;tCSRCVM-tOg$QQVUKl!{-haT+0;E@5A5P9d zrPd9p>Eb<+@k@!=S#Al%-}MtIBa#eW`Q+HC1fPE7Yf@V!e>VDeE* z6zWdyBkKL12GUBLHr4Yw^+IiZs0X$|oRV_Kr&JoPVAlU8jhCiAqvgrFOeS(IB(m8# zI#-1_@9$%}|JT`UY~7Rp5&>U)V6eUF3b>~G&o@0HkykchbB|s8zxvt(k1Y>gWqftj zRL}i+M8f~HSu6hkJ8^lP4}F(9K>?R%Ym)9Ox3n{*^9v|dx>wz^g9(>(asiT}Vq#cB zpnFJaO1K&*o(WFc>VMMp;XeCgn;%5rC?4qptLbV7ir5puL8&!{+Yd#Rhgbm*8mepf z&eplm$1}^v7a0_=v9l}baDJRC$O`)S{X5t5FHba5RVg#$<#1bKvGfw!@cUlObBnG0 z!PeRNc>}qIP&k8BQhOrhtE2T{#{Yqfiwovz ziRP=GPZ{g@uFo+tzkD;!b9>z-h?V*q4}1r;i$8r@HRnpfv5V7@J0sae5#;1f z7p|9BqpZXUNl(!Su!4euP0nOZx#T2l<6p-4X7D09{mHIb^{YGc{<~oDH&azAV>cb_ z?TdnVD%}Hd_40fF;4MTFfg4Uo{p#8c$r6`-YncV!X*_zD2k9slZfU2Xcw2a0e*O(LI1_X`c{K{*`DQcr2W;WT zwXKhIv-jGYyi|4FQ936X$Wm8VlF3gj;9D4sy&B&HnHXGq5 z;ZfmZj(@*zR8IE#JO27eZPE(!`olllx_fhY#l|$^xY?xJ%j^ZITup}Fa6Y64nF-<6QAd&91G5Zf9Mj3TuKUIwJ2F^n0otCkHey;UU)Hw`i#Ngl zEFds*Fh89YE2IlDEQu58}EkDvRu*7e>Bzn>f0?Dp^dWYFj&YHL-^RzV?zkDBautDcx6-6rxJSdb3~5_Co?qu9vv8v}q=SETEaZ7#oTm!Ev1a!$ zJMHgw$?t5E#EFmExTn9@%6K&fy(zQ#cg=G&9w)x9dbiwFs0m-!j6kW$!|CDEheBnTi)Se#a2S_vc*L@+B zPAV7f&WYfJN66|)Zw;zDrtqf9r=1seWHb!I(qdS~$6+_R4~M>n zCpn@OVP7` zNhFVukP-AeTm30++cmhD2@TsU{UqyG1=~_KJHtU=OE0!y_^6#|QXdw*6QOx9k@H3m z)7Sin?_c)q)xF8ET%PAPZb!XJZ;f>v@`y7H3slLxD-*0g=r3`FC9l;ByFw-MLaDzc zLsMO`T!OL4@R@-$MB!kGfb#4R; z`n$V5a6b_T#p~w?LC3UvtE%El_=oNbgRJ#uZ1Cz-BSngr+cTsfn*;W7BpuKFq) zg(yqg54PIm9X} zR#mFw<|OYWgBxM1@v$CgMRz{SH>JZqYSLo%E z3~M4e-+OnaLwYr#>zoT`379!jF z4|H9?r%`sAn4;)on39O@n79TC( zvQegArYlOAJjNPsceQog`Updl^T#=k{d(3m|Mo**%n5_1@c~?)IFF>)CSC4BnxT@W z`2&yx4Jcyd-;ms7SdJlkuXNE?0GIW1|C1ePxvi+WByEV#wa~O6rtq|E(l?;AYR4d}vRWf1D7$zg^tpP;WJzX&|Zh;8z{x&z}(Xuj}0(lkH!!<|jXE z?6xY+3>*2ysHuL~Pm7xtLsE`TpWoul@&?Tk8V~W)(0?gL(_L|a);6+^mVpnlg`jKS z){=v3+_jX>NZ%y>;P|^0*6OJh#MoD(obq1v+`XcQG{Ml(WXw653+npQ%AK`aK*92| zk2YniI6z^0w$VTfZZFSBu%5G` z+t_e8Ih&Uz=4=T4$Fq z*lQH`oB48&6!jA%Azjd@4``%b=}DrLr^Rw1J%^H zE=&y~Bk%tqIrzw3!3}3q{w0;d$&`B@k;<0VHFbbUoFAf`R}AD)(fpbHq%D1|7Fn@s zTrsn~bB{rAe@o3qSGF{CnWX;yJ$Z!=8t}YI?P&SB(vswR3en8(cS5_~cnb~q$&o!Z&&#bht_(2mjhv)!#X5K498+}fe& z)90ApK}P9o@@*v#ZsdO7~nw?%JreC^jU!T)dq)_;Hx# zL!RZ6mwa!t+&yS-CEPKo%cD74WfB{mys6_S=aeoWR&1mc-lB!AYgo1W{0tdrA3i^q zP5kOZ($7!7st9cQ>xMYfSf?3#-$$6uBlakLue(jR&ai^%@XBc#&ZHWzl&5i&_XH2F z3AlJ|h2fPyu+sFQ#kWhS9~&MzcIe~A4<6uJ3nnGd30^?1l6J=Tf#!`P2gsm5Z)U9)~QEbBX}xqXk%5O zEx9<&#kIsx$b@b>@ha@j6c~n%w)e#@dyN!(lDbMC4VX<3D8cp&vB~6%v zcX+bNs~AD~h2(jWTzt9(u`+QbLq<(U;#%BygCqgw?R+ln`i0k@@ss@x%MlqOugCvR zz9Fe83|I&m+mcUgEmZ<-DJQ>aC$_7ak?eyjZC?I#f9JryWjLxN2;~|EhLd%z* zzsTR=d;@h6&dh~yZ+{i|tH;V$%G5Is6BYRVDNC9d!~%4|Z04WEp3}B@lXc zGAxbQIM|OSHFVG?g%2AvIl?vtL2y zT8vuDWrSbglJV}|3u*T z_Cr>|`;>uE4~r<%_L54Hx}F(HJ~&XhSG0`?H+4pHY;opbrnQe%LQ7JdATpYu2>nvQ z7f=Yvw%v@V{KGX!o$xgym@A~*33TMXcD;y;VwPeGWw)(XlGizUNsb2Loayg01|*WK z?d-hPq<<Fi%k2CDysedpy>Z z`ajq5z%O&AI&!z7Jdqo*_;m;j;>(c?xXd4lIvkW?6;|WS^3jJ1a>kFNhV2rqPDA7; zuRI#;zi*h%z1%u8wK&|=Y9qT+Eipbr-_^my;_&-ZNO2iiu;9eEMZK2#O;@^cd6}IB z9y+Gn0wKzsiExpHpqZ3Edy`Q0qEN$!{j^aR>}j^i`fYY;LdtB5dJvU-5@pCM&fnfQ zLGWX|`Z2A8&yT%HF^!F83yo)ATustflXi6+xhS`P?KdOsT70(0Mn`~mZLrk=pm2%_Z&6(uB9D?GUobsj zN^?WOp*Dlf;5!tJ(4__U0IX6(_SmFA4*#Gu_=4Tc z%2z?>9oKRnf1-%PUC~zqBL-J^?KE)DV`R9VqODggV(A%78Ww!g+|#f`mZ$YOhx>|i z@LD-v&xO-5H8)z(OXQsR?`H4zrQVl8P1Zio{J3n5=hL?GemLz5N~u^evmWWl`0xRC zH>j?g>tB+Z)RaKPF)ZGZ5L9IQS zfE)9?23W(7HvwDf4R!3%fg`)$vTbKV-CFTn7N}sT&bzJ*i5o5xXd;V1#+DYQmlju0 zH;gH=dtF4<`$ZWFPhIANRyETS-&4WG&9P&~G;gRv1@WuI;KZe003R@V_*hmIzE~Oa zF3^H>!g^j|dQ<#I{5A|JHqT$CoKa)n62SGRz8nFG{`r60%|E%KFx|ZS1KUN`fRP`g zV(gP)b}|~v4h({7?z@Iseo7_YcV;=ULZt z&maHWu1KnOX6Ru>jz$cM#2y3e3RZU90as}|;M8J` z+VStW9og+>W}aYmz}PTeZjd|gNV_mvJ=8y3xL?MxoyzHkU%JuYy**;U=A3~ShyMJa z>F`6w?HdA;83zytg=>jJ$H+BA_i^bz%U7y!#whc)GZ$<_vxdFz7A%^dINjngJ20>|BPY!Pvda*psG-vOUq$0GGDd%%{gvp9-Uteavi1u6QR!~jb zx!PA406DGA7VeNJU9~klI~&{TFJ}y&nbuy!pP;+5zpIK1t?W;u0t^3vOpV4jit66Z zeWZ}T(7oe4Q3mbCU{%W!v|+Va^OLNQnP9K`K^Jeu+r;Mc3+fJG=pXX%i<_4xb!Z!$ zPWh;Tl1J+)@kmy{bNJ`!9UON};HEb?4d&kbqlOj{w)yuC4D#9q-J(@%AC9vCM>JhG zGN-!l7Vl(&z(6Y`UKA0gOU$Ff%)5qEf+30Mgs2pQqf*dVx zN!{hW^3o?WR3y{q)hc_>QR;9nVRyaVnqUO{h_sLGrrNGx{nDtbmCB4f_{Rdkg{8dA za+%5t%}vmy`)t);$=6tqy6)+D~^62IOMc$bl`C(#gBR0^%$f*)l-$3q})k1 z$4d>e4^H=&ovgm4gm;t2xt&f#A%2=)Q^~g4rD>_$QUZ_1ZOz2gbYGHh_ymwUx|aN* z3Uh8gqp7*vrTp4N$XaBSSJ2_S;&#q2cAK&6!F~qc7n$4e!J{njFi`DVA2!Z{jwp)m zD~<<9SLpz1W__-?9^pJV)YJ1UFcAFIbw2hIkHZbrYiji_iy!VUZwTl7(*nQsJLJ8P z2@1uP4KIK3>91~h(fN?h<<0~+X2^4I_Fx)Sgz_ex$9+bNW zG>Pry%4Y;$Uz15Z-n3>}K4;6rV^qML4R!Rcs+;9OF?Gy%^2fua1y@w115d+I@#*>4 z1S=S9sdG)JWlu4nblohLP6~48V3LXDzf?hs#L=M97FYM_rvJ=u6D@$Jf@*5^=A?+; zWs;@4PI}jnRqqnwg^j#JZ#Z_+8BHZ4CHs=0tmPlu#jb5?+k5W$GQaz@Rvy${>+kx< zQ<*IAJ92N(_#1WG=S1>dsHI|x3)2Dm;GGCexn)OzjN2xK=Ho&20ZIl`(-y3yRkNJX zFT98r#&e_ehY0xbxgWOwE@)kG_Xw9t1Uwm+%dgFz1}~uzKALMUU>q7c8wMy}kPC&7 z4fY8zKw5XJc|+8mWZ=0czR+^skg&(I$9j2fAUJ|v6H)l-KEY!a0$=9YP^;K7smC=ZM)uY zCZ)<6W+xiERv*D-f_-HwD%)@SQn`N z0=(^iSsp~-Zg7huof$Q`hlo=rpyU;&34zb%qNE>;`8O@`elBQ{NVmPM_Bapy<^%2!Vkq`^)9*T4`>gyrJrRc~41h%* zR|I|33c>ruc4i(|J0!lF5p*j(O-4*6T38iq0~BaM&@u6}Q0w#mW`5bf;Pc1HX6%)!Cm5r4HI6v1}kas=esUi#waG-ryG`el_?M4+$T zt39fFv9sro@fi|qr5F@8WnsDv2d-(oAg!5mOGYRHTc_nP#s}S%WrYi~_PyA&CVZSI zCVZG{_C_i&O_ZKczyUBi<5pPJ&E>Ddwl5#q&G}lwHu5D27l+W=T0W7Ea3cMmLJ!vZ~Af&UADDi{5HSq zjG=V{rrwp%)86D)@$A9&cB`XM4>rh|Zu>jX?bdp@Ve*at7+nO;gCc;8G7 zJSYZr`HN84&cv{-SUNMeHQ!2KY*hMlFjFQmJ-t9NkNR%DPi>8ttnc18WK|l|#K=F9 zPbraV#rP${W#1OhvUB>Rf1rPMms}_P27zCOHwhG zftVO;807}Rm)^qlGowf7J|f+r&iP^=)h?55i

Hp|qB}bPQ=PXxtOs8t?h?06Exw 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 VeIf9Lf$zXe?*{{|LX9Km{skd+klg?P literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/intellij-module-settings.png b/OpenRefine/docs/static/img/intellij-module-settings.png new file mode 100644 index 0000000000000000000000000000000000000000..1279ae1a188bca408c46810eff73c753b0e91634 GIT binary patch literal 65333 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/intellij-open-module-settings.png b/OpenRefine/docs/static/img/intellij-open-module-settings.png new file mode 100644 index 0000000000000000000000000000000000000000..7b006e02ae842c88478ab2aeb7083c95ff9b4e41 GIT binary patch literal 78009 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 Jgfet}`ZpmloWcMA literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/numericlogfacet.png b/OpenRefine/docs/static/img/numericlogfacet.png new file mode 100644 index 0000000000000000000000000000000000000000..617326c763bad3096186b56bd0eeaad7b46f8903 GIT binary patch literal 5310 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/projectscreen.png b/OpenRefine/docs/static/img/projectscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..e4b5e839ad431ebbe8dd14e477c251eac89968a5 GIT binary patch literal 43634 zcmZs?2Ut^E*EJfC1r!h)ARwSprA2890-*><@4bmM5h2ncl&Cb3CcSs*CDMCQ6eKjM zks75KdZdIvLXx}VdB6Aj@BQz7k|#TB_ciC5Ym71Hj?&XnW4OR}0R#dus6T#W00Ny( z27&&`p*;t*Sn2Rd06*tnJ~sCPfiCt^zo+`4WeydMMD zUwT5FTwXYWK>o8ihR#NY>&$Za#RDbHx37{lp$1H}Hw~1cUtLS!6TEf)lE&Lx1v5(%>h1VB&UV<*s);rwtB5|Jr9fios3f=CZ=>nbd zpP-`!^=N1H+`SP=Vcby4usZcB>{O3;!UIj(SJyxausEd>kb>%|S2^i?hM@d2peKX& zPnSV@BA_Sy@ZS@lS2;%+fu}&0$+wtJv*bs$=L&|Uqv;del10zpr{adZ2F!ZJYDRQF6}cZF&$VFZDm z%BYiV<&jo-ZAmNQL1Stv$|*3S&LVV8%I+V#Oa;-;0U4}fuO%3N?hk=L`3X$G)9#b} zM=sWkj7Y^bU9=V1=srie{q*TFd3Ch%r2+`_%R6L@EDWw^d-d?#D>rf>@6MTLHgx$u z_-Lm(MukRD{`#!x{!41#s1&?!otar(S^1&yMaj|*X&Ov+{%qT0N_ue|B71_z{p?!e zc`auBTJ6ly&(A{#TE#a;6VHb|o&O!LcG65oIpLVN{YCw0tC`@nW&JB2agQ=%_Qi^C zM=2%V`N}&^aackN6Hm*dB|#sb%byBN5Gk{^KYgglf62_dX9*7i?X^QcO$yMSe)TN$ z*Qg%_3n8iH^MYPEsV91XKsJwfM2(R3kbYVa=u!S_!HFoR`x|1hT zVM;t-J}X^Py5R8YhUb$zRd198B8ES52tEN%DsV{j=s$}{dU;XwvvJEsxtELtJKEe& z0v)fO7649Y{FZp$yzT6~zqjGE6eYP;wLb~q`-uE)&ne(&0dp5Ai z#Yh!kzE?hDoQ;=P?!Vi!cAZB2%Zt0BeZ5Mx4}{Mr*$>vJz4n9A_?2Z?XiN|c*NdvPE zu5~oh$-*~q;Tq_eK#E+ zTvuC5TRVN=N6!$!6x#pRS%5X`I?Z)wR=?|rbgdHBiD=e-qr3O-ZKh)~7&D;8W`a$E zK}-qA3n>~Yd@1aLV59Pil8VI&I^%ugL8JI`8^holRbz3(VQC=XeEUqDLT5qtQ>;$1%PWL#<_SQL%5hzXD4|%tE4SQ$l4tt4&R_i@S zE7ywDv{bXo$Cdh(YMY%>HQS{*C7mkm=ET<*75g>#t@zcP<44ZsU<_vr7fLUbGHc7p z;A%uGT#MNY+8_CKyO-{y=XTk=%GH9FE(UaB2seVkBqNd=p%kY^Z+5Ppp6A>g{m6CM zuaX{6Sq^aj+^)W|b+3YQv0aK?+OM#L)-lLw?4PNBEEBcxA-)* zH?(&$4YXTJ?vy;#dZ^VuJTzQ5Je?t#C3g=chRMQYp|a4;Pb~Z`gqzBmS{&8uRxC=) zcbYof!!4xEi_MHJtm{>)bEQ?z*C@LUfgNUpqHqxWV?| z1k-BN$L3dt7_JwxHvOH(?zdfZZwNhqcx1R~1SIa|TQjz?duft>WAn;h=tqP{sgD-3obTyM zBSbVL1?4M5pUckPZ{Bq6>Ypy&t)hvqZNX$dV5J zX8kgtVC3^bcqwza=oMj^R0XZKIuDZnC|(jQV~*k7yXwaqcOl?2$7ko;;4!JOw?CAv z1UYr~9tąNgMBm;Q9iWdv7wubSSzwgju&|1in$z{&;z3C<8Y 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�wfe!;hq}^!2d2 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/reconcile-with-property.png b/OpenRefine/docs/static/img/reconcile-with-property.png new file mode 100644 index 0000000000000000000000000000000000000000..e25b81a27042dc550c74d212a9f52342b4b2ea25 GIT binary patch literal 23650 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%0D)ngI(W_oi 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 hq=0C0c>z8*Xmfkz}2`@sS8{{mL7KJNek literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/reconcileelements.gif b/OpenRefine/docs/static/img/reconcileelements.gif new file mode 100644 index 0000000000000000000000000000000000000000..5f0403e390ca4d2ba9474fc6f4fd262f73bae870 GIT binary patch literal 243942 zcmYIvWl$X7)AcUPvgqRO1Sf*KJBuyulHddqJUENH6WrY$LLd;_LxA8Gg1ft9pZxys zhxgQ}d#i5M^r@Pf?wRV-qo5=ⅅ*Ygax_<{0ATq2m*n?U@#^oCN3@>DJdx{E9)Ch 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

cjK#{&cDD&y{zP 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 BU84X1 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/reconcilehover.png b/OpenRefine/docs/static/img/reconcilehover.png new file mode 100644 index 0000000000000000000000000000000000000000..bdc6bd5e64978eec8c85d64a815679ea0cd37dfa GIT binary patch literal 67374 zcmb@t2UJsAw>FHTfC?hLR}oNDdM`P2P!JL6CG=hdq?1I7ARR@JBA|dEz4sh{%|fB^SJT}l4Aui4i5jahDG&}xj9cO`l|V8*A{wvxwtE`Gh+Iz|%X zb?#oQ^C%*S6CKr z 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

s~+SU$>S*E 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 Wun>r}X|8z-a5&gqu%(>2p7>w20S&SM literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/reconcilewindow.png b/OpenRefine/docs/static/img/reconcilewindow.png new file mode 100644 index 0000000000000000000000000000000000000000..91a94ecf0e616331cc82c4673a1fd479d9bf2f44 GIT binary patch literal 19124 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 Drls5+ literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/reconcilewindow2.png b/OpenRefine/docs/static/img/reconcilewindow2.png new file mode 100644 index 0000000000000000000000000000000000000000..e0cfc67ee005b2af5fbf5eefd22efdf2aa573628 GIT binary patch literal 25699 zcmc$`cOcvQ+czGgMwJddXw6O?W``9*>vW*#L~A!njR+!Q#i-((Lq!)_Bh^;5wO3+A zS`MKIwStgPBNbwW7!jV2wx{QNkLP*5-}`spzvqt@pS(ZsdA+aeb-k|Z%I}vgE{Jd4 zyA=ciiJM&f^(qJ?kO%_tyNCz@Puz6KSl|aA;_8L7pnS621n`HT+ZppSAW#uTY|VKK z@VBVX#hVBaNTP1@A0G++)&&HDE}Q&%=6aw5YtR>?%0Me}&|*PH#fP6CVcI-u6&LN= za_rBdD+23LzefIA>>^|HVjmwx^f&(G*9UI;wO1M-uYl`UF$bTh+Pd5((M|~6Yq)_t z+H`|Yps8%ESE2x^+Glz_HhI)PgVB=4ZaI0f?O6$`jr`02yM4B*3X$QK5#&mq>RX}d zR)ugd8*_&FPx`aNhNZ)tXMMB0bJC)iHq90963Wt2nU%kg)7!$=*`_eli0dKA@UtG% zei9OtI4rtob$x@wh4S*O*R5uXaJA5tN?0_L9Zq^m{9xCqQ5kF zDZ)ua@`(27w(7Lhy3?Fc34`rHS?IH67>ofPO5HnY$XTYZRfQwi%TIJM1`sW5Df(;Z z^ZCH#-h{!PcD+nf#yDoJ5wi`FfBgvG)v-fH?+MLY9zCy0i{jnl)!nEbf+g26CeC?L zmF=9~V6wU$B5=*lyoGzHyMz8M?S@$6yYOV=2d(?i`k@e+z#a*4zmk-X!fG>AgYnKDeQhvLRUwjm*CiWI&^ z(#B+ulwx8vYZ=D8Zuh5g3t{5+Z(~Rukl}kegh2Bgd%QoNURP4W9yO0nF>0u8SFfDu zNa<-Dh6~BS7?u)_vgM93T!|T@K_a{ua#fKgoH-Xzkr&{-BDaLrFDNAVSd5`LX#Fl^ zTk8&mx~1#;u0D7Q%#gXIabqf0?a5WsqglXz=|1Aoq{~r!^Gk~87e5{{134z`H`{GCehi%a|JY*>w}|TM>iA*J(A`Q;zmLcCZHYat z`I(oWEHyC_$*Pm!-K+g^oJ>f_K;(da#-h5FI~4{SZ?_6?Loww-c>N>0lR6oP;g*WF z)_UuQ1?!K|kq!mPTN+w}5+U$bz0{GD#k^|RkWH>;JqMBA`z2v7U^)K7LYMJg+M zpVQYO3-jK9N=1_$171Y=kWX^LT=95p%xfA{U_==M!xC9gZg&90a1Oz;t75dgh8nbI zr&C>Xi;%ZZGps_YZ)4HeIB()d23Y>&vz+hJh3NL;D-L1g4d4mw-s%nD$job0-^vjN z+)!>BFRDX`;~k72KfNyvmL%-yGIf+nyZ=1b5|S;7kh6o&>O57TqSnx!RV?#6A3geu z$P8+R;zV^Nx@TnFXHlRvXg3FqsJV|0y~o(!)3{1NT>W<2-tC#R;&+ifg+slV-=VW( zTgM;LZ9yVl6!YWTg{U4;^$vV~D!X5QA2i31Vsi~Q$eDKhC@@nmtu9&r>WvZm?pbOj5IwT009HugYK4!cpVP z`iL&o2H3bzUM3@CP5;U_Ib(7>Vn8=3<#Kzk zevBo;``zi;Y8dC0 zf#n;;Npg`HqvD-^ZX~+7p_+pzLhvg8QWJu}1p{v8PKdwnV9y8p%*cp##c*rva0N_l zh#j}6@0G=R%$4Sa4@*JfLl#|qzZ zNx!GbS2jcqM>?YWCY9mhWSGBVSK1w9!DLh}p?+w|=S31SN>BCXnS+EM%K0gvrj@N% zY|r6QYCkk-7GReqZmi;lK4Q^7T8RV3;D=uKxGI|XL$7BY{wE%@wk0MfCu{1*VEAAE zWk$R!e#pR+tN%=Q-88;kAW%f-K_h+;NaJ^qC2sm-0FASTbo*7V?sA>Q$1-Gv2Dx(n4;Wc;cn(yZe{sf%G4wj7@`V}NphICLE+E60Ek780*gqyFOR!Ox9%$G@T?-%rEJZI&-l%r(yZ;es zi>K?^_3-re!3cR4SaVxva8z+s_Hf=i_l+VS8G3EMKBR|Xw0W$-?2Tn2cv$m^<68j` zNVrhc{^keS;^P`g{C4m1mI8WD$s~=Rb|$}iq|qnT?zX!=)cS2h4tw7w zTF&L)b_W|wRy`f8F@GRL=exE#@B)y-ObDlmC6l>6o4P6Fa<${E98IG)A5}kBnf3mL z(ViUWm2bRvwNbS!3(lCjNVB-L^`-!f$a{?Z%4Mz2X&rfk=2QyY)acQMKz4b@PL;IE z7M?V6aBygtm4P^D8?9&4d4t`UwXf{%CG8RHfXQp`%!)+)o)UQv5vK9!h`QR#mF)op~< zQbMy$uf>~<>(`RLvwsdz_KyiGyQdI_8DcN8fP6?85 z3PehaAfUEh1+YMS!V-$EZC6}k($^+Jx})ILbkTTsgEbt!0C-KMzD&U7sEozCS*rCQ z8hFJf!BePkc`la#Be|)cJ2+kn~Bd^$>wofok zgP+7Nuqy@|>=Kal?Gs5HHuI(KOq+Fg)OZn8GsrvJ&%%hwe7U}=Q((0sO*$HCpmJNW z;C);sgJJTT%M&CGr8q8OrYj7h3zT)PUXWAbs&Ac(UX*dXevPznFF+Pyg1^#F)09s} zw-!4Jmw%|xjIJ0XL8lq$CWgG&;)`49*c;N)$lt0P$<^0%6dAoF0$z7+aj}x?$AbE} z6mVCRhoz?il$-#I)OC6^=%MH0p-+V6_6AB?g42OEAewrkbv{IdR%>>O}6tNH!ZNCBWS7s;J7 z8c^sPwy7azD`M*C!UOp49#p0&>Mo`F5t6;JV@5_+dG9k@U%Kr?<;t8wU}$6Sx;9k~ zO%DFV{jBKbG@Z(u!q-=g_MHja(I5w&H731a_ckK5N@?SB9dj~$8~Z}q@_cg7w|%S) z)oTkX#(aLl>s?wAMI|u9a$Ks?YbdFny{;>1qiQBZT1Xq3yV$NG)i#$|K-{;I!u5LP zZ;@S_!jSH+59)`z42E)zdBN!CRk-0ua_FQ7Q79F8m~ei(35oD_DXSB8*YSMApeC{W z$&BNi?%h9;xDki7tAsQ~wguKdZG1WJ5l5q-G#uQvFKR?$D!j_EY280oUN51n&|zk+ z$$vcY0a%B~nOo>}p$@3b_=Y}TJWq_3$}lTfOnY>0FmlRa?GW9k_UiI&dNl#b+mB;C zPe?ASmyTN4awLfFBGnX{fObfOdSiIMvzaxGn6~4(uIap{rwKQmy7 z*XHW1rHuu!NR2ux1D#`6ZMz0tt%qe68cbNX;8TH92#5p1JBkFIk{dvhmFa19!KpX{ z4%7!SG0<7mgM~Bj5TQwE&|rn%t$;MKbap`(3O!xMuw9xwd`+KZM(tgiJo3!aeUQu{ zts)gMlYf$8IaSZXPsW-Qd^Q;L9nse!-C@=UR*h?)!ge4MCmuZX^7Nsyw0gLO@~A<4 zm12{e-qw)-&a0jl_ZbSCRx?_x>yHEbhD9M*WLU@C?^q0ayZEGesM>G>_zUP}xUXB; z$~}pB>9_^4s)cj*x75))MLTM)k>t4gpBzH3au>|00c1~?a6e1`mIjXYL;TZ*fur>G zKhY|%l2aBn4)5|H_XuLIEJ9vVwEXN4U`lGa;zV#oIyFTHUmlvia=-0@n$91ScY@Jo zZI(S&anfgoBPYpEJ3B(;TgeZ|LH;igYfjXQ{ic&|V9{Zz1$noYtJysC0Y#LH1cBuu zgiVfIIiH0ac*2uFAFhEcG|2SPkMsr1lzCG8UY_!%Sv~J0`#xIqi!EROx_RvL6#)%> zBNg|--g{6=BYvE7RQ(?DXOrry{C( zDfVg#Mi(gyZkzaXNb7u$Id_^Vy`(v1TRce96BrR9uwHWqx;NIP5=`{GD+#q)Q4SlC zHH1ZA`A-^-WJs>86nX0U4$df_f!9pi*ngOC8YLdtJ>4DRkyOmFwt<+1KiyUJ*rdI9@xc>v5u4qH16RsnBm1_vyss+ zl#SCpvQuEr+Nks|&Wne=9Dqe96d?{mAj6*7feFfv;T6?0W%w(FZCV{Td1`s(+og&3 z)16^6zw`2L?#CFIKG&>P5cl`Ep-IIFWeZU@ZF*#)9pegLk z%!qpPPCTiakO!|o@;+W ziG_PY#aa5)xnl~kMZ7(!)|UsuCQ^PG*Wv`_pLDn!sNk2yYs24sUf0DF35GQdn86-s zkd_6wQ2Opy2ITq#gPuv1nQ!;H2sUc7o#_@tXHNPPCcj|BKJ=~y@LY=uXNEmHHkG@y$ zJZxh!9EKsoF`9Y}4ZoQ(e#LDECtr*9Wmhl|OqChEgr;DFJ~=(=;AvvOKqe#5#XD;( zG@rmrS+=W{$G-*j)fjmZO|+Yf9;q{x5}e9Dt*sKi#znXG4&oIZ;rXevALOOT z4{C#Y9qx`Z!YAYuxvR2;H8u`Q299~mic13xT?MZ`7OXr(F0Jgvz})F9is##jg2e-l zjCZ4f`Iswu$wj*3BNl0n5Xu)s;*keC4{|k5wXteuZjq;CwDoCJ(hF_UJI0?8WVzys zgjRJ~)Y_yIX5?|(X-Cej?Vo*xF4|PCrAm&%C8Xs)^XbPPko^K3A9qL z9(DyFMxGPi?7d|T{8GuP6bB28j*Z>fh8Z4#30(xGbVBHHp>%#H?+cPjox7CybbbMF zkJ)}B{txlM$VtG65qm@vK`NU*ZNlS86o+>s}tEHq(V6b;RsFP?TOaX-FG~(&UO|?(a^gG6p?2v)F_<84&buskl9}caRjR%J_$A|FU&Wq zTNl)9Ak0v>Wu*!P3gZyH}5?iAuCGC~I_vLpHp&T{^P~}+F#pNP8vW_;Z zIk|Cxyz{Ox4%Bp7B++t+g{S9dgs-o-zIz|Wql6PyKPs+$T$bvY)l|WsCANoOUpuQ1 z=zK|0aq_Wj$egEx3Yi`AZiGCX!VvNikdRVB*=fMbq#3ZRf{K;skg&+KGHtpWSq>s7hpWC|fBqMbY;Q{U`%yA{xF|0~> zz2yq{ki0H3oPwL@-I^3?#I*&LgtH)bs51Q&b{up6MCV{~$6O0CzTU-5j zbe9tLgPA(vI$^Fsc8(ps-nJ36*mccv@xA!NOvmMCjaQ&&j-o?zElI0ezJ7VRUfV`w zYO6Q&$vkdIZ_;cN9})yxX_NQlR~w~^c+ zD~O`W3XdeJWWK12z2aBd%1O}zKboQF`D7#Rs{#U}4+L?#UtPd_VGJjXT#nd=5#Fu{ z$<07>`j%H-EJqL2Tt3)ABCWpehZv(%Nmh$-zcSAGe=0}lj#uyvMBEf`VeBW)9h6?5 zI~@{orLts$958-z*V%@QoG1MBZz+=f$znY47J~jELt``?) zuZ=Kk=r83P;EUawm@d|`lNIfoZOORp-zK)fDGNP0l&}t_J_Ee54x0aervBwk!_qSKz4g9k(0oTPTwRyCQz~vTu6rDLw5I*^$e*k%^(Qy!G>Edg zk8fIsCdei!YD?pI88ReNN2%tGtMnh~r1`i>*On>nhc^b{t+eiNH!!;in=0RS13}w{ z^$vl|5ZHd!T*Yu$rmM4$V3-$@1V>sFDUSL!Ae%n++LH8{=Ms;PmNaQJ^ zGsqUud+O@y(79NS~Wj;VX_tca7mT?i&KyU;3b*4hPk~W?0`F3r;0U` zmtqW(Mm*;~%)3UlE~iqKL#ypsEz05EoKQ7zrfVDfu1oG`4sAKF+R>4Fxv{Nf-$T+Bgb6^ui^O0Qz}ik+Vrfudh>>Tkd3myQkP70UJhF(T9? zW@?{Gd0y^NoNg1;D|@#YM=pGWb@0J;AEe-hc{lQTv!VRwe( zsy6tg9G$4@%U1*Udd6Y43*(ilFWcpA9U1>37S@Skgm&;uIO>k-gCsi|zSKNoi(X)a zpp>@`NZ~BQ`*{2gC2ac$36m4DG+hslABMdjc9XADZxL0j^9$53jSZ{%Q@x)YSGT$a z$|f2`&+ewkuXt>S`Nn51jzEX&Zy$V8&p9aahOaooeVJZ7E#LGeue0D8{cfWDj2kNL zVGRMvmt-Cx_{saYkrvfAykps}3JzJd?ov|Bea|k5W4^yxjjU%m-jH?!?Dv_H#w$CNhL=SW`A79cT!-PPh+Jbg z`EAth9_QkUxINrMnVPsmP=1Z7b6Xm1MKkzEHFte)?vg(9NJ&T6X#DJpO9C$QNxff! zK`mz@T0|2`7bEVE95BiVjo9`Peo#Xw3$!QsF}^T>-^KY7$Q4x%S^+2(${8=@mGt!V zyvdiphrxDK_v6aUuXw?G`tDckn3^YfM4?fQQFl*ZO5()$=0!v|m)dx3d*TGuI_m23 zBsydLOZu9`YakJ!MM74|_=smzzaA(f)}<$=M(cC~h{D2)K5@5ISTjYN>5cf40t@vD zNIR4;4?v=%3laKrpgrrM7oICp&iHVXdfIDNR_afQxEfMqXhM?`2S519=^4F2NkMhQ zw*LuArk_)Z{__o-X2rC9lrMdjvGP6x=J`ct;27Vo1PmysgU@fd4V7yQ*l&FAb;_n z8DHctf-E{=LXFe%jSoT3@L7@hr4FMKqxOf4YUg}~PaFjh-!voxzFtZL`vlu=%^9D&pinRCGDf)jiNsv2wqIVfSMkO zCIYuX`KyIcBbj=OJ5EK~EvK(aX(R5n)UqG0u-%&BPy;+@T zM_6U%bPFqnw(EENq7cq1que$G0c+X>*(-vyFfNO^!ob3lK5b&Y_EBOo@`k+&i!q_t z>CrHuFZCx$omqxy-^5B%0O0=iQY|-u9ys#A^_|Lsn4x4vr_BqGTIZ$hXA1RB1SS#RCcPak~nL z2>|0;lsBRenyTiFD;Yr|vonIrw+d;d$ zY%*q6dm&Iw4E2r{e6x4zV*i(56Jq2Fd=wpr*is$>h=&v1=!jA6uxO&#w#20wIwqVk z$6KPq74}H=8w013oe8?J?M9G~*=qDy;x<%FG4i)5LiDNpWTEcM|K5V4;{MW#n^PKk zYVGiQIK!7hkKD#Pyl30xXvde5b@Yo7xzXUK(m4iaZ>~ypTuq6CnWU(+LK*Unui@^g zAXNKDewR=K^Nq*q+_oBXEO_?$WC-cwzrCnxM~xt1Yvq-w8HegR8QPn@VLh5_wP}F& z5K98=zjjlv_D4W3%I>Fp^qV3(cI9fXBBF~7DpJ0#ZM(hXrUV{Atwz^(==Y#>sz%}$ zSb1VTczG=&iRz37%1rIjgQE$ovi_xnC`mxomJ2-Vdc^N?yxQROT0C_5obE6_F9zcr z)IqhnRu8`ibGmelH(dV^IbwU!jBYbh|0~#a*Wp({pYFCOHAYSjtXJ;&g-|bQIAGiA zdBWu(KxF&PhHl^>WdItI$03Xi30~BJ@Q>CC90b{st_U`c8t&@cNVdb{H&!U?%3m78 zRU|mD*D&dvX%5?v+qGiZ+D=TroPsi#KIRUm2Cy!;k()I4^slD`$hO{w2hE2!Na5)5 zd)6}$U@J!Yg?i|<8N}Mdr>|8Ll9$BKk6%;zTRY_mH_DuSPNGJ9j)^PH6WxF@X-gkqz=ca9%|T`nzr;YjpT!;Vp#An zPB@08-JIHPqmvLtaxG~^(x(F|(ZY;>9L!n3MZ_-X(3xyWmHx5Ag|D#}OfG(+nxetZ z$1dKxT*J$7NmE%C)LgqSJn!4F@?;!`;Qk((M)m_pF*MGwJS{)K|IMZ(-8%~+h_o6-k& z<@ZxzUgH&Q9A(w*@tt6;=&_E_t>3mEuw)-Z_4+}5wuVH6RCnpAr z!Xl<|7L{43jc~fQzcyc0#MK{8_Ct8jw>x_#~XYUDugh_cnZTyzG0n z^2`3AYXw9YT~*|s3LC67{&D^8q*6)-g)BcUH;d(WTp<<^ghl3c64B#Z$Q zzi(6ySB?B`L0lGQ^KJkzDFL(ZA}xfldW)?CLUn%RAN{;__|C1n6Q7KC=&g{CZ;GQJMh#VWO`KY2f9R%znp!25Zk_W(7^ zbrDlPY}n-5au!L!eZAED1FT$3nW@7_?HcAe7rqz-;TqX>SB>|2~cID7;N%XO*GQW9+Z#_5@iFp z?*!j`mw?MEr(0=zBzOiue;~6>b6UHl{Hj^Lu1MmA{R7UI*duy^hv8=C0?@pTlYm|R zuDEtFVo2Kmi{7b2>RHp!=i!+!x4U^;1A`F4$;T(DJrdh2TI@LhhF zTL3P|J{#d8ni0%=NAMIKuLQ-WDs9d@O$j)(UhN%Q6MX^!j0*_*E~T6N-_X-HsNpJ_ zxXCT`okMo3kiTd#d<3~6NMEb;^zKCi!&~UKuXg$G<4V{bi!W~K@BjPm0f^SpROHUS z>ef9<*+RyA^SEzdrD7How6V@()=N9)W`s;vFekFH37Zax9H>DgF_!IwRG3*!ceHB> z5%!yxzx?yHcF+nfWTu|jyj&}$ejQ%3;<`u%&s?9W;d-yhB-M>%^5#ZJt$RU*$aYW= zvM7w|Vk>QazmK7so~}9X(@7f?dm1m@U`TwcMy?wH7^QqNPT_ja>Rg=Tr|}((u7n$S z)M4%7ba@3k`)*q?>{Jo)jJsMoZZz-|)#h~O>8_x=Eu>FNV1pWDJ4>jsc22(ED(BQj zktXUpJQovBR41+-aNNi1=-4SIfY4IFX4A#G| z`N&AJLB}!A_@=C2>X|QtHMl%cjY*t0u~%vpIiA>B)@jvCzW#Vg`$+4ZuPIuvBF9~$ z!7u@=+eqF_3XT-AG$%h`rR9nWp%^B8+j751zWKjdGXVVXlud|Dm?rKi`lbF2*i=tK z(RlkxjF3+y;E^Nt*_@(pKTH&Ib3WKDdq6RqOHdYi>Y6ya!Xew0ge_-iNx7I(pLxu$ z_vC|rIpAUIzUXzzeSHJlzY8pn6AH>x2tm4@1idJn9 zu2;$R_AtptqVDT}#iMy4DoGj_B5ZvML3%_JjMy)-VD2TJ&`x#1hIQc+JVl0AF2F36ZOF^xs#dZ@TlIX^s5OHd75UtQP*^|6 zqHzZIv?cG{3=Ta%$)}>qv?BY_|v<)jj4A}Mpq$#4Q zzhmSf{D8dzw|ZS$UOg-vTTIV_-GSy)GuCW?n+mvF0ES8>3hZ%MD1mnoHqNEByLD*a z@6Z{9YYgJ+T<9rZwA)svcCp5vs138 zppB)|wDjOEPmk^?D`&W1uF%XarAt5W4^tOCk2~27;mST4?{Ggpg{ai$1SQ6!YHoFN zpH0*M9I=%t(cZiRB9T7yTm0X2Kd^7#xg*VUU-4`=r4VNy-hO(}Ft$T^rCx}M=CrFX zC{lRXFBY(?v?q|VCTB0eRBPf=MJJV^q)&A;BU{|ypkX7n#dki9Z(0gaeFuK@Mepj6nzhbNHFPc)>s2kA#TL45-gQ?!R( z{d&CTL6|L#t0iQrODAj`9Wu$E7IRbJV4BYN{oAW#JIs1F>?T*I{z;SwI~}^Mc?_S2 zGc|-o0+Hl8)jd`H+WDY^1)Z~TbyM6t$r@;R^EH%CJbQUibWDNu$gp^cU_M> z0E+0!%B{s@xCMwE+u3iBMo*}alNS3us;fX|>0@a7?uT`fpH3GFk0yGqIQk=#Xb z_NkKLhstghgH0RptNa19o01jTa#2Tr6I&phc5MwgdsnV1C#4jyx^aMH0p=aRh4Z5T z&WyY{8|SPMl8g(hhax|>jD&=h zu4a7Z)x1|DlXJSGT<3oKhUhjKk92%N&+Q$TW^~3;d(2?K@~*Z3hVQHh)Z}h;|YowAX`w+LN%Wc>AeN-g&Dvj9VS++WD z{R^dS)C*wf=&&m~89tcw!{jkP1O#v>IWtVJ98o{wlh(}TfX;`ksXGP@uR%ATn`Nu& zDzs|a=aIE1(_p8{|k$a2uLEpHZ7)67AA z@(Q&wCNCxix+iI$Lw3|&qV@=;AZ-H}>ZQ?P>AEfmR_QOelGusKr{gF5FQwvKvD#gp6eW{QW^!BKXxPaUX3%b7DaU*FY_1>_za{q+F#Xz$wadT!-N!jaZ20B$h+ zgQnO@duBq*-Y=aTB>oQc?h0RrLZ^4|57(3dm&fezH?#QL17=NBq#M+yj>TT{Xy-G8tU zqf|K2-e6;m-Fo#V5E@8EZn#?KnuHfJg~r0on3WyA=Sf~1l#AjBeO9k=-7Wm$p3Q)6 zi?UtB@v_n9Q2(NmDHhuP`#jl@VxxSkku8Zw1X@gKz#6=_BhbXc1>n~E7I02V|nMe)oy(;i~AW^yP zKPa;g*DMXXLvgl1)N2@Dl8_pV_mwa2f%~@dTWzz4*`BZx@c|OL&dCrZnK-m|Dy+`o zgq5#p7AydFT0tn5_I|Gd7~bjcmVdKRfr@eR@`goJ_u}BVU;KO6+8-n8zQ?rZMF*zj z8*UE?8_SRvUDf<_wizgH9Cogx3J|ZY3 zMW-hKVIytL-D7A}G%+DGwKW(_YNTC#PA+6U(rv$}DpGsZ-3*$?{w1BYFc zesrX)^xOVV(}{{3S2iXlAv*QBh5WB@1;`Q04=0!JRhYuHPGL-#EN zvdMeQ^Z7BWt_z7K;?MomR!V@Sw)+Q96R=~Xus7iCu&CzNVCfw1_MwHUAOdlUL zs3FDBH!UuX$3Oa^t%gK5NIcX$jSbjaG$|t$o)PA4&&z5<+l3BD79>l`w)r-!=!+n4I4 zUV1OSFSb|fPPjJ~*dE5{&r}l=;l`i5jql~Jh?zyE=L!R)LIx&UC~<;id-Q_w)#3rd zh_si0)jOC$LxAn1XwNVr_hmQzx!DSK}P|7GMA5Q2%7(=s|-J6NTa_N2D$!C<6HieB=7I6ZPes9wXO z*Y&IRo$CG?wl~$3X9_#H$!P-7CKs0TVvolS)~8LxHs}j@Q*{@2#dPerwoxS-Ru(9n z-`k^>++UoS6qDIuH;?PkiK1eGki_uGglAr_r1;0q@eG!$B`=$8B^8zu!I*2*neu;( zhb^#j9770zKBwUv;J04_lXR0)F%r@&cY#0lDjinu3X)IjK@IIS|L_NE1+J%B)_vgq z<4Nq&l{NJr%p|<09#`m7iPG#h+H~#yAi6Vy5X2g&WbHqCbcs zN@S7v@B1$GWcpUg)Vd&005e#A5)d``uOeXRzPv7+#sxW=j@);P)~I*jaAc9PpeYdG z%h#<0?TNa+YilRoF{xiljb=W;;2c2R`;O!km5hyA?m2CXZL+liVhUi!S0L97?diJC zX}(JJdW0|Ic#`C_Ctc4hn>4s+ew&N_BB(Ej>!B)Cw;;_d7ZCN4mWM{%zXoUr!0Y*4 zxN(*N)`L4fFl3jD#|*Rb09ZR<@Y4o9mPj-XuQ{NPLvxwTyn^~MnG>7C0%!gm&;yY! z0GVx?zn?7Bzm$XYuOu`1o#LCHpFa^pngs~Hq3fG`RMTg{#!^7dTL47cznuT{uZ;cQ zpOH0sm;Xm57;sxYyxRfzERO(p$Q|$-HfgkfHi_&1?IM2Wr)?fYb91wdLLCsKjsS!U zNKpHKkkaTfT@ejE2><^;zKlMxh`}6Ytn-=kRrr_T>Hk;nbx2qxtB(0eJb&LKd zk_-Ra7XdKI-_src1LGWVNcTDDS<+v(= z@)!F7sEEH9^#2cOp8tO?;%DONKd-BGSH4whw%T74&&vTyHU|R+V_t3BtdazHlg%p1 z|8ffMUrD?7MIC}C4rO`221<~;9)3&I>W)*du`yU0Ky-In8p<2SjLquE-4hG|*`eV@ZdG`+u@iY8hbEM8~#c@IlZ-lvmqozgXOxFHRN!ylljxDw`m*i>n{ zbq*)V_2fE`4}5bbw9`gb_GG&CYS8r*=rr^8$$(t{jtQJPz{u(Mt@j2Cu=ft)$ucZW z6Gnzy_JgpHYO?{|Ugyq5tr6&UW)OvE)r8YSlQ1`A@F(f_|Jr^%lu~NFm3G>FjbiaD zny4sI z>s#u$LuZb$z{r-OwpS`|e|gGrldsmwEIL5P`l}t_TJ0^sZ-3?xqAe0YEy4AVPrJa= zCP<&64YfZ834&AxZ}a~rEVBBix?kVBm3{)>k~e_Snm7L3=}TLG1R-Mm@46PnzsEq@6*^hnMyHA{$s&hC0yB= z!=A^Zv))19@bo61jHj3|c1m}GeFkBq_HMQ09@%v3JW7%vfu?EF?{|RZtRS6JnI{=a zAwjuvZ@6WoqEF?sjKew@P(+sP^$4$Me0B^L2!k9^Uc+?*2^2G-R1c3+`ndumj`YN- z=Az;qlBB!TM^1qM_-JvSC84%G{u!s4aK=ek}U)fp)Qu zGm=WeQC}A;{+b}bD8)Iehyqo%R+uZRasD{LiwVh_dP9%z(E|=cA(lo9x_-M?93i*0 zoc|!Hc~dUZL86jBR|w?Y@c+DY{0A=${iPl(BJPX+oCH8OoGG8RW**)OasqOv{x?+! z0YZPnE)ZzQze3$>x^?Y2N`_k0m?iJD?Z4 znNiyzcNHeKVu+l6&mzUmk3Ihd^>;^2+jpDX1)!MJ33w|j+2K9y?+mM(r~E#K{TsFC zr2-3=(4?pCW#^~M0;c0>y2 z+z2r%*%Mx-N6$soxaU52@Qi$%r+=(P6NN0=1Gdte@TW@Wcpx*p!o3KQK@X;F-QqbZ zuMw6B*E}fY6V;@K-xRvI*YO39f?jhS`$<3||4WF1o15WvUi%x%lDq{O!St1Q{n#^= zX?XMJW*vr1#pb{Z27{#jC?B~IC^+GQTXm={2$Z(}o0?p@2exy93m8?;(ts*Pv@hX% z6{ALbX?>Up$n<9w<6Q^X5EEDLtJNI67|cG#0=|Nw&<0<|o|t11#L1ug>#ie6^-uJ@yuDNyW%CS1TVR-4|XZNg7O!#gVCr)=G; zX%H9F5l)XPD_nc`7HXAmMW`Z)lar)2gK&7=9AtaJS*?Pm(+5HIi;-SwTTGPmgM5ww zs(a=?kZ$2u!Xo98OCmbIRrSSv{UZO&;kS!wUBdV(2epJ}`4nzwU_w+dkHm3161YH_ zY`YUk@9EiBEdL4|(64@NFWx^lM5w=Gaiko~(LADJ872|sA5;jdwe$O-czKqOYUjSf z44(m&&B}lTp9ma#YW;;CG_Z(LGA5?SsQp=2j|hHfS7|e|CHYr4VNK#{N0OSQJYb>h zZ_`f+9%M6NA@ZEtbz zq{n^ZajF%)5_&MG^DC`#eGS)sb;s;eq=ds7r_gQI)&l!7-HGLINnWI5xz^9EYviJ? zfGzaeSj*|q-u~0xb_#p7DfeFn)BA%);fw(Yq!@EWi~c3FlG`Q3UevN$)b#F|j4x`l z^E*H)*5#y={vaJl33lMylpUn-BkJzjI(sp3bEmzQjwp)Ltp4x_ALv7wNMde%#6!V` zFScirnf?Nu<8HFxO?}G&qPakN`Mh_{ojF0^F{{*gV~-M`Obh>;aOpo3lS%DV!fs~B zhyi#vwJZfx0kH3YIv)qf0N~p~{M`6QDa7@~O%;~6K4Hkq=5A@siDOPpRo^nWn>6!M zIET45^|I1Kih;UeUrMUh!M~;#9cvB8j)X~$OqCD>Dk^nyh#Ab)48^<}H-9y;Kwwj3 zN`HRGf`Vs+SKSE7aD9#mrmv6{_~y@)=^5szsWEp16_M^N?X-JKx6yf4-v!bvq8Cj$ zLNL^@1Xn`|?X_y)V){z~*ke29<0z=l!Dl99*nk@y48!Wm)rEou8#7XSV=FLqqbxCC zDQ3XZ_Rya1y?0wAJ}+}t=8`y&6kIyD}ou#8&D;N8C^^WH!(eK|wrS z*p9eJv7Cu%!1rol;Qen}GHK_*m%vLdx&D#{&=J8X_Pf(mn`mf%DKf#Wl2%`@WmJl= zUD`X7jIZYu_B0lK)z652PS%08-C*mN9oHhcl*j=|FgLbqu@zG;P?Nk05GvQQYF0Eo z#&>b;b8+kew~#Y>7BqZklH4m-Spq{>aWeUN#i^WMuoQAp^HPbA#nW*^t-~OYr3;`9 z1pnNzo4P|+N+HUf?}VMxVd)~6(p@QP9A)jcmKp=*n>)&{<)DJGFU^l?3b1XB_O6m6 zc{5I*@|LpbQ7y}b!)q3``WwEiZ5!&DRCdsK89O)0p8$2toL%}r!sGQlqWx~jM>lfJUD;<|B`s-<(9N@jePdkmD!ci~S?w`+PNE%iBQS-8vcD&qCq z{#R?)9+qUb^>wDEX)3GfqG{^PQ&Xp_mD8A7P}yXuWu;b*2o;^oxOqwO!lj$j*D1Bj zI5wh^lV)l{WTIeVX^Evmsetk-@_FC&* zd#&H@v-1SYWJZ#*@NqG=VLm^DqQ~8*Z1a}Xljh3!?|jJ3LSLl@20`(>Ty-x$p?YhxFdt@l^BfmS zG+SA1y#YS8?##J??%dew_>IK+4p|+NFFkn!b?F{30)r=F9X3ckcR?)T^jfSte$8+4 zx+J1@y>B>bljoq=FVmmf?i{^k`$FUNM4YE4eI&WM9Aax&!cu6iaIYPFZN4+6k3BcJ>pKdZ897_o(Z6|x&AjSkac{y9EEb?fabO}8h-c`?0iRjgj<;uoUT zcGxmsu>Zo@KF~JbF40!qw`Dwu_^6RQP&cBWwYm$QkLT7`ZuAyIZG-lZ>^p49Yqtq3 zb|PMM3aQ=SQ;5tbS2y7_8Q$T@JYJvjBLDQx@_G#^yIHrwNzIxZ1WprMp8@8>t#|q7 zCnrK;pyy(i>8~Cylj7IOw5MHsx~HFUI(2j2(b?Z6POHOa>g27yE>C7f?}3JAsk)}e z9?#4gUINv=W-a}R`I^8)-*9X`>ku#RiViA*65+<%Yi;@ap$jDUAQcqu;IX@L2nN;H z29M&D*u} z2li{@#tbPzjy{-b_gO8MswX{H#^tV)G=#b05pKcxt`@A*MdPn)^L@xOpp5Z!%3T~U z)0ZEvY*#%_))3Z#9Hgy#YSl32v%2UY>EY|w+Gv*6sX6*_+MZ(#DVBNGR_7c*`s2;# z75Kf!{NzYLTsZ^m!BpoGiuHOwD=Yl1f975KH@@&krlvn?bU|d+$|{1}e*UAXE{}An z9JzVO?U2>e$ob!#cTj%t+|Pl+me1S-NtSSIDJmbuatcVhj7e~7~uRpX6>fuQ4#z)++>^Jmlzt4M$82di*LF5Z*#p145q z<@M+pB?S<@b?|^i8xdm3iS&gcJE>Bs)i~G%MkZPO>=U*I9`!yq?Ob>4bL*kse=1hp zxgGlEaz(IhQ3$t{7k%o>>t&0s?Vfqv@w4S+cjjD|kJY+)ERtV&9VlD8`T^+k(@0O1 zRs14YtW0mWeu&0zzWO%e$R^GPcg)vK7d_5p=jD9EAhK=pvNmQMTXZpe)9z-tV@U;4 z!|m?Lh}?NP#iWv6QaV7V02Nf?6R!2PrSel*q{PYX6XMJ zCF*NSi@phE$|ULUF;w$YpLTDJqAqflM|Z9|cXzF$$33r|RkC5%@AJ=V zdicvj1$>-zcWPoam>$gMJvEo-x{0z~!}Byb)gB-~xU{U>=K99>%WVanC$=K$i0cz1 zwl8RJ=ex9)sh`uUF!nXdnjEa-12+7w1aZ2oo;7%B)&RNob(VJDw-{+O(&q-?`iUmgvn!<`2HU-50$f>cJzOhvmuvyDB4nP6az_z`wKnMWl3N z&53P-d+VAVh^KAB6MuJiqVYWG^(Ql%qG0%vt)%t}#2B6Z!*;XQ*`h@*5`$>g+j7VF zbD-E#UTZJsaVZZI-#|A)AD7uScQQf}w6Z046Q6}51faSt5>P&zl=YRnu^Y{LH)~J% zZd356AT+_x)l;$$`Z{mBDB!j~H(7RjS@bHMdR4za!O|32tz0G~;+c`IEJD-apNNv! zrru`&GHp>GFyl=f@lFi-2$vD-O%x}Wk(wVP5{}bQBjO#W1KN^ep9I_tts~a9F1s`b zZ?y03@#&Ve{$PYsiTTx^M>dSut>ABzQy8|jH#G~z8dTO>qllcWGhIjEVXT^yxKl-fqcyU0X#t)@>S@L zZ|8*)Gl5SFU_~|3%5(~7Pnz@sGI40>FJetn?k)tOC%%#Im+nhkJgOol;|9NGyNij+ z@|R1aj1A#O}L0}p-AGol^>@6=Tu{0#s0}40zYiN zbre~fi5Q8M(hdZorZK$~B1M-wa%^;9lPEQ*_WZ^lY}-A5mDsjv^oMn~B@X#${)_QO zY{@vO36z6+%9fp=V;(@kO!y$6#fjG>yO*~!Y*T_<=>;YqXup&l?dXo*v6bj8_4uN8 zpW+C@P0l=x-EY!d%MQ87FM606F^Pl?V_{T%810OZ^|(oY;G_NlBn!vhd=MCxFmgX2 zJgx!SnG^%u=q-4VgVO!s5~bTg{x0atRIk*_U#Y?NT|_%b9IWNMhvRVPNMr9i|BmvR z*PkXwPod6zq|C|pBliFCZ+sTW8hKm(AuOt;B}_)l1Ioc`zMTf!TRNp=*mql_!*!Fd>A#YiSnX>UAcJye7;ozbN+ zNqGhVkr!a%TgIHz5`Ov$`^iM5?pe5NvjeE!FWJ{aczn*jDZ~^VX{}3nC3*4l2?*QU}Jnr1! zJp3cQJ7&IWKuG~+`R8ezdcv~iYOfQ*XR&;`yT9x)Q`GEL-u z`Dlq~@KmaEkYm50G6am8XSBdpg>C)~YLF-vq=-JsU{+F*45k^YyYbLf!_R@yzWP?R zOeCb}ewH@j_Djt%h2JyDs+psMHX_){vPsg*mi8dt3fTJ?6(fc(O^DJ3j9LZcp(Ea&L)qfdHn(Xope8=fS!gLP{Q_l)zY( z8sioJK>Gc;hOnwlImH2}0+{i}>#)i!is`3HysMyfEYhLTfEve|rjdR(U~eZji+>w! zap&t#Hl((YYqqLcRGef>mb8?L%QLoNmj#AF&IRUMkBgTW7r?7zN`VKBrP8A?#>@6? zf;pe|;c1LY!5z3O^1dwISHxjxLYX=z7lb^GG0PM8a%qOvo0-qA^;4F15AQ`&yGqoU z4nZll3{2)#VK@o@2>pFvo-#r;q0Tt#D7zM%(fkon6AHIkx+0woCD+i9PU}S#&+YPt z1&}$-NatTrp)S;M*UoR)CSROa>44nnU5Wq1nKDy7{mKm8krK0JEE2C7V-ZZdD2n>M zAr%87?sJnl;T3%*qawXXc*!N@>=XS_BD+Il3+=2DXkY5@PF808sbiZp8RZd<5{_7^ zmm{vGF;*q2Pi<~87t!}94{~{HLTzmtOTsY<_ud4qtD;9Z$~o-M-h2Sy{&U&0BOqaqDWQE2NN8{I? zsmvOiZa~vfaJ@dPa4y|+R5y;4vu|qA@{@p3F0rv_gW}mJfdmn#iW-`(TIpDi-;mwAHe7yvae!596Xl5P7i!yR*x*<@G1skj)!Ll@YhmcG5tENtS9xn zeS-OK!tikO-IyBwio>u|QZbV(XukMG9VnqqZZWCCVD0c=vheq9qwE%du6mKriqVP=G`BH^|9H|8l-LQ!&~fP zrlq?zDSm(_#)@e}@$7bI&)=FAEc~3%#KrXHhw?r>f3={9>NiTG9;(!Sg|=z=2qNH5 z|E%_)uX~5l!y)73HfJD7vc- zQL}|Bv%E=bmrx%PN)Q zXp#c2%`HyKU#_9-(M)x<8tK0>O%G(|wL5q=6u1j$eD3D6nqbm?Z@!;XYBaYtx?G~o zZWT{T{KsceHxJN>T1Nb5sMF!dm0hWpq0`W1xGB#tj6yp1ppbBLp1@#BI<4*@$^FS*rDb)VK=97KuK- z&UjYI#$%M9B0q?`f|sRkVPWdHyBVUc+X0MaS0zcoAs&Oz;`iIRYTSBirlCk-W4Sew0tGCiG zpZUXN*;lQQiJvh7Cf9MCqg^2<+c^1h)+0<)Q_S)F;s}%bRJfGzN_n@wvDMjlv=Y^e z=?8Xjm9WpF89RDBajjQ}pZH4=89B<44T?V?%rYQ1dFJ6C|Ji!-5lp_-_^5@M!;S$6 zmAz1&r33T*MIC(n7X09+c9gVB=Lrub54MdShMPPahv4H7_-K_g%zI@n1)mte-SS0(yAiOY;WO_@0h3nMqZYUf4XeRmPa`z#094MI9L5KJkIL*&-l>rVurjgt8+c3ZT`>J09XFd?9+B@*WqT6dm@LUH6;U zSs&7b@@5ur>fP^8ontY1pamo3v)or}rZxuSE{whF{w1|D>Es!dGkNQCZ{?j-zTpk0 zubV|Vi#Nn|0FLWd;245ZVv_C69DW+NILciZ|AGt?)=D$a}gN8@R(cLPw`C%i%}&^u`xYXbo9<5-R!Fi^{9-SsU!0f6(L zPk%J+ZWwz2fVam0tPSnrPiZ$y)-Ry z{v{~7SeKt`wELEg6P-_5=f~JC!EtS=>$V-Opvrp$O*yfb@*Rerk8*P}zBHfpx+W%m z#jED$I?>(7`S$Z93BG*W4R4KaBT~pEtC~n@_AoL1E;`6XrbIFb$`qEb z$)khxevYY1a_$yE$62995p;kMXZE7Uq{IuJ1D?hOuXtbw9O#(INEJ`Lob{1s^Z>xT z_EdRYazRx%#_eND948FQ*t{>fr%2BLK+$-_bl{?7^sR&;S%TtLTW%O6695nc%B;v% zVC+ACs8l|Oavh^V_xk_~ko1VUP|C%)Q>+sW(LI5i&g}uKl|0xaFQPY zn0xry8?I}y$_Xop^s@$hBE~vhfzaX@(k0Z^-q;CpG=Z)QP?vl2$S4gx)?p>BnRnUDvMo_Yrv@hdC&IyZq_o zXyUf_gB_o;h&eHgq)f&;jA2c&DbyBT#nd4bkC)=$nCFCPKsDi;Yz!q$|0FJn`r}2J z#I8S91wZ>Ra35muSaF;lTZyQ8UPEM7y99L`@JBPtHw2bgen|W(y<__G{x<#b83fx^ z20AxpvwvuKJWS6ZB@ zpd5AXwM#o9IA>GSNNTA%Jk_@>V>5fwAo!&Cd^#!nz^Yk=`}yaJ{5p!#;%1vn@2*2s z)5gp0mun1b&d-$>{hOKy`8=yhjv}#A_8HBKTa&e0%I*BCN&oNEQx^H)~Lt zr8}xlq~Tv*+m|gYx%B=`N$rd{MKc`9GLwT}WE&_iXUV(pjCDzW(uqL4LkdXlk_Imy z!MKvfY(F2I7Ys*X#qw#=NySgB7HT3<(e9O&iGO7Hqh6EB_?l*;E|&@hT zvtV@Yc7evgW5a6W?*NVMsN_kv84LmIFWU(g%{?mTQFb7l@8%S-Gn}P zum7prb==}68X?4uGvg207pp$=P7e2Q@C9SbT^&LX(>V%RQwp(4rfCT(+lweDxxH?k zoMn6!0wXs=A<5T+?f8OxFA~;=$tQnQC$F$v$>xOkmfoS)N#SR6*p{6z8s{F}cFZ%zCTXF5O>FBIT9P^Us@ue? zqpq@>u9z;GlfH5?os7QRVMLGVT|hI}Ftqa}z673$+1~$7pvgUsVDuVSakAW*8gF0e zl2P@}opL+w%2ZhU`fYxs58;06L0w%t{jRAhGLo5Fk@l_2whx_gvf+em8UimirRLrb z|MQ}+c||aP=n>a>@Kr}wVUXiHr@eBiR04OT34a^Wso(E&%FC(~5WrVl7)6y8wNIfK z001lTzZ785regpg{v10GKx_{L1%!;yL1+NxY+wd}zQ#N!z8<*-aOSt_4J9UdM7gqF z(`~5^&IXAdc^6Kc>C>|HCGb=&ek7eud7cCYSCPM+{-!VZ@F^_*&NE1OFL;sbXy z85zkgClv3Asz-c?$!d9Cdw6+&*UadpcY8J5)&QW8n#|sRMftH-Nn-5_f+$Zp?OV2bpxsR{e5o*wfg25=P_=j}A9MyM>?x>3G`fHN$a~+6dcC*o63v zSncZy9xbP9VyIX=4ZkTDL}alVue3q*v(&M}z@ZrG5}5C*o2+(9Oa5Ng}zuJ)TEQD`u#6Z{4V_H{#3rPxCY;>Bx7j73?Vlz>+sl|5lJ`I^Ua!X zXq3klh(M|kUvFsntr@v0BeFBW`fJm6+6>*jWGd?BrE`>l!Mu17MBpNiBV>AgwMgjv zi`RS%7DJ{CVn6`5815mM^XAQ)gz@Qz;63v(_Nvl(0lcX7vO*z3tM~rJ-mjYAV3$Mz zm|PX_=)vpaV_7PUFM*(KBNDjWTur~udOhT1y=Jh6sgm6ziE_9=avH2kZtWEnl^_~4P+AZY!$xIQ#7HDA z(CVRE?s#)xL*0>@|Ndj~fP-((d{|fkf>^HPMp<8Xtd{s(OrvaFLxXj)zHmqLPN6-3 zn+lmNMTOzzsX>Pwtwo1z3F4Q9>1kUv6 zA8%T=g{?;&L^3Xsl*&)(V33CaJ^ep3N0I|l60n=&+?K2*UGnos)MhF+f+p@O zjQ^9oSZ;hm#YlBombdP<3hzqZA&7vE_ZAM1&0=&l$wyX^(E zGW{mF$tt)l941mTG&ZI;6LeTYr0?vwszZB?&M5bvb zz2^Dr!wImIG7CqD%A592&Rbg=20Hw{!na*O*uY1E;CeCQ!|_iK505JG_A5bN2DBX4PToH$g7S>Xs#l1^8KY|mR!lbgL!&* zf(ij#<%$QM6c2SIsSv_Jas}CTHs$tb5mU7g#PBIB^&2p;qFT18+W439@1CNqYTa{B zV8>V(w8E*su+DR7Xl1wv@6CD&#LB4E?eCv|tQ6&>2X7Dr#VbQYY5b^2Wa;jTTpiRC zEokyTAeR|RQ1?UB>{F}`)N`>Xx3Ex}d_?TWA6gO?7$7un;velz57p{3k@hM!kv^9Y~`-bGJs;(A{d@gZ-UEq9YgNt0Hc38;3!kape-!z7i9RR1C z=LJhCk+wgxxvY+0D;>Id1%-wGsALFlE-HHA*qaW!D`I8>jZ@!cLV9_nrWrS3C2>yK zzF%y1H>R7c5oKpiLs&d1j53?{UAo{m8_Kv`(XW|j*B+ZT{_<$CtfC@mvu;TQ+3*xy zPwczi`vM3(WX*YPh_0WHy}pbs$~K>Lr9u&OQ4Y=QvxmRqvb)f^*v|sC700>^7h>0# z31F!kq`4@CqdR*ALyBFZh_2%@LU&4WuqI@~R_L_%QLxloo4Uj&4I3(c>+jovhK849 zaEDtTW~KtPo^58c=X~5Sm#O-LCttc9GLA+!tHx~eYG#5mRNSU-_4f8sENophbbX6^iTzq`ml>;m zgMbKw&Kqd7U%Ixg^>dcallb9v8qeu`Ccsx;UpumRSQ%(F=Vr)D>X?DLAXMsnZtr$# z^#WvX2>q~>M4%JfGeF0iTQ`CQ66m~C|N+FUMQrYhAt=^?vUn)wPV%0#xl?g~sjWm{Qoe*s?n z>!W|D-*s^0z}p2i>2aK7>z+RqwHU^gn<9^*^*A00E!~4Q><`?r&cIh+p$c5%r_*hz z>k>OphukT9aMAyn%B!iUnH$5?9wCR5qAQd4&X5nCYn?P>y!y;$TyOJDz4(C-&WCG> zD*inj7~Rgyt3N~odD?`62z0md)=kN(Lk$_alSRXI^K#<;c@^s4wWrmyD&PKc2m%af zS79Y<4yaPMV_oj%E?<*qImzfdtbBPbU{1^{kB97%7t$U zXEcWIriC6%`zsjdXl5<;q}jzfczKP$ji~lfoQ|4+DwK}oRo`9vdh%+q%XqoNsu~TR zoFwo{f3-`lET1Ylsik#`f_}u_YjTucm=vTl+GVLPOV>OF9`vVirfS0FrXS`+jvtT4 zN(;V!e-Lb}!Onwgb)AB z(eSUXn@UO>$u~%Hrsi&BYAV_vDyDh5jL$I(yQYq2VN)2%~iLB2(am4ls=K3-~7kKT=wZW znadpKehg{5MWS8Uj2p4x+47GoUcBZd?~byNnOh%{>mv!0$6B=w1DhSV$1@iph?O@& z;hIOt=%XVCm*1xDwELY0XH>f%BsK0c%%0U=co&}i?GwBL#2gN{f7tm^zmG4Lq_*7s zb_oG5&y>BM2b`>t$BCp1+O}_5H=9)C)Bg>?xlddn8ns4e8cHe3=eD=Ej|e%!n3SazFR9L(^L4*inF6wo4do5o1IZ8i!k;#06}yXxp>DwOfF2Cw5$nk0sUHYuppVZ$jz5~P<&rQPu=KT!Tg9yVgunVh=7nFi$qU7w!9vg2kwGQT zsCTW9p+UVLgWhNnid7U4XwVOE>nNZ2k`l_uwvt5$_~;YgIdHN=$i5YQo|U`{F}Hvw zDocP%vcMS!?1=l5on@>v05N8j^4pqDH31}^!EKB}mJ;?7kX}3f3O)J;yX0OdhMnHP d7ex`Rx!VN%@CQQ?^|Bjapko3qy>UP6zW`TL3=;qV literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/sort.png b/OpenRefine/docs/static/img/sort.png new file mode 100644 index 0000000000000000000000000000000000000000..a793da81d18119e8bd847971ff797ec37f2cf446 GIT binary patch literal 10893 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 EAN-3w^8f$< literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/sort2.png b/OpenRefine/docs/static/img/sort2.png new file mode 100644 index 0000000000000000000000000000000000000000..200dc45b6ec548290db73b8dd1172df87f4cf1f7 GIT binary patch literal 62508 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�qMup0Aa|FxH5Gz0H5Jkm5-;xA!qYb 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 Q0Q^(Ft|ng~Yx?ki0k1F?*#H0l literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/sortPermanent.png b/OpenRefine/docs/static/img/sortPermanent.png new file mode 100644 index 0000000000000000000000000000000000000000..142e96ffb3b176fc8ede78cb7b8ea787d66d8424 GIT binary patch literal 23003 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/sql-exporter.png b/OpenRefine/docs/static/img/sql-exporter.png new file mode 100644 index 0000000000000000000000000000000000000000..f5cb98f3c426af2460d4e6822b03e45fa196412f GIT binary patch literal 30379 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/sql-exporter2.png b/OpenRefine/docs/static/img/sql-exporter2.png new file mode 100644 index 0000000000000000000000000000000000000000..1f23784e831d532af6850379b736e063fe677002 GIT binary patch literal 11149 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 G>E8ek3jhoN literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/templating-exporter.png b/OpenRefine/docs/static/img/templating-exporter.png new file mode 100644 index 0000000000000000000000000000000000000000..836e47d6873edbfc863bdb9e4d0fc2c8e5af3d32 GIT binary patch literal 43498 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/timelinefacet.png b/OpenRefine/docs/static/img/timelinefacet.png new file mode 100644 index 0000000000000000000000000000000000000000..9c00582437c0fea36d8ecd589403284870c68f2d GIT binary patch literal 4290 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 %QbXx|$=giLMu>cl_Q8xB*dsR&%sczR z9-za?Bp|hWf;7=AVvV!lA|^i%?EFC{rXYT43G25oN>@eA7U=mJJxMxKhMpItK zrk`Jp05V4vcQitZ{`!tao34)H?#7-b_)*dN>&n{`S`-WA|HBP>7*uiz<8lsRGa+|HX%N$p#x12u#x>Ot zW3uHkZHdYlG{fwOVcZ%T<8F`6-e*7OJm);;pYuHDkM*th{odd2UEh28*7IT<9c(4U zd{ustBU7{xvOE~RV99;Lk7&aG1&*^3IweFGm@k8#tfo8YL)_WQjR}WLR z{GE+78djqNcw-S`>oLw-jbxMHxUpk8*&OQg&JUSq>JvVNu5x>>@HS*Kj+^pQn#@bZ z&`{h3<~#L)s^$p}#bx6_Vrz`w*1gFadl+7Y#m~@vhGX14u;-u8uQzA8Q)L(Tg=A+9 z|8m_zu_3H;kYS@x+nKZKusTuEbC{R29vbf+Y2U$Xj+R%DRcS$?dI!k9ORv!jkH{mOy$26e+X z$~~k5YO~`kmVaeY&Ku%r@pZ7!FRK9{jh|p>w0tV;xcKTqmM{B;mM*D>{S@6yDN4-XYfAxCHJ-}1umN>KC{8Tu?wZ_Tc zt2AvXvGOpoc^XuLw9kN8KKP&?C4*BVOFRQmZZjC31T z?PL0nE9Zfwv+GVIVxXnR%#-%U(L@m+dZK#&-50}WRaC>i(tI5$cqh^q2 z@Ufh$y+MiYWi{nd%KVM)6?dnx0}^Y;3;5`^ZHx!$2>;# zq>Z#umTd7%?*QN0$YU@nzh!C9@RMKa_UI-r@gq16T2lnpZi$Bc_lv{YA8pw9BQMkF zD-Y)lBZB|AND1N9eh|f@VL!G!3ka4IJsXuS-cx<&F~; zlA9WFa|h@TQ4vvn@PC3CUjaQ^5-C=pPAC_&lOTgyT}tUGdAYEtJ1#47QwJXwIPbw- zBMPE0J`eIRliV??+s&YS{ffrxzk`)k##y#2TN4^Ynp{8A5(_!~-MEwpPF^1&W@lq! zeU)G%aDa1?bb=D4QwaC{a;+eUpmwOH#({rSHx_nK`ojj$!Wg7A2sk&P-QGWBNxN~n* z)^2aH^7%m7W~HvE4u-|YUV|IqFXH&@g{HlN<{GRZ06_h}X>O<{@LK-Q8$kOUGcgk5 z&&`I{G86NRqc}YmW_?#VH6MCquEeuE|2BdC+LgdBkBl!xUn9Yh``I(RA>~E!#tTg9 zT=7JKE7hxIX1!{%l5A&Dh@SE)#I(IxdOtfxqJB6ReJ9b|14|>+iBPb}`8qpq;vuVx z!>+4CJBl~k7SCLEcp{Am>iP<+8R<}bzm2YMt?$J36?q@Q(sE5Ksug)XGq=lQ8zMe? znT2K9N5S2q?Syk{3#8qW*p*n*M-9Jk@$FDT!P%-~Carc* zA_kRoJj`MaCd1H53Yh;ES)a^nHPqC$sHcMnT1ef}2TkX5j4m6>8D`;{8?sA@>DvFk!vDv1P;ANE8@UolrzO;{S?@nd#_gDGaf`p;RO>g0G@QPuCesK_8Vo%Wsv{? literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/visual-test-cypress-failure.png b/OpenRefine/docs/static/img/visual-test-cypress-failure.png new file mode 100644 index 0000000000000000000000000000000000000000..7f3f90048a114b48d1cf4b7b43187a53f48f0a0e GIT binary patch literal 68003 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/wikidata-login.png b/OpenRefine/docs/static/img/wikidata-login.png new file mode 100644 index 0000000000000000000000000000000000000000..836fdcfb0ab35995c29dc2fba56748cf129b79dd GIT binary patch literal 11745 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/wikidata-schema.png b/OpenRefine/docs/static/img/wikidata-schema.png new file mode 100644 index 0000000000000000000000000000000000000000..d8c7c22b827f6799a5dde32f356bd3b16ed889a4 GIT binary patch literal 39416 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

OX(!7jMvuK;|SDf4#x{yu{437Py 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 VKxbZBI5d28b@YBgYhAege*m$>i2eWo literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/wikidata-terms.png b/OpenRefine/docs/static/img/wikidata-terms.png new file mode 100644 index 0000000000000000000000000000000000000000..8327242ae7e0663f8b81b5447885bc749ef1fdbc GIT binary patch literal 24677 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 G;lBU{TV+K6 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/wikidata-terms2.png b/OpenRefine/docs/static/img/wikidata-terms2.png new file mode 100644 index 0000000000000000000000000000000000000000..fbe7d3286e10fdd66b0dcda3be3791d72401ea92 GIT binary patch literal 7336 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/docs/static/img/yeardata.png b/OpenRefine/docs/static/img/yeardata.png new file mode 100644 index 0000000000000000000000000000000000000000..8250d4036172dfafc7004d526741cfdc57ff6c64 GIT binary patch literal 21833 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 + +This user manual starts with instructions for [installing or upgrading OpenRefine on Windows, Mac, and Linux computers](manual/installing). It then walks you through [the interface and how to run OpenRefine](manual/running#jvm-preferences) from a program or command line, with or without setting custom preferences and modifications. + +The manual then teaches you how to [start a project](manual/starting) by importing an existing dataset. We work through how to [view and learn about your data](manual/exploring) using facets, filters, and sorting. + +Then we launch into [transforming that data permanently](manual/transforming) through common and custom transformations, clustering, pulling data from the web, [reconciling](manual/reconciling), and [writing expressions](manual/expressions). + +Finally we discuss what to do with your improved dataset, whether [exporting](manual/exporting) it to a file or uploading statements to Wikidata. + +If you're stuck on any aspect and can't find an answer in the manual, try the [Troubleshooting page](manual/troubleshooting) for links to various places to find help. + +If you are new and want to learn how to use OpenRefine using an example dataset, you may wish to start with a user-contributed tutorial from our [recommendations list](https://github.com/OpenRefine/OpenRefine/wiki/External-Resources). diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/cellediting.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/cellediting.md new file mode 100644 index 000000000..2c2b4f654 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/cellediting.md @@ -0,0 +1,165 @@ +--- +id: cellediting +title: Cell editing +sidebar_label: Cell editing +--- +## Overview {#overview} + +OpenRefine offers a number of features to edit and improve the contents of cells automatically and efficiently. + +One way of doing this is editing through a [text facet](facets#text-facet). Once you have created a facet on a column, hover over the displayed results in the sidebar. Click on the small “edit†button that appears to the right of the facet, and type in a new value. This will apply to all the cells in the facet. + +You can apply a text facet on numbers, boolean values, and dates, but if you edit a value it will be converted into the text [data type](exploring#data-types) (regardless of whether you edit a date into another correctly-formatted date, or a “true†value into “falseâ€, etc.). + +## Transform {#transform} + +Select Edit cells → Transform... to open up an expressions window. From here, you can apply [expressions](expressions) to your data. The simplest examples are GREL functions such as [`toUppercase()`](grelfunctions#touppercases) or [`toLowercase()`](grelfunctions#tolowercases), used in expressions as `toUppercase(value)` or `toLowercase(value)`. When used on a column operation, `value` is the information in each cell in the selected column. + +Use the preview to ensure your data is being transformed correctly. + +You can also switch to the Undo / Redo tab inside the expressions window to reuse expressions you’ve already attempted in this project, whether they have been undone or not. + +OpenRefine offers you some frequently-used transformations in the next menu option, Common transforms. For more custom transforms, read up on [expressions](expressions). + +## Common transforms {#common-transforms} + +### Trim leading and trailing whitespace {#trim-leading-and-trailing-whitespace} + +Often cell contents that should be identical, and look identical, are different because of space or line-break characters that are invisible to users. This function will get rid of any characters that sit before or after visible text characters. + +### Collapse consecutive whitespace {#collapse-consecutive-whitespace} + +You may find that some text cells contain what look like spaces but are actually tabs, or contain multiple spaces in a row. This function will remove all space characters that sit in sequence and replace them with a single space. + +### Unescape HTML {#unescape-html} + +Your data may come from an HTML-formatted source that expresses some characters through references (such as “&nbsp;†for a space, or “%u0107†for a ć) instead of the actual Unicode characters. You can use the “unescape HTML entities†transform to look for these codes and replace them with the characters they represent. For other formatting that needs to be escaped, try a custom transformation with [`escape()`](grelfunctions#escapes-s-mode). + +### Replace smart quotes with ASCII {#replace-smart-quotes-with-ascii} + +Smart quotes (or curly quotes) recognize whether they come at the beginning or end of a string, and will generate an “open†quote (“) and a “close†quote (â€). These characters are not ASCII-compliant (though they are UTF8-compliant) so you can use this tranform to replace them with a straight double quote character (") instead. + +### Case transforms {#case-transforms} + +You can transform an entire column of text into UPPERCASE, lowercase, or Title Case using these three options. This can be useful if you are planning to do textual analysis and wish to avoid case-sensitivity (which some functions are) causing problems in your analysis. Consider also using a [custom facet](facets#custom-text-facet) to temporarily modify cases instead of this permanent operation if appropriate. + +### Data-type transforms {#data-type-transforms} + +As detailed in [Data types](exploring#data-types), OpenRefine recognizes different data types: string, number, boolean, and date. When you use these transforms, OpenRefine will check to see if the given values can be converted, then both transform the data in the cells (such as “3†as a text string to “3†as a number) and convert the data type on each successfully transformed cell. Cells that cannot be transformed will output the original value and maintain their original data type. + +:::caution +Be aware that dates may require manual intervention to transform successfully: see the section on [Dates](exploring#dates) for more information. +::: + +Because these common transforms do not offer the ability to output an error instead of the original cell contents, be careful to look for unconverted and untransformed values. You will see a yellow alert at the top of screen that will tell you how many cells were converted - if this number does not match your current row set, you will need to look for and manually correct the remaining cells. Also consider faceting by data type, with the GREL function [`type()`](grelfunctions#typeo). + +You can also convert cells into null values or empty strings. This can be useful if you wish to, for example, erase duplicates that you have identified and are analyzing as a subset. + +## Fill down and blank down {#fill-down-and-blank-down} + +Fill down and blank down are two functions most frequently used when encountering data organized into [records](exploring#row-types-rows-vs-records) - that is, multiple rows associated with one specific entity. + +If you receive information in rows mode and want to convert it to records mode, the easiest way is to sort your first column by the value that you want to use as a unique records key, [make that sorting permanent](transforming#edit-rows), then blank down all the duplicates in that column. OpenRefine will retain the first unique value and erase the rest. Then you can switch from “Show as rows†to “Show as records†and OpenRefine will associate rows to each other based on the remaining values in the first column. + +Be careful that your data is sorted properly before you begin blanking down - not just the first column but other columns you may want to have in a certain order. For example, you may have multiple identical entries in the first column, one with a value in the second column and one with an empty cell in the second column. In this case you want the row with the second-column value to come first, so that you can clean up empty rows later, once you blank down. + +If, conversely, you’ve received data with empty cells because it was already in something akin to records mode, you can fill down information to the rest of the rows. This will duplicate whatever value exists in the topmost cell with a value: if the first row in the record is blank, it will take information from the next cell, or the cell after that, until it finds a value. The blank cells above this will remain blank. + +## Split multi-valued cells {#split-multi-valued-cells} + +Splitting cells with more than one value in them is a common way to get your data from single rows into [multi-row records](exploring#rows-vs-records). Survey data, for example, frequently allows respondents to “Select all that apply,†or an inventory list might have items filed under more than one category. + +You can split a column based on any character or series of characters you input, such as a semi-colon (;) or a slash (/). The default is a comma. Splitting based on a separator will remove the separator characters, so you may wish to include a space with your separator (; ) if it exists in your data. + +You can use [expressions](expressions) to design the point at which a cell should split itself into two or more rows. This can be used to identify special characters or create more advanced evaluations. You can split on a line-break by entering `\n` and checking the “[regular expression](expressions#regular-expressions)†checkbox. + +Regular expressions can be useful if the split is not straightforward: say, if a capital letter (`[A-Z]`) indicates the beginning of a new string, or if you need to _not_ always split on a character that appears in both the strings and as a separator. Remember that this will remove all the matching characters. + +You can also split based on the lengths of the strings you expect to find. This can be useful if you have predictable data in the cells: for example, a 10-digit phone number, followed by a space, followed by another 10-digit phone number. Any characters past the explicit length you’ve specified will be discarded: if you split by “11, 10†any characters that may come after the 21st character will disappear. If some cells only have one phone number, you will end up with blank rows. + +If you have data that should be split into multiple columns instead of multiple rows, see [Split into several columns](columnediting#split-into-several-columns). + +## Join multi-valued cells {#join-multi-valued-cells} + +Joining will reverse the “split multi-valued cells†operation, or join up information from multiple rows into one row. All the strings will be compressed into the topmost cell in the record, in the order they appear. A window will appear where you can set the separator; the default is a comma and a space (, ). This separator is optional. We suggest the separator | as a sufficiently rare character. + +## Cluster and edit {#cluster-and-edit} + +Creating a facet on a column is a great way to look for inconsistencies in your data; clustering is a great way to fix those inconsistencies. Clustering uses a variety of comparison methods to find text entries that are similar but not exact, then shares those results with you so that you can merge the cells that should match. Where editing a single cell or text facet at a time can be time-consuming and difficult, clustering is quick and streamlined. + +Clustering always requires the user to approve each suggested edit - it will display values it thinks are variations on the same thing, and you can select which version to keep and apply across all the matching cells (or type in your own version). + +OpenRefine will do a number of cleanup operations behind the scenes in order to do its analysis, but only the merges you approve will modify your data. Understanding those different behind-the-scenes cleanups can help you choose which clustering method will be more accurate and effective. + +You can start the process in two ways: using the dropdown menu on your column, select Edit cells → Cluster and edit…; or create a text facet and then press the “Cluster†button that appears in the facet box. + +![A screenshot of the Clustering window.](/img/cluster.png) + +The clustering pop-up window will take a small amount of time to analyze your column, and then make some suggestions based on the clustering method currently active. + +For each cluster identified, you can pick one of the existing values to apply to all cells, or manually type in a new value in the text box. And, of course, you can choose not to cluster them at all. OpenRefine will keep analyzing every time you make a change, with Merge selected & re-cluster, and you can work through all the methods this way. + +You can also export the currently identified clusters as a JSON file, or close the window with or without applying your changes. You can also use the histograms on the right to narrow down to, for example, clusters with lots of matching rows, or clusters of long or short values. + +### Clustering methods {#clustering-methods} + +You don’t need to understand the details behind each clustering method to apply them successfully to your data. The order in which these methods are presented in the interface and on this page is the order we recommend - starting with the most strict rules and moving to the most lax, which require more human supervision to apply correctly. + +The clustering pop-up window offers you a variety of clustering methods: + +* key collision + * fingerprint + * ngram-fingerprint + * metaphone3 + * cologne-phonetic + * Daitch-Mokotoff + * Beider-Morse +* nearest neighbor + * levenshtein + * ppm + +#### Key collision {#key-collision} + +**Key collisions** are very fast and can process millions of cells in seconds: + +**Fingerprinting** is the least likely to produce false positives, so it’s a good place to start. It does the same kind of data-cleaning behind the scenes that you might think to do manually: fix whitespace into single spaces, put all uppercase letters into lowercase, discard punctuation, remove diacritics (e.g. accents) from characters, split up all strings (words) and sort them alphabetically (so “Zhenyi, Wang†becomes “wang zhenyiâ€). + +**N-gram fingerprinting** allows you to set the _n_ value to whatever number you’d like, and will create n-grams of _n_ size (after doing some cleaning), alphabetize them, then join them back together into a fingerprint. For example, a 1-gram fingerprint will simply organize all the letters in the cell into alphabetical order - by creating segments one character in length. A 2-gram fingerprint will find all the two-character segments, remove duplicates, alphabetize them, and join them back together (for example, “banana†generates “ba an na an na,†which becomes “anbanaâ€). + +This can help match cells that have typos, or incorrect spaces (such as matching “lookout†and “look out,†which fingerprinting itself won’t identify because it separates words). The higher the _n_ value, the fewer clusters will be identified. With 1-grams, keep an eye out for mismatched values that are near-anagrams of each other (such as “Wellington†and “Elgin Townâ€). + +##### Phonetic clustering {#phonetic-clustering} + +The next four methods are phonetic algorithms: they identify letters that sound the same when pronounced out loud, and assess text values based on that (such as knowing that a word with an “S†might be a mistype of a word with a “Zâ€). They are great for spotting mistakes made by not knowing the spelling of a word or name after hearing it spoken aloud. + +**Metaphone3 fingerprinting** is an English-language phonetic algorithm. For example, “Reuben Gevorkiantz†and “Ruben Gevorkyants†share the same phonetic fingerprint in English. + +**Cologne fingerprinting** is another phonetic algorithm, but for German pronunciation. + +**Daitch-Mokotoff** is a phonetic algorithm for Slavic and Yiddish words, especially names. **Baider-Morse** is a version of Daitch-Mokotoff that is slightly more strict. + +Regardless of the language of your data, applying each of them might find different potential matches: for example, Metaphone clusters “Cornwall†and “Corn Hill†and “Green Hill,†while Cologne clusters “Greenvale†and “Granville†and “Cornwall†and “Green Wall.†+ +#### Nearest neighbor {#nearest-neighbor} + +**Nearest neighbor** clustering methods are slower than key collision methods. They allow the user to set a radius - a threshold for matching or not matching. OpenRefine uses a “blocking†method first, which sorts values based on whether they have a certain amount of similarity (the default is “6†for a six-character string of identical characters) and then runs the nearest-neighbor operations on those sorted groups. + +We recommend setting the block number to at least 3, and then increasing it if you need to be more strict (for example, if every value with “river†is being matched, you should increase it to 6 or more). Note that bigger block values will take much longer to process, while smaller blocks may miss matches. Increasing the radius will make the matches more lax, as bigger differences will be clustered. + +**Levenshtein distance** counts the number of edits required to make one value perfectly match another. As in the key collision methods above, it will do things like change uppercase to lowercase, fix whitespace, change special characters, etc. Each character that gets changed counts as 1 “distance.†“New York†and “newyork†have an edit distance value of 3 (“N†to “nâ€; “Y†to “yâ€; remove the space). It can do relatively advanced edits, such as understand the distance between “M. Makeba†and “Miriam Makeba†(5), but it may create false positives if these distances are greater than other, simpler transformations (such as the one-character distance to “B. Makeba,†another person entirely). + +**PPM (Prediction by Partial Matching)** uses compression to see whether two values are similar or different. In practice, this method is very lax even for small radius values and tends to generate many false positives, but because it operates at a sub-character level it is capable of finding substructures that are not easily identifiable by distances that work at the character level. So it should be used as a “last resort†clustering method. It is also more effective on longer strings than on shorter ones. + +For more of the theory behind clustering, see [Clustering In Depth](https://github.com/OpenRefine/OpenRefine/wiki/Clustering-In-Depth). + +## Replace {#replace} + +OpenRefine provides a find/replace function for you to edit your data. Selecting Edit cells → Replace will bring up a simple window where you can input a string to search and a string to replace it with. You can set case-sensitivity, and set it to only select whole words, defined by a string with spaces or punctuation around it (to prevent, for example, “house†selecting the “house†part of “doghouseâ€). You can use [regular expressions](expressions#regular-expressions) in this field. You may wish to preview the results of this operation by testing it with a [Text filter](facets#text-filter) first. + +You can also perform a sort of find/replace operation by editing one cell, and selecting “apply to all identical cells.†+ +## Edit one cell at a time {#edit-one-cell-at-a-time} + +You can edit individual cells by hovering your mouse over that cell. You should see a tiny blue link labeled “edit.†Click it to edit the cell. That pops up a window with a bigger text field for you to edit. You can change the [data type](exploring#data-types) of that cell, and you can apply these changes to all identical cells (in the same column), using this pop-up window. + +You will likely want to avoid doing this except in rare cases - the more efficient means of improving your data will be through automated and bulk operations. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/columnediting.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/columnediting.md new file mode 100644 index 000000000..754a61c62 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/columnediting.md @@ -0,0 +1,124 @@ +--- +id: columnediting +title: Column editing +sidebar_label: Column editing +--- + +## Overview {#overview} + +Column editing contains some of the most powerful data-improvement methods in OpenRefine. The operations in the Edit column menu involve using one column of data to add entirely new columns and fields to your dataset. + +## Splitting or joining {#splitting-or-joining} + +Many users find that they frequently need to make their data more granular: for example, splitting a “Firstname Lastname†column into two columns, one for first names and one for last names. The reverse is also often true: you may have several columns of category values that you want to join into one “category†column. +. +### Split into several columns {#split-into-several-columns} + +![A screenshot of the settings window for splitting columns.](/img/columnsplit.png) + +You can find this operation at Edit column → Split into several columns.... Splitting one column into several columns requires you to identify the character, string lengths, or evaluating expression you want to split on. Just like [splitting multi-valued cells into rows](cellediting#split-multi-valued-cells), splitting cells into multiple columns will remove the separator character or string you indicate. Splitting by lengths will discard any information that comes after the specified total length. + +You can also specify a maximum number of new columns to be made: separator characters after this limit will be ignored, and the remaining characters will end up in the last column. + +New columns will be named after the original column, with a number: “Location 1,†“Location 2,†etc. You can choose to remove the original column with this operation, and you can have [data types](exploring#data-types) identified where possible. This function will work best with converting strings to numbers, and may not work with [dates](exploring#dates). + +### Join columns {#join-columns} + +![A screenshot of the settings window for joining columns.](/img/columnjoin.png) + +You can join columns by selecting Edit column → Join columns.... All the columns currently in your dataset will appear in the pop-up window. You can select or un-select all the columns you want to join, and drag columns to put them in the order you want to join them in. You will define a separator character (optional) and define a string to insert into empty cells (nulls). + +The joined data will appear in the column you originally selected, or you can create a new column for this content and specify a name. You can delete all the columns that were used in this join operation. + +## Add column based on this column {#add-column-based-on-this-column} + +Selecting Edit column → Add column based on this column... will open up an [expressions](expressions) window where you can transform the data from this column (using `value`), or write a more complex expression that takes information from any number of columns or from external sources. + +Expressions used in this operation will rely on your knowledge of variables. You can learn more in the [Expressions section on variables](expressions#variables). + +The simplest way to use this operation is simply leave the default `value` in the expression field, to create an exact copy of your column. For a column of [reconciled data](reconciling), you can use the variable `cell` instead, to copy both the original string and the existing reconciliation data. This will include matched values, candidates, and new items. + +One useful expression is to create a column based on concatenating (merging) two other columns. Select either of the source columns, choose Edit column → Add column based on this column..., name your new column, and use the following format in the expression window: + +``` +cells["Column 1"].value + cells["Column 2"].value +``` + +If your column names do not contain spaces, you can use the following format instead: + +``` +cells.Column1.value + cells.Column2.value +``` + +If you are in records mode instead of rows mode, you can concatenate using the following format: + +``` +row.record.cells.Column1.value + row.record.cells.Column2.value +``` + +You may wish to add separators or spaces, or modify your input during this operation with more advanced expressions. + +## Add column by fetching URLs {#add-column-by-fetching-urls} + +Through the Add column by fetching URLs function, OpenRefine supports the ability to fetch HTML or data from web pages or services. In this operation you will be building URL strings based on your column of data, by using `value` to insert a relevant substring. Your chosen column needs to contains parts of paths to valid HTML pages or files online. + +If you have a column of URLs and want to fetch the information that they point to, you can simply run the expression as `value`. If your column has, for example, unique identifiers for Wikidata entities (numerical values starting with Q), you can download the JSON-formatted metadata about each entity with + +``` +"https://www.wikidata.org/wiki/Special:EntityData/" + value + ".json" +``` + +or whatever metadata format you prefer. Information about the format options in Wikidata can be found [here](https://www.wikidata.org/wiki/Wikidata:Data_access). The service you are fetching data from may have similar documentation on its provided options. + +![A screenshot of the settings window for fetching URLs.](/img/fetchingURLs.png) + +This service is more useful when getting metadata files instead of HTML, but you may wish to work with a page’s entire HTML contents and then parse out information from that. + +:::caution +Be aware that the fetching process can take quite some time and that servers may not want to fulfill hundreds or thousands of page requests in seconds. Fetching allows you to set a “throttle delay†which determines the amount of time between requests. The default is 5 seconds per row in your dataset (5000 milliseconds). We recommend leaving this at 1000 or greater. +::: + +Note the following: +* Before pressing “OK,†copy and paste a URL or two from the preview and test them in another browser tab to make sure they work. +* In some situations you may need to set [HTTP request headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers). To set these, click the small “Show†button next to “HTTP headers to be used when fetching URLs†in the settings window. The authorization credentials get logged in your operation history in plain text, which may be a security concern for you. You can set the following request headers: + * [User-Agent](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) + * [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) + * [Authorization](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) + +### Common errors {#common-errors} + +When OpenRefine attempts to fetch information from a web service, it can fail in a variety of ways. The following information is meant to help troubleshoot and fix problems encountered when using this function. + +First, make sure that your fetching operation is storing errors (check “store errorâ€). Then run the fetch and look at the error messages. + +**“HTTP error 403 : Forbiddenâ€** can be simply down to you not having access to the URL you are trying to use. If you can access the same URL with your browser, the remote site may be blocking OpenRefine because it doesn't recognize its request as valid. Changing the [User-Agent](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) request header may help. If you believe you should have access to a site but are “forbidden,†you may wish to contract the administrators. + +**“HTTP error 404 : Not Foundâ€** indicates that the information you are requesting does not exist, perhaps due to a problem with your cell values if it only happening in certain rows. + +**“HTTP error 500 : Internal Server Errorâ€** indicates the remote server is having a problem filling your request. You may wish to simply wait and try again later, or double-check the URLs. + +**“error: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failureâ€** can occur when you are trying to retrieve information over HTTPS but the remote site is using an encryption not supported by the Java virtual machine being used by OpenRefine. + +You can check which encryption methods are supported by your OpenRefine/Java installation by using a service such as **How's my SSL**. Add the URL `https://www.howsmyssl.com/a/check` to an OpenRefine cell and run “Add column by fetching URLs†on it, which will provide a description of the SSL client being used. + +You can try installing additional encryption supports by installing the [Java Cryptography Extension](https://www.oracle.com/java/technologies/javase-jce8-downloads.html). +Note that for Mac users and for Windows users with the OpenRefine installation with bundled JRE, these updated cipher suites need to be dropped into the Java install within the OpenRefine application: + +* On Mac, it will look something like `/Applications/OpenRefine.app/Contents/PlugIns/jdk1.8.0_60.jdk/Contents/Home/jre/lib/security`. +* On Windows: `\server\target\jre\lib\security`. + +**“javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failedâ€** can appear when the remote site is using an HTTPS certificate not trusted by your local Java installation. You will need to make sure that the certificate, or (more likely) the root certificate, is trusted. + +The list of trusted certificates is stored in an encrypted file called `cacerts` in your local Java installation. This can be read and updated by a tool called “keytool.†You can find directions on how to add a security certificate to the list of trusted certificates for a Java installation [here](http://magicmonster.com/kb/prg/java/ssl/pkix_path_building_failed.html) and [here](http://javarevisited.blogspot.co.uk/2012/03/add-list-certficates-java-keystore.html). + +Note that for Mac users and for Windows users with the OpenRefine installation with bundled JRE, the `cacerts` file within the OpenRefine application needs to be updated. + +* On Mac, it will look something like `/Applications/OpenRefine.app/Contents/PlugIns/jdk1.8.0_60.jdk/Contents/Home/jre/lib/security/cacerts`. +* On Windows: `\server\target\jre\lib\security\`. + +## Renaming, removing, and moving {#renaming-removing-and-moving} + +Every column's Edit column dropdown contains options to move it (to the beginning, end, left, or right), rename it, and delete it. +These operations can be undone, but a removed column cannot be restored later if you keep modifying your data. If you wish to temporarily hide a column, go to [View](sortview#view) → Collapse this column instead. + +Be cautious about moving columns in [records mode](cellediting#rows-vs-records): if you change the first column in your dataset (the key column), your records may change in unintended ways. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/exploring.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/exploring.md new file mode 100644 index 000000000..23bafc1a7 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/exploring.md @@ -0,0 +1,116 @@ +--- +id: exploring +title: Exploring data +sidebar_label: Overview +--- + +## Overview {#overview} + +OpenRefine offers lots of features to help you learn about your dataset, even if you don’t change a single character. In this section we cover different ways for sorting through, filtering, and viewing your data. + +Unlike spreadsheets, OpenRefine doesn’t store formulas and display the output of those calculations; it only shows the value inside each cell. It doesn’t support cell colors or text formatting. + +## Data types {#data-types} + +Each piece of information (each cell) in OpenRefine is assigned a data type. Some file formats, when imported, can set data types that are recognized by OpenRefine. Cells without an associated data type on import will be considered a “string†at first, but you can have OpenRefine convert cell contents into other data types later. This is set at the cell level, not at the column level. + +You can see data types in action when you preview a new project: check the box next to Attempt to parse cell text into numbers, and cells will be converted to the “number†data type based on their contents. You’ll see numbers change from black text to green if they are recognized. + +The data type will determine what you can do with the value. For example, if you want to add two values together, they must both be recognized as the number type. + +You can check data types at any time by: +* clicking “edit†on a single cell (where you can also edit the type) +* creating a Custom Text Facet on a column, and inserting `type(value)` into the Expression field. This will generate the data type in the preview, and you can facet by data type if you press OK. + +The data types supported are: +* string (one or more text characters) +* number (one or more characters of numbers only) +* boolean (values of “true†or “falseâ€) +* [date](#dates) (ISO-8601-compliant extended format with time in UTC: YYYY-MM-DDTHH:MM:SSZ) + +OpenRefine recognizes two further data types as a result of its own processes: +* error +* null + +An “error†data type is created when the cell is storing an error generated during a transformation in OpenRefine. + +A “null†data type is a special type that means “this cell has no value.†It’s distinct from cells that have values such as “0†or “falseâ€, or cells that look empty but have whitespace in them, or cells that contain empty strings. When you use `type(value)`, it will show you that the cell’s value is “null†and its type is “undefined.†You can opt to [show “null†values](sortview#showhide-null), by going to All → View → Show/Hide ‘null’ values in cells. + +Changing a cell's data type is not the same operation as transforming its contents. For example, using a column-wide transform such as Transform → Common transforms → To date may not convert all values successfully, but going to an individual cell, clicking “editâ€, and changing the data type can successfully convert text to a date. These operations use different underlying code. Learn more about date formatting and transformations in the next section. + +To transform data from one type to another, see [Transforming data](cellediting#data-type-transforms) for information on using common tranforms, and see [Expressions](expressions) for information on using [toString()](grelfunctions#tostringo-string-format-optional), [toDate()](grelfunctions#todateo-b-monthfirst-s-format1-s-format2-), and other functions. + + +### Dates {#dates} + +A “date†type is created when a column is [transformed into dates](transforming#to-date), when an expression is used to [convert cells to dates](grelfunctions#todateo-b-monthfirst-s-format1-s-format2-) or when individual cells are set to have the data type “dateâ€. + +Date-formatted data in OpenRefine relies on a number of conversion tools and standards. For something to be considered a date in OpenRefine, it will be converted into the ISO-8601-compliant extended format with time in UTC: YYYY-MM-DDTHH:MM:SSZ. + +When you run Edit cells → Common transforms → To date, the following column of strings on the left will transform into the values on the right: + +|Input|→|Output| +|---|---|---| +|23/12/2019|→|2019-12-23T00:00:00Z| +|14-10-2015|→|2015-10-14T00:00:00Z| +|2012 02 16|→|2012-02-16T00:00:00Z| +|August 2nd 1964|→|1964-08-02T00:00:00Z| +|today|→|today| +|never|→|never| + +OpenRefine uses a variety of tools to recognize, convert, and format [dates](exploring#dates) and so some of the values above can be reformatted using other methods. In this case, clicking the “today†cell and editing its data type manually will convert “today†into a value such as “2020-08-14T00:00:00Zâ€. Attempting the same data-type change on “never†will give you an error message and refuse to proceed. + +You can do more precise conversion and formatting using expressions and arguments based on the state of your data: see the GREL functions reference section on [Date functions](grelfunctions#date-functions) for more help. + +You can convert dates into a more human-readable format when you [export your data using the custom tabular exporter](exporting#custom-tabular-exporter). You are given the option to keep your dates in the ISO 8601 format, to output short, medium, long, or full locale formats, or to specify a custom format. This means that you can format your dates into, for example, MM/DD/YY (the US short standard) with or without including the time, after working with ISO-8601-formatted dates in your project. + +The following table shows some example [date and time formatting styles for the U.S. and French locales](https://docs.oracle.com/javase/tutorial/i18n/format/dateFormat.html): + +|Style |U.S. Locale |French Locale| +|---|---|---| +|Default |Jun 30, 2009 7:03:47 AM |30 juin 2009 07:03:47| +|Short |6/30/09 7:03 AM |30/06/09 07:03| +|Medium |Jun 30, 2009 7:03:47 AM |30 juin 2009 07:03:47| +|Long |June 30, 2009 7:03:47 AM PDT |30 juin 2009 07:03:47 PDT| +|Full |Tuesday, June 30, 2009 7:03:47 AM PDT |mardi 30 juin 2009 07 h 03 PDT| + +## Rows vs. records {#rows-vs-records} + +A row is a simple way to organize data: a series of cells, one cell per column. Sometimes there are multiple pieces of information in one cell, such as when a survey respondent can select more than one response. + +In cases where there is more than one value for a single column in one or more rows, you may wish to use OpenRefine’s records mode: this defines a single record as potentially containing more than one row. From there you can transform cells into multiple rows, each cell containing one value you’d like to work with. + +Generally, when you import some data, OpenRefine reads that data in row mode. From the project screen, you can convert the project into records mode. OpenRefine remembers this action and will present you with records mode each time you open the project from then on. + +OpenRefine understands records based on the content of the first column, what we call the “key column.†Splitting a row into a multi-row record will base all association on the first column in your dataset. + +If you have more than one column to split out into multiple rows, OpenRefine will keep your data associated with its original record, and associate subgroups based on the top-most row in each group. + +You can imagine the structure as a tree with many branches, all leading back to the same trunk. + +For example, your key column may be a film or television show, with multiple cast members identified by name, associated to that work. You may have one or more roles listed for each person. The roles are linked to the actors, which are linked to the title. + +|Work|Actor|Role| +|---|---|---| +|The Wizard of Oz|Judy Garland|Dorothy Gale| +||Ray Bolger|"Hunk"| +|||The Scarecrow| +||Jack Haley|"Hickory"| +|||The Tin Man| +||Bert Lahr|"Zeke"| +|||The Cowardly Lion| +||Frank Morgan|Professor Marvel| +|||The Gatekeeper| +|||The Carriage Driver| +|||The Guard| +|||The Wizard of Oz| +||Margaret Hamilton|Miss Almira Gulch| +|||The Wicked Witch of the West| + +Once you are in records mode, you can still move some columns around, but if you move a column to the beginning, you may find your data becomes misaligned. The new key column will sort into records based on empty cells, and values in the old key column will be assigned to the last row in the old record (the key value sitting above those values). + +OpenRefine assigns a unique key behind the scenes, so your records don’t need a unique identifier in the key column. You can keep track of which rows are assigned to each record by the record number that appears under the All column. + +To [split multi-valued cells](transforming#split-multi-valued-cells) and apply other operations that take advantage of records mode, see [Transforming data](transforming). + +Be careful when in records mode that you do not accidentally delete rows based on being blank in one column where there is a value in another. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/exporting.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/exporting.md new file mode 100644 index 000000000..5dcec2204 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/exporting.md @@ -0,0 +1,134 @@ +--- +id: exporting +title: Exporting your work +sidebar_label: Exporting +--- + +## Overview {#overview} + +Once your dataset is ready, you will need to get it out of OpenRefine and into the system of your choice. OpenRefine outputs a number of file formats, can upload your data directly into Google Sheets, and can create or update statements on Wikidata. + +You can also [export your full project data](#export-a-project) so that it can be opened by someone else using OpenRefine (or yourself, on another computer). + +## Export data {#export-data} + +![A screenshot of the Export dropdown.](/img/export-menu.png) + +Many of the options only export data in the current view - that is, with current filters and facets applied. Some will give you the choice to export your entire dataset or just the currently-viewed rows. + +To export data from a project, click the Export dropdown button in the top right corner and pick the format you want. Your options are: + +* Tab-separated value (TSV) or Comma-separated value (CSV) +* HTML-formatted table +* Excel spreadsheet (XLS or XLSX) +* Open Document Format (ODF) spreadsheet (ODS) +* Upload to Google Sheets (requires [Google account authorization](starting#google-sheet-from-drive)) +* [Custom tabular exporter](#custom-tabular-exporter) +* [SQL statement exporter](#sql-statement-exporter) +* [Templating exporter](#templating-exporter), which generates JSON by default + +You can also export reconciled data to Wikidata, or export your Wikidata schema for future use with other OpenRefine projects: + +* [Upload edits to Wikidata](wikidata#upload-edits-to-wikidata) +* [Export to QuickStatements](wikidata#quickstatements-export) (version 1) +* [Export Wikidata schema](wikidata#import-and-export-schema) + +### Custom tabular exporter {#custom-tabular-exporter} + +![A screenshot of the custom tabular content tab.](/img/custom-tabular-exporter.png) + +With the custom tabular exporter, you can choose which of your data to export, the separator you wish to use, and whether you'd like to download the result to your computer or upload it into a Google Sheet. + +On the Content tab, you can drag and drop the columns appearing in the column list to reorder the output. The options for reconciled and date data are applied to each column individually. + +This exporter is especially useful with reconciled data, as you can choose whether you wish to output the cells' original values, the matched values, or the matched IDs. Ouputting “match entity's nameâ€, “matched entity's IDâ€, or “cell's content†will output, respectively, the contents of `cell.recon.match.name`, `cell.recon.match.id`, and `cell.value`. + +“Output nothing for unmatched cells†will export empty cells for both newly-created matches and cells with no chosen matches. “Link to matched entity's page†will produce hyperlinked text in an HTML table output, but have no effect in other formats. + +At this time, the date-formatting options in this window do not work. You can [keep track of this issue on Github](https://github.com/OpenRefine/OpenRefine/issues/3368). +In the future, you will be able to choose how to [output date-formatted cells](exploring#dates). You can create a custom date output by using [formatting according to the SimpleDateFormat parsing key found here](grelfunctions#todateo-b-monthfirst-s-format1-s-format2-). + +![A screenshot of the custom tabular file download tab.](/img/custom-tabular-exporter2.png) + +On the Download tab, you can generate a preview of how the first ten rows of your dataset will output. If you do not choose one of the file formats on the right, the Download button will generate a text file. On the Upload tab, you can create a new Google Sheet. + +With the Option Code tab, you can copy JSON of your current custom settings to reuse on another export, or you can paste in existing JSON settings to apply to the current project. + +### SQL exporter {#sql-exporter} + +The SQL exporter creates a SQL statement containing the data you’ve exported, which you can use to overwrite or add to an existing database. Choosing Export → SQL exporter will bring up a window with two tabs: one to define what data to output, and another to modify other aspects of the SQL statement, with options to preview and download the statement. + +![A screenshot of the SQL statement content window.](/img/sql-exporter.png) + +The Content tab allows you to craft your dataset into an SQL table. From here, you can choose which columns to export, the data type to export for each (or choose "VARCHAR"), and the maximum character length for each field (if applicable based on the data type). You can set a default value for empty cells after unchecking “Allow null†in one or more columns. + +With this output tool, you can choose whether to output only currently visible rows, or all the rows in your dataset, as well as whether to include empty rows. The option to “Trim column names†will remove their whitespace characters. + +![A screenshot of the SQL statement download window.](/img/sql-exporter2.png) + +The Download tab allows you to finalize your complete SQL statement. + +Include schema means that you will start your statement with the creation of a table. Without that, you will only have an INSERT statement. + +Include content means including the INSERT statement with data from your project. Without that, you will only create empty columns. + +You can include DROP and IF EXISTS if you require them, and set a name for the table to which the statement will refer. + +You can then preview your statement, which will open up a new browser tab/window showing a statement with the first ten rows of your data (if included), or you can save a `.sql` file to your computer. + +### Templating exporter {#templating-exporter} + +If you pick Templating… from the Export dropdown menu, you can “roll your own†exporter. This is useful for formats that we don't support natively yet, or won't support. The Templating exporter generates JSON by default. + +![A screenshot of the Templating exporter generating JSON by default.](/img/templating-exporter.png) + +The Templating Export window allows you to set your own separators, prefix, and suffix to create a complete dataset in the language of your choice. In the Row template section, you can choose which columns to generate from each row by calling them with [variables](expressions#variables). + +This can be used to: +* output [reconciliation data](expressions#reconciliation), such as `cells["ColumnName"].recon.match.name` +* create multiple columns of output from different [member fields](expressions#variables) of a single project column +* employ [expressions](expressions) to modify data for output: for example, `cells["ColumnName"].value.toUppercase()`. + +Anything that appears inside doubled curly braces ({{ }}) is treated as a GREL expression; anything outside is generated as straight text. You can use Jython or Clojure by declaring it at the start: +``` +{{jython:return cells["ColumnName"].value}} +``` + +:::caution +Note that some syntax is different in this tool than elsewhere in OpenRefine: a forward slash must be escaped with a backslash, while other characters do not need escaping. You cannot, at this time, include a closing curly brace (}) anywhere in your expression, or it will cause it to malfunction. +::: + +You can include [regular expressions](expressions#regular-expressions) as usual (inside forward slashes, with any GREL function that accepts them). For example, you could output a version of your cells with punctuation removed, using an expression such as +``` +{{jsonize(cells["ColumnName"].value.replaceChars("/[.!?$&,/]/",""))}} +``` + +You could also simply output a plain-text document inserting data from your project into sentences: for example, "In `{{cells["Year"].value}}` we received `{{cells["RequestCount"].value}}` requests." + +You can use the shorthand `${ColumnName}` (no need for quotes) to insert column values directly. You cannot use this inside an expression, because of the closing curly brace. + +If your projects is in records mode, the Row separator field will insert a separator between records, rather than individual rows. Rows inside a single record will be directly appended to one another as per the content in the Row Template field. + +Once you have created your template, you may wish to save the text you produced in each field, in order to reuse it in the future. Once you click Export OpenRefine will output a simple `.txt` file, and your template will be discarded. + +We have recipes on using the Templating exporter to [produce several different formats](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#12-templating-exporter). + +## Export a project {#export-a-project} + +You can share a project in progress with another computer, a colleague, or with someone who wants to check your history. This can be useful for showing that your data cleanup didn’t distort or manipulate the information in any way. Once you have exported a project, another OpenRefine installation can [import it as a new project](starting#import-a-project). + +You can either save it locally or upload it to Google Drive (which requires you to authorize a Google account). + +:::caution +OpenRefine project archives contain confidential data from previous steps, which will still be accessible to anyone who has the archive. If you are hoping to keep your original dataset hidden for privacy reasons, such as using OpenRefine to anonymize information, do not share your project archive. +::: + +To save your project archive locally: from the Export dropdown, select OpenRefine project archive to file. OpenRefine exports your full project with all of its history. It does not export any current views or applied facets. Existing reconciliation information will be preserved, but the importing computer will need to add the same reconciliation services to keep working with that data. + +OpenRefine exports files in `.tar.gz` format. You can rename the file when you save it; otherwise it will bear the project name. + +To save your project archive to Google Drive: from the Export dropdown, select OpenRefine project archive to Google Drive.... OpenRefine will not share the link with you, only confirm that the file was uploaded. + +## Export operations {#export-operations} + +You can [save and re-apply the history of any project](running#reusing-operations) (all the operations shown in the Undo/Redo tab). This creates JSON that you can save for later reuse on another OpenRefine project. \ No newline at end of file diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/expressions.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/expressions.md new file mode 100644 index 000000000..3408fbf66 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/expressions.md @@ -0,0 +1,208 @@ +--- +id: expressions +title: Expressions +sidebar_label: Overview +--- + +## Overview {#overview} + +You can use expressions in multiple places in OpenRefine to extend data cleanup and transformation. Expressions are available with the following functions: +* Facet: + + * Custom text facet... + * Custom numeric facet… + * Customized facets (click “change†after they have been created to bring up an expressions window) +* Edit cells: + + * Transform… + * Split multi-valued cells… + * Join multi-valued cells… +* Edit column: + + * Split + * Join + * Add column based on this column + * Add column by fetching URLs. + +In the expressions editor window you have the opportunity to select a supported language. The default is [GREL (General Refine Expression Language)](grel); OpenRefine also comes with support for [Clojure](jythonclojure#clojure) and [Jython](jythonclojure#jython). Extensions may offer support for more expressions languages. + +These languages have some syntax differences but support many of the same [variables](#variables). For example, the GREL expression `value.split(" ")[1]` would be written in Jython as `return value.split(" ")[1]`. + +This page is a general reference for available functions, variables, and syntax. For examples that use these expressions for common data tasks, look at the [Recipes section on the wiki](https://github.com/OpenRefine/OpenRefine/wiki/Documentation-For-Users#recipes-and-worked-examples). + +## Expressions {#expressions} + +There are significant differences between OpenRefine's expressions and the spreadsheet formulas you may be used to using for data manipulation. OpenRefine does not store formulas in cells and display output dynamically: OpenRefine’s transformations are one-time operations that can change column contents or generate new columns. These are applied using variables such as `value` or `cell` to perform the same modification to each cell in a column. + +Take the following example: + +|ID|Friend|Age| +|---|---|---| +|1.|John Smith|28| +|2.|Jane Doe|33| + +Were you to apply a transformation to the “friend†column with the expression + +``` + value.split(" ")[1] +``` + +OpenRefine would work through each row, splitting the “friend†values based on a space character. The `value` for row 1 is “John Smith†so the output would be “Smith†(as "[1]" selects the second part of the created output); the `value` for row 2 is “Jane Doe†so the output would be “Doeâ€. Using variables, a single expression yields different results for different rows. The old information would be discarded; you couldn't get "John" and "Jane" back unless you undid the operation in the [History](running#history-undoredo) tab. + +For another example, if you were to create a new column based on your data using the expression `row.starred`, it would generate a column of true and false values based on whether your rows were starred at that moment. If you were to then star more rows and unstar some rows, that data would not dynamically update - you would need to run the operation again to have current true/false values. + +Note that an expression is typically based on one particular column in the data - the column whose drop-down menu is first selected. Many variables are created to stand for things about the cell in that “base column†of the current row on which the expression is evaluated. There are also variables about rows, which you can use to access cells in other columns. + +## The expressions editor {#the-expressions-editor} + +When you select a function that accepts expressions, you will see a window overlay the screen with what we call the expressions editor. + +![The expressions editor window with a simple expression: value + 10.](/img/expression-editor.png) + +The expressions editor offers you a field for entering your formula and shows you a preview of its transformation on your first few rows of cells. + +There is a dropdown menu from which you can choose an expression language. The default at first is GREL; if you begin working with another language, that selection will persist across OpenRefine. Jython and Clojure are also offered with the installation package, and you may be able to add more language support with third-party extensions and customizations. + +There are also tabs for: +* History, which shows you formulas you’ve recently used from across all your projects +* Starred, which shows you formulas from your History that you’ve starred for reuse +* Help, a quick reference to GREL functions. + +Starring formulas you’ve used in the past can be helpful for repetitive tasks you’re performing in batches. + +You can also choose how formula errors are handled: replicate the original cell value, output an error message into the cell, or ouput a blank cell. + +## Regular expressions {#regular-expressions} + +OpenRefine offers several fields that support the use of regular expressions (regex), such as in a Text filter or a Replace… operation. GREL and other expressions can also use regular expression markup to extend their functionality. + +If this is your first time working with regex, you may wish to read [this tutorial specific to the Java syntax that OpenRefine supports](https://docs.oracle.com/javase/tutorial/essential/regex/). We also recommend this [testing and learning tool](https://regexr.com/). + +### GREL-supported regex {#grel-supported-regex} + +To write a regular expression inside a GREL expression, wrap it between a pair of forward slashes (/) much like the way you would in Javascript. For example, in + +``` +value.replace(/\s+/, " ") +``` + +the regular expression is `\s+`, and the syntax used in the expression wraps it with forward slashes (`/\s+/`). Though the regular expression syntax in OpenRefine follows that of Java (normally in Java, you would write regex as a string and escape it like "\\s+"), a regular expression within a GREL expression is similar to Javascript. + +Do not use slashes to wrap regular expressions outside of a GREL expression. + +On the [GREL functions](grelfunctions) page, functions that support regex will indicate that with a “p†for “pattern.†The GREL functions that support regex are: +* [contains](grelfunctions#containss-sub-or-p) +* [replace](grelfunctions#replaces-s-or-p-find-s-replace) +* [find](grelfunctions#finds-sub-or-p) +* [match](grelfunctions#matchs-p) +* [partition](grelfunctions#partitions-s-or-p-fragment-b-omitfragment-optional) +* [rpartition](grelfunctions#rpartitions-s-or-p-fragment-b-omitfragment-optional) +* [split](grelfunctions#splits-s-or-p-sep) +* [smartSplit](grelfunctions#smartsplits-s-or-p-sep-optional) + +### Jython-supported regex {#jython-supported-regex} + +You can also use [regex with Jython expressions](http://www.jython.org/docs/library/re.html), instead of GREL, for example with a Custom Text Facet: + +``` +python import re g = re.search(ur"\u2014 (.*),\s*BWV", value) return g.group(1) +``` + +### Clojure-supported regex {#clojure-supported-regex} + +[Clojure](https://clojure.org/reference/reader) uses the same regex engine as Java, and can be invoked with [re-find](http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/re-find), [re-matches](http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/re-matches), etc. You can use the #"pattern" reader macro as described [in the Clojure documentation](https://clojure.org/reference/other_functions#regex). For example, to get the nth element of a returned sequence, you can use the nth function: + +``` +clojure (nth (re-find #"\u2014 (.*),\s*BWV" value) 1) +``` + +## Variables {#variables} + +Most OpenRefine variables have attributes: aspects of the variables that can be called separately. We call these attributes “member fields†because they belong to certain variables. For example, you can query a record to find out how many rows it contains with `row.record.rowCount`: `rowCount` is a member field specific to the `record` variable, which is a member field of `row`. Member fields can be called using a dot separator, or with square brackets (`row["record"]`). The square bracket syntax is also used for variables that can call columns by name, for example, `cells["Postal Code"]`. + +|Variable |Meaning | +|-|-| +| `value` | The value of the cell in the current column of the current row (can be null) | +| `row` | The current row | +| `row.record` | One or more rows grouped together to form a record | +| `cells` | The cells of the current row, with fields that correspond to the column names (or row.cells) | +| `cell` | The cell in the current column of the current row, containing value and other attributes | +| `cell.recon` | The cell's reconciliation information returned from a reconciliation service or provider | +| `rowIndex` | The index value of the current row (the first row is 0) | +| `columnName` | The name of the current cell's column, as a string | + +### Row {#row} + +The `row` variable itself is best used to access its member fields, which you can do using either a dot operator or square brackets: `row.index` or `row["index"]`. + +|Field |Meaning | +|-|-| +| `row.index` | The index value of the current row (the first row is 0) | +| `row.cells` | The cells of the row, returned as an array | +| `row.columnNames` | An array of the column names of the project. This will report all columns, even those with null cell values in that particular row. Call a column by number with `row.columnNames[3]` | +| `row.starred` | A boolean indicating if the row is starred | +| `row.flagged` | A boolean indicating if the row is flagged | +| `row.record` | The [record](#record) object containing the current row | + +For array objects such as `row.columnNames` you can preview the array using the expressions window, and output it as a string using `toString(row.columnNames)` or with something like: + +``` +forEach(row.columnNames,v,v).join("; ") +``` + +### Cells {#cells} + +The `cells` object is used to call information from the columns in your project. For example, `cells.Foo` returns a [cell](#cell) object representing the cell in the column named “Foo†of the current row. If the column name has spaces, use square brackets, e.g., `cells["Postal Code"]`. To get the corresponding column's value inside the `cells` variable, use `.value` at the end, for example, `cells["Postal Code"].value`. There is no `cells.value` - it can only be used with member fields. + +### Cell {#cell} + +A `cell` object contains all the data of a cell and is stored as a single object. + +You can use `cell` on its own in the expressions editor to copy all the contents of a column to another column, including reconciliation information. Although the preview in the expressions editor will only show a small representation (“[object Cell]â€), it will actually copy all the cell's data. Try this with Edit Column → Add Column based on this column .... + +|Field |Meaning |Member fields | +|-|-|-| +| `cell` | An object containing the entire contents of the cell | .value, .recon, .errorMessage | +| `cell.value` | The value in the cell, which can be a string, a number, a boolean, null, or an error | | +| `cell.recon` | An object encapsulating reconciliation results for that cell | See the [reconciliation](expressions#reconciliation) section | +| `cell.errorMessage` | Returns the message of an *EvalError* instead of the error object itself (use value to return the error object) | .value | + +### Reconciliation {#reconciliation} + +Several of the fields here provide the data used in [reconciliation facets](reconciling#reconciliation-facets). You must type `cell.recon`; `recon` on its own will not work. + +|Field|Meaning |Member fields | +|-|-|-| +| `cell.recon.judgment` | A string: either “matchedâ€, "newâ€, "none†| | +| `cell.recon.judgmentAction` | A string: either "single†or “similar†(or “unknownâ€) | | +| `cell.recon.judgmentHistory` | A number, the epoch timestamp (in milliseconds) of your judgment | | +| `cell.recon.matched` | A boolean, true if judgment is “matched†| | +| `cell.recon.match` | The recon candidate that has been matched against this cell (or null) | .id, .name, .type | +| `cell.recon.best` | The highest scoring recon candidate from the reconciliation service (or null) | .id, .name, .type, .score | +| `cell.recon.features` | An array of reconciliation features to help you assess the accuracy of your matches | .typeMatch, .nameMatch, .nameLevenshtein, .nameWordDistance | +| `cell.recon.features.typeMatch` | A boolean, true if your chosen type is “matched†and false if not (or “(no type)†if unreconciled) | | +| `cell.recon.features.nameMatch` | A boolean, true if the cell and candidate strings are identical and false if not (or “(unreconciled)â€) | | +| `cell.recon.features.nameLevenshtein` | A number representing the [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance): larger if the difference is greater between value and candidate | | +| `cell.recon.features.nameWordDistance` | A number based on the [word similarity](reconciling#reconciliation-facets) | | +| `cell.recon.candidates` | An array of the top 3 candidates (default) | .id, .name, .type, .score | + +The `cell.recon.candidates` and `cell.recon.best` objects have a few deeper fields: `id`, `name`, `type`, and `score`. `type` is an array of type identifiers for a list of candidates, or a single string for the best candidate. + +Arrays such as `cell.recon.candidates` and `cell.recon.candidates.type` can be joined into lists and stored as strings with something like: +``` +forEach(cell.recon.candidates,v,v.name).join("; ") +``` + +### Record {#record} + +A `row.record` object encapsulates one or more rows that are grouped together, when your project is in records mode. You must call it as `row.record`; `record` will not return values. + +|Field|Meaning | +|-|-| +| `row.record.index` | The index of the current record (starting at 0) | +| `row.record.cells` | An array of the [cells](#cells) in the given column of the record | +| `row.record.fromRowIndex` | The row index of the first row in the record | +| `row.record.toRowIndex` | The row index of the last row in the record + 1 (i.e. the next record) | +| `row.record.rowCount` | A count of the number of rows in the record | + +For example, you can facet by number of rows in each record by creating a Custom Numeric Facet (or a Custom Text Facet) and entering `row.record.rowCount`. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/facets.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/facets.md new file mode 100644 index 000000000..b63df21e8 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/facets.md @@ -0,0 +1,325 @@ +--- +id: facets +title: Exploring facets +sidebar_label: Facets +--- + +## Overview {#overview} + +Facets are one of OpenRefine’s strongest features - that’s where the diamond logo comes from! + +Faceting allows you to look for patterns and trends. Facets are essentially aspects or angles of data variance in a given column. For example, if you had survey data where respondents indicated one of five responses from “Strongly agree†to “Strongly disagree,†those five responses make up a text facet, showing how many people selected each option. + +Faceted browsing gives you a big-picture look at your data (do they agree or disagree?) and also allows you to filter down to a specific subset to explore it more (what do people who disagree say in other responses?). + +Typically, you create a facet on a particular column. That facet selection appears on the left, in the Facet/Filter tab, and you can click on a displayed facet to view all the records that match. You can also “exclude†the facet, to view every record that does _not_ match, and you can select more than one facet by clicking “include.†+ + +### An example {#an-example} + +You can learn about facets and filtering with the following example. You can copy the following table and paste it using the Clipboard method of starting a project if you would like to try it yourself. + +We collected a list of the [10 most populous cities from Wikidata](https://w.wiki/3Em), using an example query of theirs. We removed the GPS coordinates and added the country. + +| cityLabel | population | countryLabel | +|-|-|-| +| Shanghai | 23390000 | People's Republic of China | +| Beijing | 21710000 | People's Republic of China | +| Lagos | 21324000 | Nigeria | +| Dhaka | 16800000 | Bangladesh | +| Mumbai | 15414288 | India | +| Istanbul | 14657434 | Turkey | +| Tokyo | 13942856 | Japan | +| Tianjin | 13245000 | People's Republic of China | +| Guangzhou | 13080500 | People's Republic of China | +| São Paulo | 12106920 | Brazil | + +If we want to see which countries have the most populous cities, we can create a text facet on the “countryLabel†column and OpenRefine will generate a list of all the different strings used in these cells. + +We will see in the sidebar that the countries identified are displayed, along with the number of matches (the “countâ€). We can sort this list alphabetically or by the count. If you sort by count at the top of the facet window, you’ll learn which countries hold the most populous cities. + +|Facet|Count| +|---|---| +|People's Republic of China|4| +|Bangladesh|1| +|Brazil|1| +|India|1| +|Japan|1| +|Nigeria|1| +|Turkey|1| + +If we want to learn more about a particular country, we can click on its appearance in the facet sidebar. This narrows our dataset down temporarily to only rows matching that facet. + +You’ll see the “10 rows†indicator change to “4 matching rows (10 total)†if you click on “People’s Republic of Chinaâ€. In the data grid, you’ll see fewer rows: only the ones matching your current filter. Each row will maintain its original numbering, though - in this case, rows #1, 2, and 8. + +If you want to go back to the original dataset, click Reset All or the small “exclude†text next to the facet. If you want to view the most populous cities in both China and India, click “include†next to each facet. Now you’ll see 5 rows - #1, 2, 5, 8, 9. + +We can also explore our data using the population information. In this case, because population is a number, we can create a numeric facet. This will give us the ability to explore by range rather than by exact matching values. + +With the numeric facet, we are given a scale from the smallest to the largest value in the column. We can drag the range minimum and maximum to narrow the results. In this case, if we narrow down to only cities with more than 20 million in population, we get 3 matching rows out of the original 10. + +When you look back at the text facet display of country names, you should see a smaller list with a reduced count: OpenRefine is now displaying the facets of the 3 matching rows, not the total dataset of 10 rows. + +We can combine these facets - say, by narrowing to only the Chinese cities with populations greater than 20 million - simply by clicking in both. You should see 2 matching rows for both these criteria. + +### Things to know about facets {#things-to-know-about-facets} + +When you have facets applied, you will see “matching rows†in the [project grid header](running#project-grid-header). If you click Export and copy your data out of OpenRefine while facets are active, many of the exporting options will only export the matching rows, not all the rows in your project. + +OpenRefine has several default facets, which you’ll learn about below. The most powerful facets are the ones designed by you - custom facets, written using [expressions](expressions) to transform the data behind the scenes and help you narrow down to precisely what you’re looking for. + +Facets are not saved in the project along with the data. But you can save a link to the current state of the application. Find the [Permalink](running#the-project-bar) next to the project’s name. + +You can modify any facet expression by clicking the “change†button to the right of the column name in the facet sidebar. + +Facet boxes that appear in the sidebar can be resized and rearranged. You can drag and drop the title bar of each box to reorder them, and drag on the bottom bar of text facet boxes. + +## Text facet {#text-facet} + +A text facet can be generated on any column with the “text†data type. Select the column dropdown and go to Facet → Text facet. The created facet will be sorted alphabetically, and can be sorted by count. + +A text facet is very simple: it takes the total contents of the cells of the column in question and matches them up. It does no guessing about typos or near-matches. + +You can edit any entry that appears in the facet display, by hovering over the facet and clicking the “edit†button that appears. You can then type in a new value manually. This will mass-edit every identical cell in the column. This is a great way to fix typos, whitespace, and other issues that may be affecting the way facets appear. You can also automate the cleanup of facets by using [clustering](transforming#cluster-and-edit): a “Cluster†button is displayed within the facet window. It may be most efficient to cluster cells to one value, and then mass-edit that value to your desired string within the clustering operation window. + +Each text facet shows up to 2,000 choices by default. You can [increase this limit on the Preferences screen](running#preferences) if you need to, which may slow down your browser. If your applied facet has more choices than the current limit, you'll be offered the option to increase the limit, which will permanently edit that preference for you. + +The choices and counts displayed in each facet can be copied as tab-separated values. To do so, click on the "X choices" link near the top left corner of the facet. This can be useful to generate small summary tables of your data. + +![A column of years faceted as text and numbers, and with the count ready to be copied.](/img/yeardata.png) + +## Numeric facet {#numeric-facet} + +![A screenshot of an example numeric facet.](/img/numericfacet.png) + +Whereas a text facet groups unique text values into groups, a numeric facet sorts numbers by their range - smallest to biggest. This displays visually as a histogram, and allows you to set a custom facet within that range. You can drag the minimum and maximum range markers to set a range. OpenRefine snaps to some basic equal-sized divisions - 19 in the example set above. + +You will be offered the option to include blank, non-numeric, and error values in your numeric visualization; these will appear in the visual range as “0†values. + +:::info Numbers as text +You can create a text facet on numeric data, which will treat each entry as a string. This can be useful if you wish, for example, to manually include facets instead of selecting a range, or sort by count, or copy that count. +::: + +## Timeline facet {#timeline-facet} + +![A screenshot of an example timeline facet.](/img/timelinefacet.png) + +Much like a numeric facet, a timeline facet will display as a small histogram with the values sorted: in this case, chronologically. A timeline facet only works on cells formatted as the [“date†data type](exploring#dates). + +The facet appears with a count of blank cells and those with errors, which can help you analyze whether your date cells are correctly converted. + +## Scatterplot facet {#scatterplot-facet} + +A scatterplot is a visual representation of two related sets of numeric data. + +You have the option to generate linear scatterplots (where the X and Y axes show continuous increases) or logarithmic scatterplots (where the X and Y axes show exponential or scaled increases). You can also rotate the plot by 45 degrees in either direction, and you can choose the size of the dot indicating a datapoint. You can make these choices in both the preview and in the facet display. + +A scatterplot facet can be generated on any column. You require two or more number columns to generate scatterplots. Selecting Facet → Scatterplot facet will create a preview of data plotted from every number-formatted column in your dataset, comparing every column against every other column. Each scatterplot will show in its own square, allowing you to choose which data comparison you would like to analyze further. You can control which columns are on the X and Y axes by rearranging the columns in your dataset. + +![A simple scatterplot of two numeric values.](/img/scatterplot.png) + +When you click on your desired square, that two-column comparison will appear in the facets sidebar. From here, you can drag your mouse to draw a rectangle inside the scatterplot, which will narrow down to just the rows matching the points plotted inside that rectangle (as shown by the rectangle inside the square in the image above). This rectangle can be resized by dragging any of the four edges. To draw a new rectangle, simply click and drag your mouse again. To add more scatterplots to the facet sidebar, re-run this process and select a different square. + +If you have multiple facets applied, plotted points in your scatterplot displays will be greyed out if they are not part of the current matching data subset. If the rectangle you have drawn within a scatterplot display only includes grey dots, you will see no matching rows. + +If you would like to export a scatterplot, OpenRefine will open a new tab with a generated PNG file that you can save. + +## Custom text facet {#custom-text-facet} + +You may want to explore your textual data with modifications that aren't permanent. Creating custom text facets will load your column into memory, transform the data temporarily, and store those transformations inside the facet. + +You can also use custom text facets to analyze numerical data, such as by analyzing a number as a string, or by creating a test that will return “true†and “false†as values. + +Clicking on Facet → Custom text facet… will bring up an [expressions](expressions) window where you can enter in a GREL, Jython, or Clojure expression to modify how the facet works. + +A custom text facet operates just like a [text facet](#text-facet) by default. Unlike a text facet, however, you cannot click “edit†on the facets that appear in the sidebar and change the matching cells in your dataset - because what they display is modified, not the original entries. + +For example, you may wish to analyze only the first word in a text field - perhaps the first name in a column of “[First Name] [Last Name]†entries. In this case, you can tell OpenRefine to facet only on the information that comes before the first space: + +``` +value.split(" ")[0] +``` + +In this case, `split()` is creating an array of text strings based on every space in the cells ["Firstname", "Lastname"]. Because arrays number their entries starting with 0, we want the first value, so we ask for `[0]`. (Assuming the first name is one word, not something like “Mary Anne.â€) We can do the same splitting and ask for the last name with + +``` +value.split(" ")[1] +``` + +You may want to create a facet that references several columns. For example, let’s say you have two columns, “First Name†and “Last Nameâ€, and you want out how many people have the same initial letter for both names (e.g., Marilyn Monroe, Steven Segal). To do so, create a custom text facet on either column and enter the expression + +``` +cells["First Name"].value[0] == cells["Last Name"].value[0] +``` + +That expression will look for the first letter (the character at index 0) of each entry and compare them. Then it will facet your rows into “true†and “false.†+ +You can learn more about text-modification functions on the [Expressions page](expressions). + +## Custom numeric facet {#custom-numeric-facet} + +You may want to explore your numerical data with modifications that aren't permanent. You can also use custom numeric facets to analyze textual data, such as by getting the length of text strings (with `value.length()`), or by analyzing it as though it were formatted as numbers (with `toNumber(value)`). + +If you would like to build your own version of a numeric facet, you can use the Custom Numeric Facet option. Clicking on Facet → Custom Numeric Facet… will bring up an [expressions](expressions) window where you can enter in a GREL, Jython, or Clojure expression to modify how the facet works. A custom numeric facet operates just like a [numeric facet](#numeric-facet) by default. + +For example, you may wish to create a numeric facet that rounds your value to the nearest integer, enter + +``` +round(value) +``` + +If you have two columns of numbers and for each row you wish to create a numeric facet only on the larger of the two, enter + +``` +max(cells["Column1"].value, cells["Column2"].value) +``` + +If the numeric values in a column are drawn from a power law distribution, then it's better to group them by their logs: + +``` +value.log() +``` + +If the values are periodic you could take the modulus by the period to understand if there's a pattern: + +``` +mod(value, 7) +``` + +You can learn more about numeric-modification functions on the [Expressions page](expressions). + +## Customized facets {#customized-facets} + +Customized facets have been added to expand the number of default facets users can apply with a single click. They represent some common and useful functions you shouldn’t have to work out using an [expression](expressions). + +All facets that display in the Facet/Filter tab can be edited by clicking on the “change†button to the right of the column title. This brings up the expressions window that will allow you to modify and preview the expression being used. + +### Word facet {#word-facet} + +A Word facet is a simple version of a text facet: it splits up the content of the cells based on spaces, and outputs each character string as a facet: + +``` +value.split(" ") +``` + +This can be useful for exploring the language used in a corpus, looking for common first and last names or titles, or seeing what’s in multi-valued cells you don’t wish to split up. + +Word facet is case-sensitive and only splits by spaces, not by line breaks or other natural divisions. + +### Duplicates facet {#duplicates-facet} + +A Duplicates facet will return only rows that have non-unique values in the column you’ve selected. It will create a facet of “true†and “false†values - true being cells that are not unique, and “false†being cells that are. The actual expression being used is + +``` +facetCount(value, 'value', '[Column]') > 1 +``` + +Duplicates facets are case-sensitive and you may wish to filter out things like leading and trailing whitespace or other hard-to-see issues. You can modify the facet expression, for example, with: + +``` +facetCount(trim(toLowercase(value)), 'trim(toLowercase(value))', 'cityLabel') > 1 +``` + +### Numeric log facet {#numeric-log-facet} + +Logarithmic scales reduce wide-ranging quantities to more compact and manageable ranges. A log transformation can be used to make highly skewed distributions less skewed. If your numerical data is unevenly distributed (say, lots of values in one range, and then a long tail extending off into different magnitudes), a Numeric log facet can represent that range better than a simple numeric facet. It will break these values down into more navigable segments than the buckets of a numeric facet. This facet can make patterns in your data more visible. OpenRefine uses a base-10 log, the “common logarithm.†+ +For example, we can look at [this data about the body weight of various mammals](http://wiki.stat.ucla.edu/socr/index.php/SOCR_Data_Brain2BodyWeight): + +|Species|BodyWeight (kg)| +|---|---| +| Newborn_Human | 3.2 | +| Adult_Human | 73 | +| Pithecanthropus_Man | 70 | +| Squirrel | 0.8 | +| Hamster | 0.15 | +| Chimpanzee | 50 | +| Rabbit | 1.4 | +| Dog_(Beagle) | 10 | +| Cat | 4.5 | +| Rat | 0.4 | +| Sperm_Whale | 35000 | +| Turtle | 3 | +| Alligator | 270 | + +Most values will be clustered in the 0-100 range, but 35,000 is many magnitudes above that. A numeric facet will create 36 equal buckets of 1,000 each - containing almost all the cells in the first bucket. A numeric log facet will instead display the data more evenly across the visual range. + +![A screenshot of a numeric facet first and a numeric log facet second.](/img/numericlogfacet.png) + +A 1-bounded numeric log facet can be used if you'd like to exclude all the values below 1 (including zero and negative numbers). + +### Text-length facet {#text-length-facet} + +The Text-length facet returns a numerical value for each cell and plots it on a numeric facet chart. The expression used is + +``` +value.length() +``` + +This can be useful to, for example, look for values that did not successfully split on an earlier split operation, or to validate that data is a certain expected length (such as whether a date in YYYY/MM/DD is eight to ten characters). + +You can also employ a Log of text-length facet that allows you to navigate more easily a wide range of string lengths. This can be useful in the case of web-scraping, where lots of textual data is loaded into single cells and needs to be parsed out. + + +### Unicode character-code facet {#unicode-character-code-facet} + +![A screenshot of the Unicode facet.](/img/unicodefacet.png) + +The Unicode facet identifies and returns [Unicode decimal values](https://en.wikipedia.org/wiki/List_of_Unicode_characters). It generates a list of the Unicode numerical values of each character used in each text cell, which allows you to narrow down and search for special characters, punctuation, and other data formatting issues. + +This facet creates a numerical chart, which offers you the ability to narrow down to a range of numbers. For example, lowercase characters are numbers 97-122, uppercase characters are numbers 65-90, and numerical digits are numbers 48-57. + +### Facet by error {#facet-by-error} + +An error is a data type created by OpenRefine in the process of transforming data. For example, say you had converted a column to the number data type. If one cell had text characters in it, OpenRefine could either output the original text string unchanged or output an error. If you allow errors to be created, you can facet by them later to search for them and fix them. + +![A view of the expressions window with an error converting a string to a number.](/img/error.png) + +To store errors in cells, ensure that you have store error selected for the “On error†option in the expressions window. + +### Facet by null, empty, or blank {#facet-by-null-empty-or-blank} + +Any column can be faceted for [null and/or empty cells](#cell-data-types). These can help you find cells where you want to manually enter content. + +“Blank†means both null values and empty values. All three facets will generate “true†and “false†facets, “true†being blank. + +An empty cell is a cell that is set to contain a string, but doesn’t have any characters in it (a zero-length string). This can be left over from an operation that removed characters, or from manually editing a cell and deleting its contents. + +### Facet by star or flag {#facet-by-star-or-flag} + +Stars and flags offer you the opportunity to mark specific rows for yourself for later focus. Stars and flags persist through closing and opening your project, and thus can provide a different function than using a permalink to persist your facets. Stars and flags can be used in any way you want, although they are designed to help you flag errors and star rows of particular importance. + +You can manually star or flag rows simply by clicking on the icons to the left of each row. + +You can also apply stars or flags to all matching rows by using the All dropdown menu (on the first column) and selecting Edit rows → Star rows or Flag rows. This will create “true†and “false†facets in the Facet/Filter. These operations will modify all matching rows in your current subset. You can unstar or unflag them as well. + +You may wish to create a custom subset of your data through a series of separate faceting activities (rather than successively narrowing down with multiple facets applied). For example, you may wish to: +* apply a facet +* star all the matching rows +* remove that facet +* apply another, unrelated facet +* star all the new matching rows (which will not modify already-starred rows) +* remove that facet +* and then work with all of the cumulative starred rows. + +You can also create a text facet on any column with the expression `row.starred` or `row.flagged`. + +## Text filter {#text-filter} + +Filters allow you to narrow down your data based on whether a given column includes a text string. + +When you choose Text filter a box appears in the Facet/Filter tab that allows you to enter in text. Matching rows will narrow dynamically with every character you enter. You can set the search to be case-sensitive or not, and you can use this box to enter in a regular expression. + +For example, you can enter in “side†as a text filter, and it will return all cells in that column containing “side,†“sideways,†“offside,†etc. + +The text filter field supports [regular expressions](expressions#regular-expressions). For example, you can employ a regular expression to view all properly-formatted emails: + +``` +([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9\-\.]+)\.([a-zA-Z0-9\-]{2,15}) +``` + +You can press “invert†on this facet to then see blank cells or invalid email addresses. + +This filter works differently than facets because it is always active as long as it appears in the sidebar. If you “reset†it, you will delete all the text or expression you have entered. + +You can apply multiple text filters in succession, which will successively narrow your data subset. This can be useful if you apply multiple inverted filters, such as to filter out all rows that respond “yes†or “maybe†and only look at the remaining responses. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/grel.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/grel.md new file mode 100644 index 000000000..841e031b0 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/grel.md @@ -0,0 +1,154 @@ +--- +id: grel +title: General Refine Expression Language +sidebar_label: General Refine Expression Language +--- + +## Basics {#basics} + +GREL (General Refine Expression Language) is designed to resemble Javascript. Formulas use variables and depend on data types to do things like string manipulation or mathematical calculations: + +|Example|Output| +|---|---| +| `value + " (approved)"` | Concatenate two strings; whatever is in the cell gets converted to a string first | +| `value + 2.239` | Add 2.239 to the existing value (if a number); append text "2.239" to the end of the string otherwise | +| `value.trim().length()`     | Trim leading and trailing whitespace of the cell value and then output the length of the result | +| `value.substring(7, 10)` | Output the substring of the value from character index 7, 8, and 9 (excluding character index 10) | +| `value.substring(13)` | Output the substring from index 13 to the end of the string | + +Note that the operator for string concatenation is `+` (not “&†as is used in Excel). + +Evaluating conditions uses symbols such as <, >, *, /, etc. To check whether two objects are equal, use two equal signs (`value=="true"`). + +See the [GREL functions page for a thorough reference](grelfunctions) on each function and its inputs and outputs. Read on below for more about the general nature of GREL expressions. + +## Syntax {#syntax} + +In GREL, functions can use either of these two forms: +* functionName(arg0, arg1, ...) +* arg0.functionName(arg1, ...) + +The second form is a shorthand to make expressions easier to read. It simply pulls the first argument out and appends it to the front of the function, with a dot: + +|Dot notation |Full notation | +|-|-| +| `value.trim().length()` | `length(trim(value))` | +| `value.substring(7, 10)` | `substring(value, 7, 10)` | + +So, in the dot shorthand, the functions occur from left to right in the order of calling, rather than in the reverse order with parentheses. This allows you to string together multiple functions in a readable order. + +The dot notation can also be used to access the member fields of [variables](expressions#variables). For referring to column names that contain spaces (anything not a continuous string), use square brackets instead of dot notation: + +|Example |Description | +|-|-| +| `FirstName.cells` | Access the cell in the column named “FirstName†of the current row | +| `cells["First Name"]` | Access the cell in the column called “First Name†of the current row | + +Square brackets can also be used to get substrings and sub-arrays, and single items from arrays: + +|Example |Description | +|-|-| +| `value[1,3]` | A substring of value, starting from character 1 up to but excluding character 3 | +| `"internationalization"[1,-2]` | Will return “nternationalizati†(negative indexes are counted from the end) | +| `row.columnNames[5]` | Will return the name of the fifth column | + +Any function that outputs an array can use square brackets to select only one part of the array to output as a string (remember that the index of the items in an array starts with 0). + +For example, [partition()](grelfunctions#partitions-s-or-p-fragment-b-omitfragment-optional) would normally output an array of three items: the part before your chosen fragment, the fragment you've identified, and the part after. Selecting only the third part with `"internationalization".partition("nation")[2]` will output “alization†(and so will [-1], indicating the final item in the array). + +## Controls {#controls} + +GREL offers controls to support branching and looping (that is, “if†and “for†functions), but unlike functions, their arguments don't all get evaluated before they get run. A control can decide which part of the code to execute and can affect the environment bindings. Functions, on the other hand, can't do either. Each control decides which of their arguments to evaluate to `value`, and how. + +Please note that the GREL control names are case-sensitive: for example, the isError() control can't be called with iserror(). + +#### if(e, eTrue, eFalse) {#ife-etrue-efalse} + +Expression e is evaluated to a value. If that value is true, then expression eTrue is evaluated and the result is the value of the whole if() expression. Otherwise, expression eFalse is evaluated and that result is the value. + +Examples: + +| Example expression | Result | +| ------------------------------------------------------------------------ | ------------ | +| `if("internationalization".length() > 10, "big string", "small string")` | “big string†| +| `if(mod(37, 2) == 0, "even", "odd")` | “odd†| + +Nested if (switch case) example: + + if(value == 'Place', 'http://www.example.com/Location', + + if(value == 'Person', 'http://www.example.com/Agent', + + if(value == 'Book', 'http://www.example.com/Publication', + + null))) + +#### with(e1, variable v, e2) {#withe1-variable-v-e2} + +Evaluates expression e1 and binds its value to variable v. Then evaluates expression e2 and returns that result. + +| Example expression | Result | +| ------------------------------------------------------------------------------------ | ---------- | +| `with("european union".split(" "), a, a.length())` | 2 | +| `with("european union".split(" "), a, forEach(a, v, v.length()))` | [ 8, 5 ] | +| `with("european union".split(" "), a, forEach(a, v, v.length()).sum() / a.length())` | 6.5 | + +#### filter(e1, v, e test) {#filtere1-v-e-test} + +Evaluates expression e1 to an array. Then for each array element, binds its value to variable v, evaluates expression test - which should return a boolean. If the boolean is true, pushes v onto the result array. + +| Expression | Result | +| ---------------------------------------------- | ------------- | +| `filter([ 3, 4, 8, 7, 9 ], v, mod(v, 2) == 1)` | [ 3, 7, 9 ] | + +#### forEach(e1, v, e2) {#foreache1-v-e2} + +Evaluates expression e1 to an array. Then for each array element, binds its value to variable v, evaluates expression e2, and pushes the result onto the result array. + +| Expression | Result | +| ------------------------------------------ | ------------------- | +| `forEach([ 3, 4, 8, 7, 9 ], v, mod(v, 2))` | [ 1, 0, 0, 1, 1 ] | + +#### forEachIndex(e1, i, v, e2) {#foreachindexe1-i-v-e2} + +Evaluates expression e1 to an array. Then for each array element, binds its index to variable i and its value to variable v, evaluates expression e2, and pushes the result onto the result array. + +| Expression | Result | +| ------------------------------------------------------------------------------- | --------------------------- | +| `forEachIndex([ "anne", "ben", "cindy" ], i, v, (i + 1) + ". " + v).join(", ")` | 1. anne, 2. ben, 3. cindy | + +#### forRange(n from, n to, n step, v, e) {#forrangen-from-n-to-n-step-v-e} + +Iterates over the variable v starting at from, incrementing by the value of step each time while less than to. At each iteration, evaluates expression e, and pushes the result onto the result array. + +#### forNonBlank(e, v, eNonBlank, eBlank) {#fornonblanke-v-enonblank-eblank} + +Evaluates expression e. If it is non-blank, forNonBlank() binds its value to variable v, evaluates expression eNonBlank and returns the result. Otherwise (if e evaluates to blank), forNonBlank() evaluates expression eBlank and returns that result instead. + +Unlike other GREL functions beginning with “for,†forNonBlank() is not iterative. forNonBlank() essentially offers a shorter syntax to achieving the same outcome by using the isNonBlank() function within an “if†statement. + +#### isBlank(e), isNonBlank(e), isNull(e), isNotNull(e), isNumeric(e), isError(e) {#isblanke-isnonblanke-isnulle-isnotnulle-isnumerice-iserrore} + +Evaluates the expression e, and returns a boolean based on the named evaluation. + +Examples: + +| Expression | Result | +| ------------------- | ------- | +| `isBlank("abc")` | false | +| `isNonBlank("abc")` | true | +| `isNull("abc")` | false | +| `isNotNull("abc")` | true | +| `isNumeric(2)` | true | +| `isError(1)` | false | +| `isError("abc")` | false | +| `isError(1 / 0)` | true | + +Remember that these are controls and not functions: you can’t use dot notation (for example, the format `e.isX()` will not work). + +## Constants {#constants} +|Name |Meaning | +|-|-| +| true | The boolean constant true | +| false | The boolean constant false | +| PI | From [Java's Math.PI](https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#PI), the value of pi (that is, 3.1415...) | \ No newline at end of file diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/grelfunctions.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/grelfunctions.md new file mode 100644 index 000000000..e156d4b3b --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/grelfunctions.md @@ -0,0 +1,531 @@ +--- +id: grelfunctions +title: GREL functions +sidebar_label: GREL functions +--- + +## Reading this reference {#reading-this-reference} + +For the reference below, the function is given in full-length notation and the in-text examples are written in dot notation. Shorthands are used to indicate the kind of [data type](exploring#data-types) used in each function: s for string, b for boolean, n for number, d for date, a for array, p for a regex pattern, and o for object (meaning any data type), as well as “null†and “error†data types. + +If a function can take more than one kind of data as input or can output more than one kind of data, that is indicated with more than one letter (as with “s or aâ€) or with o for object, meaning it can take any type of data (string, boolean, date, number, etc.). + +We also use shorthands for substring (“subâ€) and separator string (“sepâ€). +Optional arguments will say “(optional)â€. + +In places where OpenRefine will accept a string (s) or a regex pattern (p), you can supply a string by putting it in quotes. If you wish to use any [regex](expressions#regular-expressions) notation, wrap the pattern in forward slashes. + +## Boolean functions {#boolean-functions} + +###### and(b1, b2, ...) {#andb1-b2-} + +Uses the logical operator AND on two or more booleans to output a boolean. Evaluates multiple statements into booleans, then returns true if all of the statements are true. For example, `(1 < 3).and(1 < 0)` returns false because one condition is true and one is false. + +###### or(b1, b2, ...) {#orb1-b2-} + +Uses the logical operator OR on two or more booleans to output a boolean. For example, `(1 < 3).or(1 > 7)` returns true because at least one of the conditions (the first one) is true. + +###### not(b) {#notb} + +Uses the logical operator NOT on a boolean to output a boolean. For example, `not(1 > 7)` returns true because 1 > 7 itself is false. + +###### xor(b1, b2, ...) {#xorb1-b2-} + +Uses the logical operator XOR (exclusive-or) on two or more booleans to output a boolean. Evaluates multiple statements, then returns true if only one of them is true. For example, `(1 < 3).xor(1 < 7)` returns false because more than one of the conditions is true. + +## String functions {#string-functions} + +###### length(s) {#lengths} + +Returns the length of string s as a number. + +###### toString(o, string format (optional)) {#tostringo-string-format-optional} + +Takes any value type (string, number, date, boolean, error, null) and gives a string version of that value. + +You can use toString() to convert numbers to strings with rounding, using an [optional string format](https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html). For example, if you applied the expression `value.toString("%.0f")` to a column: + +|Input|Output| +|-|-| +|3.2|3| +|0.8|1| +|0.15|0| +|100.0|100| + +You can also convert dates to strings, using date parsing syntax built in to OpenRefine (see [the toDate() function for details](#todateo-boolean-month_first--format1-format2--)). For example, `value.toString("MMM-dd-yyyy")` would convert the date value [2024-10-15T00:00:00Z] to “Oct-15-2024â€. + +Note: In OpenRefine, using toString() on a null cell outputs the string “nullâ€. + +### Testing string characteristics {#testing-string-characteristics} + +###### startsWith(s, sub) {#startswiths-sub} + +Returns a boolean indicating whether s starts with sub. For example, `"food".startsWith("foo")` returns true, whereas `"food".startsWith("bar")` returns false. + +###### endsWith(s, sub) {#endswiths-sub} + +Returns a boolean indicating whether s ends with sub. For example, `"food".endsWith("ood")` returns true, whereas `"food".endsWith("odd")` returns false. + +###### contains(s, sub or p) {#containss-sub-or-p} + +Returns a boolean indicating whether s contains sub, which is either a substring or a regex pattern. For example, `"food".contains("oo")` returns true whereas `"food".contains("ee")` returns false. + +You can search for a regular expression by wrapping it in forward slashes rather than quotes: `"rose is a rose".contains(/\s+/)` returns true. startsWith() and endsWith() can only take strings, while contains() can take a regex pattern, so you can use contains() to look for beginning and ending string patterns. + +### Basic string modification {#basic-string-modification} + +#### Case conversion {#case-conversion} + +###### toLowercase(s) {#tolowercases} + +Returns string s converted to all lowercase characters. + +###### toUppercase(s) {#touppercases} + +Returns string s converted to all uppercase characters. + +###### toTitlecase(s) {#totitlecases} + +Returns string s converted into titlecase: a capital letter starting each word, and the rest of the letters lowercase. For example, `"Once upon a midnight DREARY".toTitlecase()` returns the string “Once Upon A Midnight Drearyâ€. + +#### Trimming {#trimming} + +###### trim(s) {#trims} + +Returns a copy of the string s with leading and trailing whitespace removed. For example, `" island ".trim()` returns the string “islandâ€. Identical to strip(). + +###### strip(s) {#strips} + +Returns a copy of the string s with leading and trailing whitespace removed. For example, `" island ".strip()` returns the string “islandâ€. Identical to trim(). + +###### chomp(s, sep) {#chomps-sep} + +Returns a copy of string s with the string sep removed from the end if s ends with sep; otherwise, just returns s. For example, `"barely".chomp("ly")` and `"bare".chomp("ly")` both return the string “bareâ€. + +#### Substring {#substring} + +###### substring(s, n from, n to (optional)) {#substrings-n-from-n-to-optional} + +Returns the substring of s starting from character index from, and up to (excluding) character index to. If the to argument is omitted, substring will output to the end of s. For example, `"profound".substring(3)` returns the string “foundâ€, and `"profound".substring(2, 4)` returns the string “ofâ€. + +Remember that character indices start from zero. A negative character index counts from the end of the string. For example, `"profound".substring(0, -1)` returns the string “profounâ€. + +###### slice(s, n from, n to (optional)) {#slices-n-from-n-to-optional} + +Identical to substring() in relation to strings. Also works with arrays; see [Array functions section](#slicea-n-from-n-to-optional). + +###### get(s, n from, n to (optional)) {#gets-n-from-n-to-optional} + +Identical to substring() in relation to strings. Also works with named fields. Also works with arrays; see [Array functions section](#geta-n-from-n-to-optional). + +#### Find and replace {#find-and-replace} + +###### indexOf(s, sub) {#indexofs-sub} + +Returns the first character index of sub as it first occurs in s; or, returns -1 if s does not contain sub. For example, `"internationalization".indexOf("nation")` returns 5, whereas `"internationalization".indexOf("world")` returns -1. + +###### lastIndexOf(s, sub) {#lastindexofs-sub} + +Returns the first character index of sub as it last occurs in s; or, returns -1 if s does not contain sub. For example, `"parallel".lastIndexOf("a")` returns 3 (pointing at the second “aâ€). + +###### replace(s, s or p find, s replace) {#replaces-s-or-p-find-s-replace} + +Returns the string obtained by replacing the find string with the replace string in the inputted string. For example, `"The cow jumps over the moon and moos".replace("oo", "ee")` returns the string “The cow jumps over the meen and meesâ€. Find can be a regex pattern. For example, `"The cow jumps over the moon and moos".replace(/\s+/, "_")` will return “The_cow_jumps_over_the_moon_and_moosâ€. + +You cannot find or replace nulls with this, as null is not a string. You can instead: + +1. Facet by null and then bulk-edit them to a string, or +2. Transform the column with an expression such as `if(value==null,"new",value)`. + +###### replaceChars(s, s find, s replace) {#replacecharss-s-find-s-replace} + +Returns the string obtained by replacing a character in s, identified by find, with the corresponding character identified in replace. For example, `"Téxt thát was optícálly recógnízéd".replaceChars("áéíóú", "aeiou")` returns the string “Text that was optically recognizedâ€. You cannot use this to replace a single character with more than one character. + +###### find(s, sub or p) {#finds-sub-or-p} + +Outputs an array of all consecutive substrings inside string s that match the substring or [regex](expressions#grel-supported-regex) pattern p. For example, `"abeadsabmoloei".find(/[aeio]+/)` would result in the array [ "a", "ea", "a", "o", "oei" ]. + +You can supply a substring instead of p, by putting it in quotes, and OpenRefine will compile it into a regex pattern. Anytime you supply quotes, OpenRefine interprets the contents as a string, not regex. If you wish to use any regex notation, wrap the pattern in forward slashes. + +###### match(s, p) {#matchs-p} + +Attempts to match the string s in its entirety against the [regex](expressions#grel-supported-regex) pattern p and, if the pattern is found, outputs an array of all [capturing groups](https://www.regular-expressions.info/brackets.html) (found in order). For example, `"230.22398, 12.3480".match(/.*(\d\d\d\d)/)` returns an array of 1 substring: [ "3480" ]. It does not find 2239 as the first sequence with four digits, because the regex indicates the four digits must come at the end of the string. + +You will need to convert the array to a string to store it in a cell, with a function such as toString(). An empty array [] is returned when there is no match to the desired substrings. A null is output when the entire regex does not match. + +Remember to enclose your regex in forward slashes, and to escape characters and use parentheses as needed. Parentheses denote a desired substring (capturing group); for example, “.*(\d\d\d\d)†would return an array containing a single value, while “(.*)(\d\d\d\d)†would return two. So, if you are looking for a desired substring anywhere within a string, use the syntax `value.match(/.*(desired-substring-regex).*/)`. + +For example, if `value` is “hello 123456 goodbyeâ€, the following would occur: + +|Expression|Result| +|-|-| +|`value.match(/\d{6}/)` |null (does not match the full string)| +|`value.match(/.*\d{6}.*/)` |[ ] (no indicated substring)| +|`value.match(/.*(\d{6}).*/)` |[ "123456" ] (array with one value)| +|`value.match(/(.*)(\d{6})(.*)/)` |[ "hello ", "123456", " goodbye" ] (array with three values)| + +### String parsing and splitting {#string-parsing-and-splitting} + +###### toNumber(s) {#tonumbers} + +Returns a string converted to a number. Will attempt to convert other formats into a string, then into a number. If the value is already a number, it will return the number. + +###### split(s, s or p sep, b preserveTokens (optional)) {#splits-s-or-p-sep-b-preservetokens-optional} + +Returns the array of strings obtained by splitting s by sep. The separator can be either a string or a regex pattern. For example, `"fire, water, earth, air".split(",")` returns an array of 4 strings: [ "fire", " water", " earth", " air" ]. Note that the space characters are retained but the separator is removed. If you include “true†for the preserveTokens boolean, empty segments are preserved. + +###### splitByLengths(s, n1, n2, ...) {#splitbylengthss-n1-n2-} + +Returns the array of strings obtained by splitting s into substrings with the given lengths. For example, `"internationalization".splitByLengths(5, 6, 3)` returns an array of 3 strings: [ "inter", "nation", "ali" ]. Excess characters are discarded. + +###### smartSplit(s, s or p sep (optional)) {#smartsplits-s-or-p-sep-optional} + +Returns the array of strings obtained by splitting s by sep, or by guessing either tab or comma separation if there is no sep given. Handles quotes properly and understands cancelled characters. The separator can be either a string or a regex pattern. For example, `value.smartSplit("\n")` will split at a carriage return or a new-line character. + +Note: [`value.escape('javascript')`](#escapes-s-mode) is useful for previewing unprintable characters prior to using smartSplit(). + +###### splitByCharType(s) {#splitbychartypes} + +Returns an array of strings obtained by splitting s into groups of consecutive characters each time the characters change [Unicode categories](https://en.wikipedia.org/wiki/Unicode_character_property#General_Category). For example, `"HenryCTaylor".splitByCharType()` will result in an array of [ "H", "enry", "CT", "aylor" ]. It is useful for separating letters and numbers: `"BE1A3E".splitByCharType()` will result in [ "BE", "1", "A", "3", "E" ]. + +###### partition(s, s or p fragment, b omitFragment (optional)) {#partitions-s-or-p-fragment-b-omitfragment-optional} + +Returns an array of strings [ a, fragment, z ] where a is the substring within s before the first occurrence of fragment, and z is the substring after fragment. Fragment can be a string or a regex. For example, `"internationalization".partition("nation")` returns 3 strings: [ "inter", "nation", "alization" ]. If s does not contain fragment, it returns an array of [ s, "", "" ] (the original unpartitioned string, and two empty strings). + +If the omitFragment boolean is true, for example with `"internationalization".partition("nation", true)`, the fragment is not returned. The output is [ "inter", "alization" ]. + +You can use regex for your fragment. The expresion `"abcdefgh".partition(/c.e/)` will output [“abcâ€, "cde", defgh†]. + +###### rpartition(s, s or p fragment, b omitFragment (optional)) {#rpartitions-s-or-p-fragment-b-omitfragment-optional} + +Returns an array of strings [ a, fragment, z ] where a is the substring within s before the last occurrence of fragment, and z is the substring after the last instance of fragment. (Rpartition means “reverse partition.â€) For example, `"parallel".rpartition("a")` returns 3 strings: [ "par", "a", "llel" ]. Otherwise works identically to partition() above. + +### Encoding and hashing {#encoding-and-hashing} + +###### diff(s1, s2, s timeUnit (optional)) {#diffs1-s2-s-timeunit-optional} + +Takes two strings and compares them, returning a string. Returns the remainder of s2 starting with the first character where they differ. For example, `"cacti".diff("cactus")` returns "us". Also works with dates; see [Date functions](#diffd1-d2-s-timeunit). + +###### escape(s, s mode) {#escapes-s-mode} + +Escapes s in the given escaping mode. The mode can be one of: "html", "xml", "csv", "url", "javascript". Note that quotes are required around your mode. See the [recipes](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#question-marks--showing-in-your-data) for examples of escaping and unescaping. + +###### unescape(s, s mode) {#unescapes-s-mode} + +Unescapes s in the given escaping mode. The mode can be one of: "html", "xml", "csv", "url", "javascript". Note that quotes are required around your mode. See the [recipes](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#atampampt----att) for examples of escaping and unescaping. + +###### md5(o) {#md5o} + +Returns the [MD5 hash](https://en.wikipedia.org/wiki/MD5) of an object. If fed something other than a string (array, number, date, etc.), md5() will convert it to a string and deliver the hash of the string. For example, `"internationalization".md5()` will return 2c55a1626e31b4e373ceedaa9adc12a3. + +###### sha1(o) {#sha1o} + +Returns the [SHA-1 hash](https://en.wikipedia.org/wiki/SHA-1) of an object. If fed something other than a string (array, number, date, etc.), sha1() will convert it to a string and deliver the hash of the string. For example, `"internationalization".sha1()` will return cd05286ee0ff8a830dbdc0c24f1cb68b83b0ef36. + +###### phonetic(s, s encoding) {#phonetics-s-encoding} + +Returns a phonetic encoding of a string, based on an available phonetic algorithm. See the [section on phonetic clustering](cellediting#clustering-methods) for more information. Can be one of the following supported phonetic methods: [metaphone, doublemetaphone, metaphone3](https://www.wikipedia.org/wiki/Metaphone), [soundex](https://en.wikipedia.org/wiki/Soundex), [cologne](https://en.wikipedia.org/wiki/Cologne_phonetics). Quotes are required around your encoding method. For example, `"Ruth Prawer Jhabvala".phonetic("metaphone")` outputs the string “R0PRWRJHBFLâ€. + +###### reinterpret(s, s encoderTarget, s encoderSource) {#reinterprets-s-encodertarget-s-encodersource} + +Returns s reinterpreted through the given character encoders. You must supply one of the [supported encodings](http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html) for each of the original source and the target output. Note that quotes are required around your character encoder. + +When an OpenRefine project is started, data is imported and interpreted. A specific character encoding is identified or manually selected at that time (such as UTF-8). You can reinterpret a column into another specificed encoding using this function. This function may not fix your data; it may be better to use this in conjunction with new projects to test the interpretation, and pre-format your data as needed. + +###### fingerprint(s) {#fingerprints} + +Returns the fingerprint of s, a string that is the first step in [fingerprint clustering methods](cellediting#clustering-methods): it will trim whitespaces, convert all characters to lowercase, remove punctuation, sort words alphabetically, etc. For example, `"Ruth Prawer Jhabvala".fingerprint()` outputs the string “jhabvala prawer ruthâ€. + +###### ngram(s, n) {#ngrams-n} + +Returns an array of the word n-grams of s. That is, it lists all the possible consecutive combinations of n words in the string. For example, `"Ruth Prawer Jhabvala".ngram(2)` would output the array [ "Ruth Prawer", "Prawer Jhabvala" ]. A word n-gram of 1 simply lists all the words in original order; an n-gram larger than the number of words in the string will only return the original string inside an array (e.g. `"Ruth Prawer Jhabvala".ngram(4)` would simply return ["Ruth Prawer Jhabvala"]). + +###### ngramFingerprint(s, n) {#ngramfingerprints-n} + +Returns the [n-gram fingerprint](cellediting#clustering-methods) of s. For example, `"banana".ngram(2)` would output “anbanaâ€, after first generating the 2-grams “ba an na an naâ€, removing duplicates, and sorting them alphabetically. + +###### unicode(s) {#unicodes} + +Returns an array of strings describing each character of s in their full unicode notation. For example, `"Bernice Rubens".unicode()` outputs [ 66, 101, 114, 110, 105, 99, 101, 32, 82, 117, 98, 101, 110, 115 ]. + +###### unicodeType(s) {#unicodetypes} + +Returns an array of strings describing each character of s by their unicode type. For example, `"Bernice Rubens".unicodeType()` outputs [ "uppercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "space separator", "uppercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter" ]. + +## Format-based functions (JSON, HTML, XML) {#format-based-functions-json-html-xml} + +###### jsonize(o) {#jsonizeo} + +Quotes a value as a JSON literal value. + +###### parseJson(s) {#parsejsons} + +Parses a string as JSON. get() can then be used with parseJson(): for example, `parseJson(" { 'a' : 1 } ").get("a")` returns 1. + +For example, from the following JSON array in `value`, we want to get all instances of “keywords†having the same object string name of “textâ€, and combine them, using the forEach() function to iterate over the array. + + { + "status":"OK", + "url":"", + "language":"english", + "keywords":[ + { + "text":"York en route", + "relevance":"0.974363" + }, + { + "text":"Anthony Eden", + "relevance":"0.814394" + }, + { + "text":"President Eisenhower", + "relevance":"0.700189" + } + ] + } + +The GREL expression `forEach(value.parseJson().keywords,v,v.text).join(":::")` will output “York en route:::Anthony Eden:::President Eisenhowerâ€. + +### Jsoup XML and HTML parsing {#jsoup-xml-and-html-parsing} + +###### parseHtml(s) {#parsehtmls} +Given a cell full of HTML-formatted text, parseHtml() simplifies HTML tags (such as by removing “ /†at the end of self-closing tags), closes any unclosed tags, and inserts linebreaks and indents for cleaner code. You cannot pass parseHtml() a URL, but you can pre-fetch HTML with the [Add column by fetching URLs](columnediting#add-column-by-fetching-urls) menu option. + +A cell cannot store the output of parseHtml() unless you convert it with toString(): for example, `value.parseHtml().toString()`. + +When parseHtml() simplifies HTML, it can sometimes introduce errors. When closing tags, it makes its best guesses based on line breaks, indentation, and the presence of other tags. You may need to manually check the results. + +You can then extract or [select()](#selects-element) which portions of the HTML document you need for further splitting, partitioning, etc. An example of extracting all table rows from a div using parseHtml().select() together is described more in depth at [StrippingHTML](https://github.com/OpenRefine/OpenRefine/wiki/StrippingHTML). + +###### parseXml(s) {#parsexmls} +Given a cell full of XML-formatted text, parseXml() returns a full XML document and adds any missing closing tags. You can then extract or [select()](#selects-element) which portions of the XML document you need for further splitting, partitioning, etc. Functions the same way as parseHtml() is described above. + +###### select(s, element) {#selects-element} +Returns an array of all the desired elements from an HTML or XML document, if the element exists. Elements are identified using the [Jsoup selector syntax](https://jsoup.org/apidocs/org/jsoup/select/Selector.html). For example, `value.parseHtml().select("img.portrait")[0]` would return the entirety of the first “img†tag with the “portrait†class found in the parsed HTML inside `value`. Returns an empty array if no matching element is found. Use with toString() to capture the results in a cell. A tutorial of select() is shown in [StrippingHTML](https://github.com/OpenRefine/OpenRefine/wiki/StrippingHTML). + +You can use select() more than once: + +``` +value.parseHtml().select("div#content")[0].select("tr").toString() +``` + +###### htmlAttr(s, element) {#htmlattrs-element} +Returns a string from an attribute on an HTML element. Use it in conjunction with parseHtml() as in the following example: `value.parseHtml().select("a.email")[0].htmlAttr("href")` would retrieve the email address attached to a link with the “email†class. + +###### xmlAttr(s, element) {#xmlattrs-element} +Returns a string from an attribute on an XML element. Functions the same way htmlAttr() is described above. Use it in conjunction with parseXml(). + +###### htmlText(element) {#htmltextelement} +Returns a string of the text from within an HTML element (including all child elements), removing HTML tags and line breaks inside the string. Use it in conjunction with parseHtml() and select() to provide an element, as in the following example: `value.parseHtml().select("div.footer")[0].htmlText()`. + +###### xmlText(element) {#xmltextelement} +Returns a string of the text from within an XML element (including all child elements). Functions the same way htmlText() is described above. Use it in conjunction with parseXml() and select() to provide an element. + +###### innerHtml(element) {#innerhtmlelement} +Returns the [inner HTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) of an HTML element. This will include text and children elements within the element selected. Use it in conjunction with parseHtml() and select() to provide an element. + +###### innerXml(element) {#innerxmlelement} +Returns the inner XML elements of an XML element. Does not return the text directly inside your chosen XML element - only the contents of its children. To select the direct text, use ownText(). To select both, use xmlText(). Use it in conjunction with parseXml() and select() to provide an element. + +###### ownText(element) {#owntextelement} +Returns the text directly inside the selected XML or HTML element only, ignoring text inside children elements (for this, use innerXml()). Use it in conjunction with a parser and select() to provide an element. + +## Array functions {#array-functions} + +###### length(a) {#lengtha} +Returns the size of an array, meaning the number of objects inside it. Arrays can be empty, in which case length() will return 0. + +###### slice(a, n from, n to (optional)) {#slicea-n-from-n-to-optional} +Returns a sub-array of a given array, from the first index provided and up to and excluding the optional last index provided. Remember that array objects are indexed starting at 0. If the to value is omitted, it is understood to be the end of the array. For example, `[0, 1, 2, 3, 4].slice(1, 3)` returns [ 1, 2 ], and `[ 0, 1, 2, 3, 4].slice(2)` returns [ 2, 3, 4 ]. Also works with strings; see [String functions](#slices-n-from-n-to-optional). + +###### get(a, n from, n to (optional)) {#geta-n-from-n-to-optional} +Returns a sub-array of a given array, from the first index provided and up to and excluding the optional last index provided. Remember that array objects are indexed starting at 0. + +If the to value is omitted, only one array item is returned, as a string, instead of a sub-array. To return a sub-array from one index to the end, you can set the to argument to a very high number such as `value.get(2,999)` or you can use something like `with(value,a,a.get(1,a.length()))` to count the length of each array. + +Also works with strings; see [String functions](#gets-n-from-n-to-optional). + +###### inArray(a, s) {#inarraya-s} +Returns true if the array contains the desired string, and false otherwise. Will not convert data types; for example, `[ 1, 2, 3, 4 ].inArray("3")` will return false. + +###### reverse(a) {#reversea} +Reverses the array. For example, `[ 0, 1, 2, 3].reverse()` returns the array [ 3, 2, 1, 0 ]. + +###### sort(a) {#sorta} +Sorts the array in ascending order. Sorting is case-sensitive, uppercase first and lowercase second. For example, `[ "al", "Joe", "Bob", "jim" ].sort()` returns the array [ "Bob", "Joe", "al", "jim" ]. + +###### sum(a) {#suma} +Return the sum of the numbers in the array. For example, `[ 2, 1, 0, 3 ].sum()` returns 6. + +###### join(a, sep) {#joina-sep} +Joins the items in the array with sep, and returns it all as a string. For example, `[ "and", "or", "not" ].join("/")` returns the string “and/or/notâ€. + +###### uniques(a) {#uniquesa} +Returns the array with duplicates removed. Case-sensitive. For example, `[ "al", "Joe", "Bob", "Joe", "Al", "Bob" ].uniques()` returns the array [ "Joe", "al", "Al", "Bob" ]. + +As of OpenRefine 3.4.1, uniques() reorders the array items it returns; in 3.4 beta 644 and onwards, it preserves the original order (in this case, [ "al", "Joe", "Bob", "Al" ]). + +## Date functions {#date-functions} + +###### now() {#now} + +Returns the current time according to your system clock, in the [ISO 8601 extended format](exploring#data-types) (converted to UTC). For example, 10:53am (and 00 seconds) on November 26th 2020 in EST returns [date 2020-11-26T15:53:00Z]. + +###### toDate(o, b monthFirst, s format1, s format2, ...) {#todateo-b-monthfirst-s-format1-s-format2-} + +Returns the inputted object converted to a date object. Without arguments, it returns the ISO 8601 extended format. With arguments, you can control the output format: +* monthFirst: set false if the date is formatted with the day before the month. +* formatN: attempt to parse the date using an ordered list of possible formats. Supply formats based on the [SimpleDateFormat](https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html) syntax (and see the table below for a handy reference). + +For example, you can parse a column containing dates in different formats, such as cells with “Nov-09†and “11/09â€, using `value.toDate('MM/yy','MMM-yy').toString('yyyy-MM')` and both will output “2009-11â€. For another example, “1/4/2012 13:30:00†can be parsed into a date using `value.toDate('d/M/y H:m:s')`. + +| Letter | Date or Time Component | Presentation | Examples | +|-|-|-|-| +| G | Era designator | Text | AD | +| y | Year | Year | 1996; 96 | +| Y | [Week year](https://en.wikipedia.org/wiki/ISO_week_date#First_week) | Year | 2009; 09 | +| M | Month in year | Month | July; Jul; 07 | +| w | Week in year | Number | 27 | +| W | Week in month | Number | 2 | +| D | Day in year | Number | 189 | +| d | Day in month | Number | 10 | +| F | Day of week in month | Number | 2 | +| E | Day name in week | Text | Tuesday; Tue | +| u | Day number of week (1 = Monday, ..., 7 = Sunday) | Number | 1 | +| a | AM/PM marker | Text | PM | +| H | Hour in day (0-23) | Number | 0 | +| k | Hour in day (1-24) | Number | 24 | +| K | Hour in AM/PM (0-11) | Number | 0 | +| h | Hour in AM/PM (1-12) | Number | 12 | +| m | Minute in hour | Number | 30 | +| s | Second in minute | Number | 55 | +| S | Millisecond | Number | 978 | +| n | Nanosecond | Number | 789000 | +| z | Time zone | General time zone | Pacific Standard Time; PST; GMT-08:00 | +| Z | Time zone | RFC 822 time zone | \-0800 | +| X | Time zone | ISO 8601 time zone | \-08; -0800; -08:00 | + +###### diff(d1, d2, s timeUnit) {#diffd1-d2-s-timeunit} + +Given two dates, returns a number indicating the difference in a given time unit (see the table below). For example, `diff(("Nov-11".toDate('MMM-yy')), ("Nov-09".toDate('MMM-yy')), "weeks")` will return 104, for 104 weeks, or two years. The later date should go first. If the output is negative, invert d1 and d2. + +Also works with strings; see [diff() in string functions](#diffsd1-sd2-s-timeunit-optional). + +###### inc(d, n, s timeUnit) {#incd-n-s-timeunit} + +Returns a date changed by the given amount in the given unit of time (see the table below). The default unit is “hourâ€. A positive value increases the date, and a negative value moves it back in time. For example, if you want to move a date backwards by two months, use `value.inc(-2,"month")`. + +###### datePart(d, s timeUnit) {#datepartd-s-timeunit} + +Returns part of a date. The data type returned depends on the unit (see the table below). + +OpenRefine supports the following values for timeUnit: + +| Unit | Date part returned | Returned data type | Example using [date 2014-03-14T05:30:04.000789000Z] as value | +|-|-|-|-| +| years | Year | Number | value.datePart("years") → 2014 | +| year | Year | Number | value.datePart("year") → 2014 | +| months | Month | Number | value.datePart("months") → 2 | +| month | Month | Number | value.datePart("month") → 2 | +| weeks | Week of the month | Number | value.datePart("weeks") → 3 | +| week | Week of the month | Number | value.datePart("week") → 3 | +| w | Week of the month | Number | value.datePart("w") → 3 | +| weekday | Day of the week | String | value.datePart("weekday") → Friday | +| hours | Hour | Number | value.datePart("hours") → 5 | +| hour | Hour | Number | value.datePart("hour") → 5 | +| h | Hour | Number | value.datePart("h") → 5 | +| minutes | Minute | Number | value.datePart("minutes") → 30 | +| minute | Minute | Number | value.datePart("minute") → 30 | +| min | Minute | Number | value.datePart("min") → 30 | +| seconds | Seconds | Number | value.datePart("seconds") → 04 | +| sec | Seconds | Number | value.datePart("sec") → 04 | +| s | Seconds | Number | value.datePart("s") → 04 | +| milliseconds | Millseconds | Number | value.datePart("milliseconds") → 789 | +| ms | Millseconds | Number | value.datePart("ms") → 789 | +| S | Millseconds | Number | value.datePart("S") → 789 | +| n | Nanoseconds | Number | value.datePart("n") → 789000 | +| nano | Nanoseconds | Number | value.datePart("n") → 789000 | +| nanos | Nanoseconds | Number | value.datePart("n") → 789000 | +| time | Milliseconds between input and the [Unix Epoch](https://en.wikipedia.org/wiki/Unix_time) | Number | value.datePart("time") → 1394775004000 | + +## Math functions {#math-functions} + +For integer division and precision, you can use simple evaluations such as `1 / 2`, which is equivalent to `floor(1/2)` - that is, it returns only whole number results. If either operand is a floating point number, they both get promoted to floating point and a floating point result is returned. You can use `1 / 2.0` or `1.0 / 2` or `1.0 * x / y` (if you're working with variables of unknown contents). + +:::caution +Some of these math functions don't recognize integers when supplied as the first argument in dot notation (e.g., `5.cos()` simply returns 5 instead of the expected result). To ensure operations are successful, always wrap the first argument in brackets, such as `(value).cos()`. +::: + +|Function|Use|Example| +|-|-|-| +|`abs(n)`|Returns the absolute value of a number.|`abs(-6)` returns 6.| +|`acos(n)`|Returns the arc cosine of an angle, in the range 0 through [PI](https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#PI).|`acos(0.345)` returns 1.218557541697832.| +|`asin(n)`|Returns the arc sine of an angle in the range of -PI/2 through PI/2.|`asin(0.345)` returns 0.35223878509706474.| +|`atan(n)`|Returns the arc tangent of an angle in the range of -PI/2 through PI/2.|`atan(0.345)` returns 0.3322135507465967.| +|`atan2(n1, n2)`|Converts rectangular coordinates (n1, n2) to polar (r, theta). Returns number theta.|`atan2(0.345,0.6)` returns 0.5218342798144103.| +|`ceil(n)`|Returns the ceiling of a number.|`3.7.ceil()` returns 4 and `-3.7.ceil()` returns -3.| +|`combin(n1, n2)`|Returns the number of combinations for n2 elements as divided into n1.|`combin(20,2)` returns 190.| +|`cos(n)`|Returns the trigonometric cosine of a value.|`cos(5)` returns 0.28366218546322625.| +|`cosh(n)`|Returns the hyperbolic cosine of a value.|`cosh(5)` returns 74.20994852478785.| +|`degrees(n)`|Converts an angle from radians to degrees.|`degrees(5)` returns 286.4788975654116.| +|`even(n)`|Rounds the number up to the nearest even integer.|`even(5)` returns 6.| +|`exp(n)`|Returns [e](https://en.wikipedia.org/wiki/E_(mathematical_constant)) raised to the power of n.|`exp(5)` returns 148.4131591025766.| +|`fact(n)`|Returns the factorial of a number, starting from 1.|`fact(5)` returns 120.| +|`factn(n1, n2)`|Returns the factorial of n1, starting from n2.|`factn(10,3)` returns 280.| +|`floor(n)`|Returns the floor of a number.|`3.7.floor()` returns 3 and `-3.7.floor()` returns -4.| +|`gcd(n1, n2)`|Returns the greatest common denominator of two numbers.|`gcd(95,135)` returns 5.| +|`lcm(n1, n2)`|Returns the least common multiple of two numbers.|`lcm(95,135)` returns 2565.| +|`ln(n)`|Returns the natural logarithm of n.|`ln(5)` returns 1.6094379124341003.| +|`log(n)`|Returns the base 10 logarithm of n.|`log(5)` returns 0.6989700043360189.| +|`max(n1, n2)`|Returns the larger of two numbers.|`max(3,10)` returns 10.| +|`min(n1, n2)`|Returns the smaller of two numbers.|`min(3,10)` returns 3.| +|`mod(n1, n2)`|Returns n1 modulus n2. Note: `value.mod(9)` will work, whereas `74.mod(9)` will not work.|`mod(74, 9)` returns 2. | +|`multinomial(n1, n2 …(optional))`|Calculates the multinomial of one number or a series of numbers.|`multinomial(2,3)` returns 10.| +|`odd(n)`|Rounds the number up to the nearest odd integer.|`odd(10)` returns 11.| +|`pow(n1, n2)`|Returns n1 raised to the power of n2. Note: value.pow(3)` will work, whereas `2.pow(3)` will not work.|`pow(2, 3)` returns 8 (2 cubed) and `pow(3, 2)` returns 9 (3 squared). The square root of any numeric value can be called with `value.pow(0.5)`.| +|`quotient(n1, n2)`|Returns the integer portion of a division (truncated, not rounded), when supplied with a numerator and denominator.|`quotient(9,2)` returns 4.| +|`radians(n)`|Converts an angle in degrees to radians.|`radians(10)` returns 0.17453292519943295.| +|`randomNumber(n lowerBound, n upperBound)`|Returns a random integer in the interval between the lower and upper bounds (inclusively). Will output a different random number in each cell in a column.| +|`round(n)`|Rounds a number to the nearest integer.|`3.7.round()` returns 4 and `-3.7.round()` returns -4.| +|`sin(n)`|Returns the trigonometric sine of an angle.|`sin(10)` returns -0.5440211108893698.| +|`sinh(n)`|Returns the hyperbolic sine of an angle.|`sinh(10)` returns 11013.232874703393.| +|`sum(a)`|Sums the numbers in an array. Ignores non-number items. Returns 0 if the array does not contain numbers.|`sum([ 10, 2, three ])` returns 12.| +|`tan(n)`|Returns the trigonometric tangent of an angle.|`tan(10)` returns 0.6483608274590866.| +|`tanh(n)`|Returns the hyperbolic tangent of a value.|`tanh(10)` returns 0.9999999958776927.| + +## Other functions {#other-functions} + +###### type(o) {#typeo} +Returns a string with the data type of o, such as undefined, string, number, boolean, etc. For example, a [Transform](cellediting#transform) operation using `value.type()` will convert all cells in a column to strings of their data types. + +###### facetCount(choiceValue, s facetExpression, s columnName) {#facetcountchoicevalue-s-facetexpression-s-columnname} +Returns the facet count corresponding to the given choice value, by looking for the facetExpression in the choiceValue in columnName. For example, to create facet counts for the following table, we could generate a new column based on “Gift†and enter in `value.facetCount("value", "Gift")`. This would add the column we've named “Countâ€: + +| Gift | Recipient | Price | Count | +|-|-|-|-| +| lamp | Mary | 20 | 1 | +| clock | John | 57 | 2 | +| watch | Amit | 80 | 1 | +| clock | Claire | 62 | 2 | + +The facet expression, wrapped in quotes, can be useful to manipulate the inputted values before counting. For example, you could do a textual cleanup using fingerprint(): `(value.fingerprint()).facetCount(value.fingerprint(),"Gift")`. + +###### hasField(o, s name) {#hasfieldo-s-name} +Returns a boolean indicating whether o has a member field called [name](expressions#variables). For example, `cell.recon.hasField("match")` will return false if a reconciliation match hasn’t been selected yet, or true if it has. You cannot chain your desired fields: for example, `cell.hasField("recon.match")` will return false even if the above expression returns true). + +###### coalesce(o1, o2, o3, ...) {#coalesceo1-o2-o3-} +Returns the first non-null from a series of objects. For example, `coalesce(value, "")` would return an empty string Ҡif `value` was null, but otherwise return `value`. + +###### cross(cell, s projectName, s columnName) {#crosscell-s-projectname-s-columnname} +Returns an array of zero or more rows in the project projectName for which the cells in their column columnName have the same content as the cell in your chosen column. For example, if two projects contained matching names, and you wanted to pull addresses for people by their names from a project called “People†you would apply the following expression to your column of names: +``` +cell.cross("People","Name").cells["Address"].value[0] +``` + +This would match your current column to the “Name†column in “People†and, using those matches, pull the respective “Address†value into your current project. + +You may need to do some data preparation with cross(), such as using trim() on your key columns or deduplicating values. + +The first argument will be interpreted as `cell.value` if set to `cell`. + +Recipes and more examples for using cross() can be found [on our wiki](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#combining-datasets). diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/installing.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/installing.md new file mode 100644 index 000000000..0dd2618c2 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/installing.md @@ -0,0 +1,425 @@ +--- +id: installing +title: Installing OpenRefine +sidebar_label: Installing +--- + +## System requirements {#system-requirements} + +OpenRefine does not require internet access to run its basic functions. Once you download and install it, it runs as a small web server on your own computer, and you access that local web server by using your browser. It only requires an internet connection to import data from the web, reconcile data using a web service, or export data to the web. + +OpenRefine requires three things on your computer in order to function: + +#### Compatible operating system {#compatible-operating-system} + +OpenRefine is designed to work with **Windows**, **Mac**, and **Linux** operating systems. [Our team releases packages for each](https://openrefine.org/download.html). + +#### Java {#java} + +[Java](https://java.com/en/download/) must be installed and configured on your computer to run OpenRefine. The Mac version of OpenRefine includes Java; new in OpenRefine 3.4, there is also a Windows package with Java included. + +If you install and start OpenRefine on a Windows computer without Java, it will automatically open up a browser window to the [Java downloads page](https://java.com/en/download/), and you can simply follow the instructions there. + +We recommend you [download](https://java.com/en/download/) and install Java before proceeding with the OpenRefine installation. Please note that OpenRefine works with Java 8 to Java 15 but not Java 16 or later versions. + +#### Compatible browser {#compatible-browser} + +OpenRefine works best on browsers based on Webkit, such as: + +* Google Chrome +* Chromium +* Opera +* Microsoft Edge + +We are aware of some minor rendering and performance issues on other browsers such as Firefox. We don't support Internet Explorer. If you are having issues running OpenRefine, see the [section on Running](running.md#troubleshooting). + +### Release versions {#release-versions} + +OpenRefine always has a [latest stable release](https://github.com/OpenRefine/OpenRefine/releases/latest), as well as some more recent developments available in beta, release candidate, or [snapshot releases](https://github.com/OpenRefine/OpenRefine-snapshot-releases/releases). If you are installing for the first time, we recommend [the latest stable release](https://github.com/OpenRefine/OpenRefine/releases/latest). + +If you wish to use an extension that is only compatible with an earlier version of OpenRefine, and do not require the latest features, you may find that [an older stable version is best for you](https://github.com/OpenRefine/OpenRefine/releases) in our list of releases. Look at later releases to see which security vulnerabilities are being fixed, in order to assess your own risk tolerance for using earlier versions. Look for “final release†versions instead of “beta†or “release candidate†versions. + +#### Unstable versions {#unstable-versions} + +If you need a recently developed function, and are willing to risk some untested code, you can look at [the most recent items in the list](https://github.com/OpenRefine/OpenRefine/releases) and see what changes appeal to you. + +“Beta†and “release candidate†versions may both have unreported bugs and are most suitable for people who are willing to help us troubleshoot these versions by [creating bug reports](https://github.com/OpenRefine/OpenRefine/issues). + +For the absolute latest development updates, see the [snapshot releases](https://github.com/OpenRefine/OpenRefine-snapshot-releases/releases). These are created with every commit. + +#### What’s changed {#whats-changed} + +Our [latest version is OpenRefine 3.4.1](https://github.com/OpenRefine/OpenRefine/releases/tag/3.4.1), released September 24th 2020. The major changes in this version are listed on the [3.4.1 release page](https://github.com/OpenRefine/OpenRefine/releases/tag/3.4.1) with the downloadable packages. + +You can find information about all OpenRefine versions on the [Releases page on Github](https://github.com/OpenRefine/OpenRefine/releases). + +:::info Other distributions +OpenRefine may also work in other environments, such as [Chromebooks](https://gist.github.com/organisciak/3e12e5138e44a2fed75240f4a4985b4f) where Linux terminals are available. Look at our list of [Other Distributions on the Downloads page](https://openrefine.org/download.html) for other ways of running OpenRefine, and refer to our contributor community to see new environments in development. +::: + +## Installing or upgrading {#installing-or-upgrading} +### Back up your data {#back-up-your-data} + +If you are upgrading from an older version of OpenRefine and have projects already on your computer, you should create backups of those projects before you install a new version. + +First, [locate your workspace directory](#where-is-data-stored). Then copy everything you find there and paste it into a folder elsewhere on your computer. + +For extra security you can [export your existing OpenRefine projects](exporting#export-a-project). + +:::caution +Take note of the [extensions](#installing-extensions) you have currently installed. They may not be compatible with the upgraded version of OpenRefine. Installations can be installed in two places, so be sure to check both your workspace directory and the existing installation directory. +::: + +### Install or upgrade OpenRefine {#install-or-upgrade-openrefine} + +If you are upgrading an existing OpenRefine installation, you can delete the old program files and install the new files into the same space. Do not overwrite the files as some obsolete files may be left over unnecessarily. + +:::caution +If you have extensions installed, do not delete the `webapp\extensions` folder where you installed them. You may wish to install extensions into the workspace directory instead of the program directory. There is no guarantee that extensions will be forward-compatible with new versions of OpenRefine, and we do not maintain extensions. +::: + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + + +Once you have downloaded the `.zip` file, extract it into a folder where you wish to store program files (such as `D:\Program Files\OpenRefine`). + +You can right-click on `openrefine.exe` or `refine.bat` and pin one of those programs to your Start Menu or create shortcuts for easier access. + + + + + +Once you have downloaded the `.dmg` file, open it and drag the OpenRefine icon onto the Applications folder icon (just like you would normally install Mac applications). + + + + + +The quick version: + +1. Install [Homebrew](http://brew.sh) +2. In Terminal enter `brew install openrefine` +1. Then find OpenRefine in your Applications folder. + +The long version: + +[Homebrew](https://brew.sh) is a popular command-line package manager for Mac. Installing Homebrew is accomplished by pasting the installation command on the Homebrew website into a Terminal window. Once Homebrew is installed, applications like OpenRefine can be installed via a simple command. You can [install Homebrew from their website](https://brew.sh). + +###### Install {#install} + +Install OpenRefine with this command: + +``` +brew install openrefine +``` + +You should see output like this: + +``` +==> Downloading https://github.com/OpenRefine/OpenRefine/releases/download/3.4.1/openrefine-mac-3.4.1.dmg +######################################################################## 100.0% +==> Installing Cask openrefine +==> Moving App 'OpenRefine.app' to '/Applications/OpenRefine.app' +🺠openrefine was successfully installed! +``` + +Behind the scenes, this command causes Homebrew to download the OpenRefine installer, verify the file’s authenticity (using a SHA-256 checksum), mount the disk image, copy the `OpenRefine.app` application bundle into the Applications folder, unmount the disk image, and save a copy of the installer and metadata about the installation for future use. + +If an existing `OpenRefine.app` is found in the Applications folder, Homebrew will not overwrite it, so installing via Homebrew requires either deleting or renaming previously installed copies. + +###### Uninstall {#uninstall} + +To uninstall OpenRefine, paste this command into the Terminal: + +``` +brew uninstall openrefine +``` + +You should see output like this: + +``` +==> Uninstalling Cask openrefine +==> Backing App 'OpenRefine.app' up to '/usr/local/Caskroom/openrefine/3.4.1/OpenRefine.app' +==> Removing App '/Applications/OpenRefine.app' +==> Purging files for version 3.4.1 of Cask openrefine +``` + +###### Update {#update} + +To update to the latest version of OpenRefine, paste these two commands into the Terminal: + +``` +brew update +brew upgrade +``` + +You should see output like this: + +``` +==> Upgrading 1 outdated package: +openrefine 3.4.0-> 3.4.1 +==> Upgrading openrefine +==> Downloading https://github.com/OpenRefine/OpenRefine/releases/download/3.4.1/openrefine-mac-3.4.1.dmg +######################################################################## 100.0% +==> Backing App 'OpenRefine.app' up to '/usr/local/Caskroom/openrefine/3.4.0/OpenRefine.app' +==> Removing App '/Applications/OpenRefine.app' +==> Installing Cask openrefine +==> Moving App 'OpenRefine.app' to '/Applications/OpenRefine.app' +🺠openrefine was successfully upgraded! +``` + + + + +Once you have downloaded the `.tar.gz` file, open a shell, navigate to the folder containing the download, and type: + +``` +tar xzf openrefine-linux-3.4.tar.gz +``` + + + + + +--- + + +### Set where data is stored {#set-where-data-is-stored} + +OpenRefine stores data in two places: program files in the program directory, wherever it is you’ve installed it; and project files in what we call the “workspace directory.†You can access this folder easily from OpenRefine by going to the [home screen](running#the-home-screen) (at [http://127.0.0.1:3333/](http://127.0.0.1:3333/)) and clicking Browse workspace directory. + +By default this is: + + + + + +Depending on your version of Windows, the data is in one of these directories: +* `%appdata%\OpenRefine` +* `%localappdata%\OpenRefine` +* `C:\Documents and Settings\(user id)\Local Settings\Application Data\OpenRefine` +* `C:\Users\(user id)\AppData\Roaming\OpenRefine` +* `C:\Users\(user id)\AppData\Local\OpenRefine` +* `C:\Users\(user id)\OpenRefine` + +For older Google Refine releases, replace `OpenRefine` with `Google\Refine`. + +You can change this by adding this line to the file `openrefine.l4j.ini` and specifying your desired drive and folder path: + +``` +-Drefine.data_dir=D:\MyDesiredFolder +``` + +If your folder path has spaces, use neutral quotation marks around it: + +``` +-Drefine.data_dir="D:\My Desired Folder" +``` + +If the folder does not exist, OpenRefine will create it. + + + + + +``` +~/Library/Application Support/OpenRefine/ +``` + +For older versions, as Google Refine: + +``` +~/Library/Application Support/Google/Refine/ +``` + +Logging is to `/var/log/daemon.log` - grep for `com.google.refine.Refine`. + + + + + +``` +~/.local/share/openrefine/ +``` + +You can change this when you run OpenRefine from the terminal, by pointing to the workspace directory through the `-d` parameter: + +``` + ./refine -p 3333 -i 0.0.0.0 -m 6000M -d /My/Desired/Folder +``` + + + + + +--- + + +### Logs {#logs} + +OpenRefine does not currently output an error log, but because the OpenRefine console window is always open (on Linux and Windows) while OpenRefine runs in your browser, you can copy information from the console if an error occurs. + +Using a Mac, you can [run OpenRefine using the terminal](running#starting-and-exiting) in order to capture errors. + +--- + +## Increasing memory allocation {#increasing-memory-allocation} + +OpenRefine relies on having computer memory available to it to work effectively. If you are planning to work with large datasets, you may wish to set up OpenRefine to handle it at the outset. By “large†we generally mean one of the following indicators: +* more than one million total cells +* an input file size of more than 50 megabytes (MB) +* more than 50 [rows per record in records mode](running#records-mode) + +By default OpenRefine is set to operate with 1 gigabyte (GB) of memory (1024MB). If you feel that OpenRefine is running slowly, or you are getting “out of memory†errors (for example, `java.lang.OutOfMemoryError`), you can try allocating more memory. + +A good practice is to start with no more than 50% of whatever memory is left over after the estimated usage of your operating system, to leave memory for your browser to run. + +All of the settings below use a four-digit number to specify the megabytes (MB) used (actually [mebibytes](https://en.wikipedia.org/wiki/Mebibyte)). The default is usually 1024MB, but the new value doesn't need to be a multiple of 1024. + +:::info Dealing with large datasets +If your project is big enough to need more than the default amount of memory, consider turning off Parse cell text into numbers, dates, ... on import. It's convenient, but less efficient than explicitly converting any columns that you need as a data type other than the default “string†type. +::: + + + + + +#### Using openrefine.exe {#using-openrefineexe} + +If you run `openrefine.exe`, you will need to edit the `openrefine.l4j.ini` file found in the program directory and edit the line + +``` +# max memory memory heap size +-Xmx1024M +``` + +The line “-Xmx1024M†defines the amount of memory available in megabytes. Change the number “1024†- for example, edit the line to “-Xmx2048M†to make 2048MB [2GB] of memory available. + +:::caution openrefine.exe not running? +Once you increase the memory allocation, you may find that you cannot run `openrefine.exe`. In this case, your computer needs a 64-bit version of [Java](https://www.java.com/en/download/help/index_installing.xml) (this is different from [Java JDK](#install-or-upgrade-java). Look for the “Windows Offline (64-bit)†download on the Downloads page and install that. Your system must also be set to use the 64-bit version of Java by [changing the Java configuration](https://www.java.com/en/download/help/update_runtime_settings.xml). +::: + +#### Using refine.bat {#using-refinebat} + +On Windows, OpenRefine can also be run by using the file `refine.bat` in the program directory. If you start OpenRefine using `refine.bat`, the memory available to OpenRefine can be specified either through command line options, or through the `refine.ini` file. + +To set the maximum amount of memory on the command line when using `refine.bat`, `cd` to the program directory, then type + +```refine.bat /m 2048m``` + +where “2048†is the maximum amount of MB that you want OpenRefine to use. + +To change the default that `refine.bat` uses, edit the `refine.ini` line that reads + +```REFINE_MEMORY=1024M``` + +Note that this file is only read if you use `refine.bat`, not `openrefine.exe`. + + + + +If you have downloaded the `.dmg` package and you start OpenRefine by double-clicking on it: + +* close OpenRefine +* control-click on the OpenRefine icon (opens the contextual menu) +* click on "show package content†(a finder window opens) +* open the “Contents†folder +* open the `Info.plist` file with any text editor (like Mac's default TextEdit) +* Change “-Xmx1024M†into, for example, “-Xmx2048M†or “-Xmx8G†+* save the file +* restart OpenRefine. + + + + +If you have downloaded the `.tar.gz` package and you start OpenRefine from the command line, add the “-m xxxxM†parameter like this: +`./refine -m 2048m` + +#### Setting a default {#setting-a-default} + +If you don't want to set this option on the command line each time, you can also set it in the `refine.ini` file. Edit the line + +``` +REFINE_MEMORY=1024M +``` + +Make sure it is not commented out (that is, that the line doesn't start with a “#†character), and change “1024†to a higher value. Save the file, and when you next start OpenRefine it will use this value. + + + + + +--- + + +## Installing extensions {#installing-extensions} + +Extensions have been created by our contributor community to add functionality or provide convenient shortcuts for common uses of OpenRefine. [We list extensions we know about on our downloads page](https://openrefine.org/download.html). + +:::info Contributing extensions +If you’d like to create or modify an extension, [see our developer documentation here](https://github.com/OpenRefine/OpenRefine/wiki/Documentation-For-Developers). If you’re having a problem, [use our downloads page](https://openrefine.org/download.html) to go to the extension’s page and report the issue there. +::: + +### Two ways to install extensions {#two-ways-to-install-extensions} + +You can [install extensions in one of two places](#set-where-data-is-stored): + +* Into your OpenRefine program folder, so they will only be available to that version/installation of OpenRefine (meaning the extension will not run if you upgrade OpenRefine), or +* Into your workspace, where your projects are stored, so they will be available no matter which version of OpenRefine you’re using. + +We provide these options because you may wish to reinstall a given extension manually each time you upgrade OpenRefine, in order to be sure it works properly. + +### Find the right place to install {#find-the-right-place-to-install} + +If you want to install the extension into the program folder, go to your program directory and then go to `webapp\extensions` (or create it if not does not exist). + +If you want to install the extension into your workspace, you can: +* launch OpenRefine and click Open Project in the sidebar +* At the bottom of the screen, click Browse workspace directory +* A file-explorer or finder window will open in your workspace +* Create a new folder called “extensions†inside the workspace if it does not exist. + +You can also [find your workspace on each operating system using these instructions](#set-where-data-is-stored). + +### Install the extension {#install-the-extension} + +Some extensions have their own instructions: make sure you read the documentation before you begin installing. + +Some extensions may have multiple versions, to match OpenRefine versions, so be sure to choose the right release for your installation. If you have questions about compatibility or want to request or voice your support for an update, [use our downloads page](https://openrefine.org/download.html) to go to the extension’s page and report the issue there. + +Generally, the installation process will be: + +* Download the extension (usually as a zip file from GitHub) +* Extract the zip contents into the “extensions†directory, making sure all the contents go into one folder with the name of the extension +* Start (or restart) OpenRefine. + +To confirm that installation was a success, follow the instructions provided by the extension. Each extension will appear in its own way inside the OpenRefine interface. Make sure you read its documentation to know where the functionality will appear, such as under specific dropdown menus. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/jythonclojure.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/jythonclojure.md new file mode 100644 index 000000000..a93d18155 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/jythonclojure.md @@ -0,0 +1,76 @@ +--- +id: jythonclojure +title: Jython & Clojure +sidebar_label: Jython & Clojure +--- + +## Jython {#jython} + +Jython 2.7.2 comes bundled with the default installation of OpenRefine 3.4.1. You can add libraries and code by following [this tutorial](https://github.com/OpenRefine/OpenRefine/wiki/Extending-Jython-with-pypi-modules). A large number of Python files (`.py` or `.pyc`) are compatible. + +Python code that depends on C bindings will not work in OpenRefine, which uses Java / Jython only. Since Jython is essentially Java, you can also import Java libraries and utilize those. + +You will need to restart OpenRefine, so that new Jython or Python libraries are initialized during startup. + +OpenRefine now has [most of the Jsoup.org library built into GREL functions](grelfunctions#jsoup-xml-and-html-parsing-functions) for parsing and working with HTML and XML elements. + +### Syntax {#syntax} + +Expressions in Jython must have a `return` statement: + +``` + return value[1:-1] +``` + +``` + return rowIndex%2 +``` + +Fields have to be accessed using the bracket operator rather than dot notation: + +``` + return cells["col1"]["value"] +``` + +For example, to access the [edit distance](reconciling#reconciliation-facets) between a reconciled value and an original cell value using [recon variables](#reconciliation): + +``` + return cell["recon"]["features"]["nameLevenshtein"] +``` + +To return the lower case of `value` (if the value is not null): + +``` + if value is not None: + return value.lower() + else: + return None +``` + +### Tutorials {#tutorials} +- [Extending Jython with pypi modules](https://github.com/OpenRefine/OpenRefine/wiki/Extending-Jython-with-pypi-modules) +- [Working with phone numbers using Java libraries inside Python](https://github.com/OpenRefine/OpenRefine/wiki/Jython#tutorial---working-with-phone-numbers-using-java-libraries-inside-python) + +Full documentation on the Jython language can be found on its official site: [http://www.jython.org](http://www.jython.org). + +## Clojure {#clojure} + +Clojure 1.10.1 comes bundled with the default installation of OpenRefine 3.4.1. At this time, not all [variables](expressions#variables) can be used with Clojure expressions: only `value`, `row`, `rowIndex`, `cell`, and `cells` are available. + +For example, functions can take the form +``` +(.. value (toUpperCase) ) +``` + +Or can look like +``` +(-> value (str/split #" ") last ) +``` + +which functions like `value.split(" ")` in GREL. + +For help with syntax, see the [Clojure website's guide to syntax](https://clojure.org/guides/learn/syntax). + +User-contributed Clojure recipes can be found on our wiki at [https://github.com/OpenRefine/OpenRefine/wiki/Recipes#11-clojure](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#11-clojure). + +Full documentation on the Clojure language can be found on its official site: [https://clojure.org/](https://clojure.org/). \ No newline at end of file diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/reconciling.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/reconciling.md new file mode 100644 index 000000000..9457bf120 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/reconciling.md @@ -0,0 +1,247 @@ +--- +id: reconciling +title: Reconciling +sidebar_label: Reconciling +--- + +## Overview {#overview} +:::info +If you are interested in reconciling with Wikidata, see also [our page about Wikidata](wikidata). + +This page covers the general handling in OpenRefine for any reconciliation service. +::: + +Reconciliation is the process of matching your dataset with that of an external source. Datasets for comparison might be produced by libraries, archives, museums, academic organizations, scientific institutions, non-profits, or interest groups. You can also reconcile against user-edited data on [Wikidata](wikidata), or reconcile against [a local dataset that you yourself supply](https://github.com/OpenRefine/OpenRefine/wiki/Reconcilable-Data-Sources#local-services). + +To reconcile your OpenRefine project against an external dataset, that dataset must offer a web service that conforms to the [Reconciliation Service API standards](https://reconciliation-api.github.io/specs/0.1/). + +You may wish to reconcile in order to: +* fix spelling or variations in proper names +* clean up manually-entered subject headings against authorities such as the [Library of Congress Subject Headings](https://id.loc.gov/authorities/subjects.html) (LCSH) +* link your data to an existing dataset +* add to an editable platform such as [Wikidata](https://www.wikidata.org) +* or see whether entities in your project appear in some specific list, such as the [Panama Papers](https://aleph.occrp.org/datasets/734). + +Reconciliation is semi-automated: OpenRefine matches your cell values to the reconciliation information as best it can, but human judgment is required to review and approve the results. Reconciling happens by default through string searching, so typos, whitespace, and extraneous characters will have an effect on the results. You may wish to [clean and cluster](cellediting) your data before reconciliaton. + +:::info Working iteratively +We recommend planning your reconciliation operations as iterative: reconcile multiple times with different settings, and with different subgroups of your data. +::: + +## Sources {#sources} + +Start with [this current list of reconcilable authorities](https://reconciliation-api.github.io/testbench/), which includes instructions for adding new services via Wikidata editing if you have one to add. + +OpenRefine maintains a [further list of sources on the wiki](https://github.com/OpenRefine/OpenRefine/wiki/Reconcilable-Data-Sources), which can be edited by anyone. This list includes ways that you can reconcile against a [local dataset](https://github.com/OpenRefine/OpenRefine/wiki/Reconcilable-Data-Sources#local-services). + +Other services may exist that are not yet listed in these two places: for example, the [310 datasets hosted by the Organized Crime and Corruption Reporting Project (OCCRP)](https://aleph.occrp.org/datasets/) each have their own reconciliation URL, or you can reconcile against their entire database with the URL [shared on the reconciliation API list](https://reconciliation-api.github.io/testbench/). For another example, you can reconcile against the entire Virtual International Authority File (VIAF) dataset, or [only the contributions from certain institutions](http://refine.codefork.com/). Search online to see if the authority you wish to reconcile against has an available service, or whether you can download a copy to reconcile against locally. + +OpenRefine includes Wikidata reconciliation in the installation package - see the [Wikidata](wikidata) page for more information particular to that service. Extensions can add reconciliation services, and can also add enhanced reconciliation capacities. Check the list of extensions on the [Downloads page](https://openrefine.org/download.html) for more information. + +Each source will have its own documentation on how it provides reconciliation. The table on [the reconciliation API list](https://reconciliation-api.github.io/testbench/) indicates whether your chosen service supports the features described below. Refer to the service's documentation if you have questions about its behaviors and which OpenRefine features it supports. + +In addition to the reconciliation services mentioned above, you may also choose to build your own service. You can either start from scratch using the [API specification](https://reconciliation-api.github.io/specs/latest/) or use one of the frameworks mentioned in the [Reconciliation census](https://reconciliation-api.github.io/census/services/). + +Of particular note is [reconcile-csv](http://okfnlabs.org/reconcile-csv/) which allows you to build a reconciliation service from a simple CSV file. Thus if you wanted to reconcile one OpenRefine project against another, you'd simply need to export the target project as a CSV, point `reconcile-csv` at it and you're good to go. A somewhat newer port of this project written in Python can be found at [csv-reconcile](https://github.com/gitonthescene/csv-reconcile) which is more configurable and defaults to parsing tab separated files for convenience. + +Similiarly, you may choose to export some SPARQL output to a TSV to limit the scope of values you're reconciling against and/or for better peformance. + +## Getting started {#getting-started} + +Choose a column to reconcile and use its dropdown menu to select Reconcile → Start reconciling. If you want to reconcile only some cells in that column, first use filters and facets to isolate them. + +In the reconciliation window, you will see Wikidata offered as a default service. To add another service, click Add Standard Service... and paste in the URL of a [service](#sources). You should see the name of the service appear in the list of Services if the URL is correct. + +![The reconciliation window.](/img/reconcilewindow.png) + +Once you select a service, your selected column may be sampled in order to suggest [“types†(categories)](#reconciling-by-type) to reconcile against. Other services will suggest their available types without sampling, and some services have no types. + +For example, if you had a list of artists represented in a gallery collection, you could reconcile their names against the Getty Research Institute’s [Union List of Artist Names (ULAN)](https://www.getty.edu/research/tools/vocabularies/ulan/). The same [Getty reconciliation URL](https://services.getty.edu/vocab/reconcile/) will offer you ULAN, AAT (Art and Architecture Thesaurus), and TGN (Thesaurus of Geographic Names). + +![The reconciliation window with types.](/img/reconcilewindow2.png) + +Refer to the [documentation specific to the reconciliation service](https://reconciliation-api.github.io/testbench/) to learn whether types are offered, which types are offered, and which one is most appropriate for your column. You may wish to facet your data and reconcile batches against different types if available. + +Reconciliation can be a time-consuming process, especially with large datasets. We suggest starting with a small test batch. There is no throttle (delay between requests) to set for the reconciliation process. The amount of time will vary for each service, and vary based on the options you select during the process. + +When the process is done, you will see the reconciliation data in the cells. +If the cell was successfully matched, it displays text as a single dark blue link. In this case, the reconciliation is confident that the match is correct, and you should not have to check it manually. +If there is no clear match, one or more candidates are displayed, together with their reconciliation score, with the text in light blue links. You will need to select the correct one. + +For each matching decision you make, you have two options: match this cell only (one checkmark), or also use the same identifier for all other cells containing the same original string (two checkmarks). + +For services that offer the [“preview entities†feature](https://reconciliation-api.github.io/testbench/), you can hover your mouse over the suggestions to see more information about the candidates or matches. Each participating service (and each type) will deliver different structured data that may help you compare the candidates. + +For example, the Getty ULAN shows an artist’s discipline, nationality, and birth and death years: + +![Hovering over matches.](/img/reconcilehover.png) + +Hovering over the suggestion will also offer the two matching options as buttons. + +For matched values (those appearing as dark blue links), the underlying cell value has not been altered - the cell is storing both the original string and the matched entity link at the same time. If you were to copy your column to a new column at this point using `value`, for example, the reconcilation data would not transfer - only the original strings. You can learn more about how OpenRefine stores different pieces of information in each cell in [the Variables section specific to reconciliation data](expressions#reconciliation). + +For each cell, you can manually “Create new item,†which will take the cell’s original value and apply it, as though it is a match. This will not become a dark blue link, because at this time there is nothing to link to: it is a draft entity stored only in your project. You can use this feature to prepare these entries for eventual upload to an editable service such as [Wikidata](wikidata), but most services do not yet support this feature. + +### Reconciliation facets {#reconciliation-facets} + +Under Reconcile → Facets there are a number of reconciliation-specific faceting options. OpenRefine automatically creates two facets when you reconcile some cells. + +One is a numeric facet for “best candidate's score,†the range of reconciliation scores of only the best candidate of each cell. Higher scores mean better matches, although each service calculates scores differently and has a different range. You can facet for higher scores using the numeric facet, and then approve them all in bulk, by using Reconcile → [Actions](#reconciliation-actions) → Match each cell to its best candidate. + +There is also a “judgment†facet created, which lets you filter for the cells that haven't been matched (pick “none†in the facet). As you process each cell, its judgment changes from “none†to “matched†and it disappears from the view. + +You can add other facets by selecting Reconcile → Facets on your reconciled column. You can facet by: + +* your judgments (“matched,†or “none†for unreconciled cells, or “new†for entities you've created) +* the action you’ve performed on that cell (chosen a “single†match, or set a “mass†match, or no action, which appears as “unknownâ€) +* the timestamps on the edits you’ve made so far (these appear as millisecond counts since an arbitrary point: they can be sorted alphabetically to move forward and back in time). + +You can facet only the best candidates for each cell, based on: +* the score (calculated based on each service's own methods) +* the edit distance (using the [Levenshtein distance](cellediting#nearest-neighbor), a number based on how many single-character edits would be required to get your original value to the candidate value, with a larger value being a greater difference) +* the word similarity. + +Word similarity is calculated as a percentage based on how many words (excluding [stop words](https://en.wikipedia.org/wiki/Stop_word)) in the original value match words in the candidate. For example, the value “Maria Luisa Zuloaga de Tovar†matched to the candidate “Palacios, Luisa Zuloaga de†results in a word similarity value of 0.6, or 60%, or 3 out of 5 words. Cells that are not yet matched to one candidate will show as 0.0). + +You can also look at each best candidate’s: +* type (the ones you have selected in successive reconciliation attempts, or other types returned by the service based on the cell values) +* type match (“true†if you selected a type and it succeeded, “false†if you reconciled against no particular type, and “(no type)†if it didn’t reconcile) +* name match (“true†if you’ve matched, “false†if you haven’t yet chosen from the candidates, or “(unreconciled)†if it didn’t reconcile). + +These facets are useful for doing successive reconciliation attempts, against different types, and with different supplementary information. The information represented by these facets are held in the cells themselves and can be called using the [reconciliation variables](expressions#reconciliation) available in expressions. + +### Reconciliation actions {#reconciliation-actions} + +You can use the Reconcile → Actions menu options to perform bulk changes (which will apply only to your currently viewed set of rows or records): +* Match each cell to its best candidate (by highest score) +* Create a new item for each cell (discard any suggested matches) +* Create one new item for similar cells (a new entity will be created for each unique string) +* Match all filtered cells to... (a specific item from the chosen service, via a search box; only works with services that support the “suggest entities†property) +* Discard all reconciliation judgments (reverts back to multiple candidates per cell, including cells that may have been auto-matched in the original reconciliation process) +* Clear reconciliation data, reverting all cells back to their original values. + +The other options available under Reconcile are: +* Copy reconciliation data... (to an existing column: if the original values in your reconciliation column are identical to those in your chosen column, the matched and new cells will copy over; unmatched values will not change) +* [Use values as identifiers](#reconciling-with-unique-identifiers) (if you are reconciling with unique identifiers instead of by doing string searches) +* [Add entity identifiers column](#add-entity-identifiers-column). + +## Reconciling with unique identifiers {#reconciling-with-unique-identifiers} + +Reconciliation services use unique identifiers for their entities. For example, the 14th Dalai Lama has the VIAF ID [38242123](https://viaf.org/viaf/38242123/) and the Wikidata ID [Q17293](https://www.wikidata.org/wiki/Q37349). You can supply these identifiers directly to your chosen reconciliation service in order to pull more data, but these strings will not be “reconciled†against the external dataset. + +Select the column with unique identifiers and apply the operation Reconcile → Use values as identifiers. This will bring up the list of reconciliation services you have already added (to add a new service, open the Start reconciling... window first). If you use this operation on a column of IDs, you will not have access to the usual reconciliation settings. + +Matching identifiers does not validate them. All cells will appear as dark blue “confirmed†matches. You should check before this operation that the identifiers in the column exist on the target service. + +You may get false positives, which you will need to hover over or click on to identify: + +![Hovering over an error.](/img/reconcileIDerror.png) + +## Reconciling by type {#reconciling-by-type} + +Reconciliation services, once added to OpenRefine, may suggest types from their databases. These types will usually be whatever the service specializes in: people, events, places, buildings, tools, plants, animals, organizations, etc. + +Reconciling against a type may be faster and more accurate, but may result in fewer matches. Some services have hierarchical types (such as “mammal†as a subtype of “animalâ€). When you reconcile against a more specific type, unmatched values may fall back to the broader type; other services will not do this, so you may need to perform successive reconciliation attempts against different types. Refer to the documentation specific to the reconciliation service to learn more. + +When you select a service from the list, OpenRefine will load some or all available types. Some services will sample the first ten rows of your column to suggest types (check the [“Suggest types†column](https://reconciliation-api.github.io/testbench/)). You will see a service’s types in the reconciliation window: + +![Reconciling using a type.](/img/reconcile-by-type.png) + +In this example, “Person†and “Corporate Name†are potential types offered by the reconciliation API for VIAF. You can also use the Reconcile against type: field to enter in another type that the service offers. When you start typing, this field may search and suggest existing types. For VIAF, you could enter “/book/book†if your column contained publications. You may need to enter the service's own strings precisely instead of attempting to search for a match. + +Types are structured to fit their content: the Wikidata “human†type, for example, can include fields for birth and death dates, nationality, etc. The VIAF “person†type can include nationality and gender. You can use this to [include more properties](#reconciling-with-additional-columns) and find better matches. + +If your column doesn’t fit one specific type offered, you can Reconcile against no particular type. This may take longer. + +We recommend working in batches and reconciling against different types, moving from specific to broad. You can create a facet for Best candidate’s types facet to see which types are being represented. Some candidates may return more than one type, depending on the service. Types may appear in facets by their unique IDs, rather than by their semantic labels (for example, Q5 for “human†in Wikidata). + +## Reconciling with additional columns {#reconciling-with-additional-columns} + +Some of your cells may be ambiguous, in the sense that a string can point to more than one entity: there are dozens of places called “Paris†and many characters, people, and pieces of culture, too. Selecting non-geographic or more localized types can help narrow that down, but if your chosen service doesn't provide a useful type, you can include more properties that make it clear whether you're looking for Paris, France. + +![Reconciling sometimes turns up ambiguous matches.](/img/reconcileParis.gif) + +Including supplementary information can be useful, depending on the service (such as including birthdate information about each person you are trying to reconcile). You can re-reconcile unmatched cells with additional properties, in the right side of the Start reconciling window, under “Also use relevant details from other columns.†The column names in your project will appear in the reconciliation window, with an Include? checkbox next to each one. + +Fill in the As Property field with the type of information you are including. When you start typing, potential fields may pop up (depending on the [“suggest properties†feature](https://reconciliation-api.github.io/testbench/)), such as “birthDate†in the case of ULAN or “Geburtsdatum†in the case of Integrated Authority File (GND). Use the documentation for your chosen service to identify the fields in their terms. + +Some services will not be able to search for the exact name of your desired As Property entry, but you can still manually supply the field name. Refer to the service to choose the most appropriate field, and make sure you enter it correctly. + +![Including a birth-date type.](/img/reconcile-with-property.png) + +## Fetching more data {#fetching-more-data} + +One reason to reconcile to some external service is that it allows you to pull data from that service into your OpenRefine project. There are three ways to do this: + +* Add identifiers for your values +* Add columns from reconciled values +* Add column by fetching URLs. + +### Add entity identifiers column {#add-entity-identifiers-column} + +Once you have selected matches for your cells, you can retrieve the unique identifiers for those cells and create a new column for these, with Reconcile → Add entity identifiers column. You will be asked to supply a column name. New items and other unmatched cells will generate null values in this column. + +### Add columns from reconciled values {#add-columns-from-reconciled-values} + +If the reconciliation service supports [data extension](https://reconciliation-api.github.io/testbench/), then you can augment your reconciled data with new columns using Edit column → Add columns from reconciled values.... + +For example, if you have a column of chemical elements identified by name, you can fetch categorical information about them such as their atomic number and their element symbol: + +![A screenshare of elements fetching related information.](/img/reconcileelements.gif) + +Once you have chosen reconciliation matches for your cells, selecting Add column from reconciled values... will bring up a window to choose which related information you’d like to import into new columns. You can manually enter desired properties, or select from a list of suggestions. + +The quality of the suggested properties will depend on how you have reconciled your data beforehand: reconciling against a specific type will provide you with the associated properties of that type. For example, GND suggests elements about the “people†type after you've reconciled with it, such as their parents, native languages, children, etc. + +![A screenshot of available properties from GND.](/img/reconcileGND.png) + +If you have left any values unreconciled in your column, you will see “<not reconciled>†in the preview. These will generate blank cells if you continue with the column addition process. + +This process may pull more than one property per row in your data (such as multiple occupations), so you may need to switch into records mode after you've added columns. + +### Add columns by fetching URLs {#add-columns-by-fetching-urls} + +If the reconciliation service cannot extend data, look for a generic web API for that data source, or a structured URL that points to their dataset entities via unique IDs (such as “https://viaf.org/viaf/000000â€). You can use the Edit column → [Add column by fetching URLs](columnediting#add-column-by-fetching-urls) operation to call this API or URL with the IDs obtained from the reconciliation process. This will require using [expressions](expressions). + +You may not want to pull the entire HTML content of the pages at the ends of these URLs, so look to see whether the service offers a metadata endpoint, such as JSON-formatted data. You can either use a column of IDs, or you can pull the ID from each matched cell during the fetching process. + +For example, if you have reconciled artists to the Getty's ULAN, and [have their unique ULAN IDs as a column](#add-entity-identifiers-column), you can generate a new column of JSON-formatted data by using Add column by fetching URLs and entering the GREL expression `"http://vocab.getty.edu/" + value + ".json"`. For this service, the unique IDs are formatted “ulan/000000†and so the generated URLs look like “http://vocab.getty.edu/ulan/000000.jsonâ€. + +Alternatively, you can insert the ID directly from the matched column's reconciliation variables, using a GREL expression like `“http://vocab.getty.edu/†+ cell.recon.match.id + “.jsonâ€` instead. + +Remember to set an appropriate throttle and to refer to the service documentation to ensure your compliance with their terms. See [the section about this operation](columnediting#add-column-by-fetching-urls) to learn more about the fetching process. + +## Keep all the suggestions made {#keep-all-the-suggestions-made} + +To generate a list of each suggestion made, rather than only the best candidate, you can use a [GREL expression](expressions#GREL). Go to Edit column → Add column based on this column. To create a list of all the possible matches, use something like + +``` +forEach(cell.recon.candidates,c,c.name).join(", ") +``` + +To get the unique identifiers of these matches instead, use + +``` +forEach(cell.recon.candidates,c,c.id).join(", ") +``` + +This information is stored as a string, without any attached reconciliation information. + +## Writing reconciliation expressions {#writing-reconciliation-expressions} + +OpenRefine supplies a number of variables related specifically to reconciled values. These can be used in GREL and Jython expressions. For example, some of the reconciliation variables are: + +* `cell.recon.match.id` or `cell.recon.match.name` for matched values +* `cell.recon.best.name` or `cell.recon.best.id` for best-candidate values +* `cell.recon.candidates` for all listed candidates of each cell +* `cell.recon.judgment` (the values used in the “judgment†facet) +* `cell.recon.judgmentHistory` (the values used in the “judgment action timestamp†facet) +* `cell.recon.matched` (a “true†or “false†value) + +You can find out more in the [reconciliaton variables](expressions#reconciliaton-variables) section. + +## Exporting reconciled data {#exporting-reconciled-data} + +Once you have data that is reconciled to existing entities online, you may wish to export that data to a user-editable service such as Wikidata. See the section on [uploading your edits to Wikidata](wikidata#upload-edits-to-wikidata) for more information, or the section on [exporting](exporting) to see other formats OpenRefine can produce. + +You can share reconciled data in progress through a [project export or import](exporting#export-a-project), with some preparation. The importing user needs to have the appropriate reconciliation services installed on their OpenRefine instance (by going to Start reconciling and clicking on Add Standard Service...) in advance of opening the project, in order to use candidate and match links. Otherwise, the links will be broken and the user will need to add the reconciliation service and re-reconcile the columns in question. [Wikidata](wikidata) reconciliation data can be shared more easily as the service comes bundled with OpenRefine. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/running.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/running.md new file mode 100644 index 000000000..725d5a1fe --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/running.md @@ -0,0 +1,506 @@ +--- +id: running +title: Running OpenRefine +sidebar_label: Running +--- + +## Starting and exiting {#starting-and-exiting} + +OpenRefine does not require internet access to run its basic functions. Once you download and install it, it runs as a small web server on your own computer, and you access that local web server by using your browser. + +You will see a command line window open when you run OpenRefine. Ignore that window while you work on datasets in your browser. + +No matter how you start OpenRefine, it will load its interface in your computer’s default browser. If you would like to use another browser instead, start OpenRefine and then point your chosen browser at the home screen: [http://127.0.0.1:3333/](http://127.0.0.1:3333/). + +OpenRefine works best on browsers based on Webkit, such as: +* Google Chrome +* Chromium +* Opera +* Microsoft Edge + +We are aware of some minor rendering and performance issues on other browsers such as Firefox. We don't support Internet Explorer. + +You can view and work on multiple projects at the same time by simply having multiple tabs or browser windows open. From the Open Project screen, you can right-click on project names and open them in new tabs or windows. + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + + +#### With openrefine.exe {#with-openrefineexe} +You can run OpenRefine by double-clicking `openrefine.exe` or calling it from the command line. + +If you want to [modify the way `openrefine.exe` opens](#starting-with-modifications), you can edit the `openrefine.l4j.ini` file. + +#### With refine.bat {#with-refinebat} +On Windows, OpenRefine can also be run by using the file `refine.bat` in the program directory. If you start OpenRefine using `refine.bat`, you can do so by opening the file itself, or by calling it from the command line. + +If you call `refine.bat` from the command line, you can [start OpenRefine with modifications](#starting-with-modifications). +If you want to modify the way `refine.bat` opens through double-clicking or using a shortcut, you can edit the `refine.ini` file. + +#### Exiting {#exiting} + +To exit OpenRefine, close all the browser tabs or windows, then navigate to the command line window. To close this window and ensure OpenRefine exits properly, hold down `Control` and press `C` on your keyboard. This will save any last changes to your projects. + + + + + +You can find OpenRefine in your Applications folder, or you can open it using Terminal. + +To run OpenRefine using Terminal: +* Find the OpenRefine application / icon in Finder +* Control-click on the icon and select “Show Package Contents†from the context menu +* This should open a new Finder menu: navigate into the “MacOS†folder +* Control-click on “JavaAppLauncher†+* Choose “Open With†from the menu, and select “Terminal.†+ +To exit, close all your OpenRefine browser tabs, go back to the terminal window and press `Command` and `Q` to close it down. + +:::caution Problems starting? +If you are using an older version of OpenRefine or are on an older version of MacOS, [check our Wiki for solutions to problems with MacOS](https://github.com/OpenRefine/OpenRefine/wiki/Installation-Instructions#macos). +::: + + + + + +Use a terminal to launch OpenRefine. First, navigate to the installation folder. Then call the program: + +``` +cd openrefine-3.4.1 + ./refine +``` + +This will start OpenRefine and open your browser to the home screen. + +To exit, close all the browser tabs, and then press `control` and `C` in the terminal window. + +:::caution Did you get a JAVA_HOME error? +“Error: Could not find the ‘java’ executable at ‘’, are you sure your JAVA_HOME environment variable is pointing to a proper java installation?†+ +If you see this error, you need to [install and configure a JDK package](installing#linux), including setting up `JAVA_HOME`. +::: + + + + + +--- + +### Troubleshooting {#troubleshooting} + +If you are having problems connecting to OpenRefine with your browser, [check our Wiki for information about browser settings and operating-system issues](https://github.com/OpenRefine/OpenRefine/wiki/FAQ#i-am-having-trouble-connecting-to-openrefine-with-my-browser). + +### Starting with modifications {#starting-with-modifications} + +When you run OpenRefine from a command line, you can change a number of default settings. + + + + + +On Windows, use a slash: + +``` +C:>refine /i 127.0.0.2 /p 3334 +``` + +Get a list of all the commands with `refine /?`. + +|Command|Use|Syntax example| +|---|---|---| +|/w|Path to the webapp|refine /w /path/to/openrefine| +|/m|Memory maximum heap|refine /m 6000M| +|/p|Port|refine /p 3334| +|/i|Interface (IP address, or IP and port)|refine /i 127.0.0.2:3334| +|/d|Enable debugging (on port 8000)|refine /d| +|/x|Enable JMX monitoring for Jconsole and JvisualVM|refine /x| + + + + + +You cannot start the Mac version with modifications using Terminal, but you can modify the way the application starts with [settings within files](#modifications-set-within-files). + + + + + +To see the full list of command-line options, run `./refine -h`. + +|Command|Use|Syntax example| +|---|---|---| +|-w|Path to the webapp|./refine -w /path/to/openrefine| +|-d|Path to the workspace|./refine -d /where/you/want/the/workspace| +|-m|Memory maximum heap|./refine -m 6000M| +|-p|Port|./refine -p 3334| +|-i|Interface (IP address, or IP and port)|./refine -i 127.0.0.2:3334| +|-k|Add a Google API key|./refine -k YOUR_API_KEY| +|-v|Verbosity (from low to high: error,warn,info,debug,trace)|./refine -v info| +|-x|Additional Java configuration parameters (see Java documentation)|| +|--debug|Enable debugging (on port 8000)|./refine --debug| +|--jmx|Enable JMX monitoring for Jconsole and JvisualVM|./refine --jmx| + + + + + +--- + +#### Modifications set within files {#modifications-set-within-files} + +On Windows, you can modify the way `openrefine.exe` runs by editing `openrefine.l4j.ini`; you can modify the way `refine.bat` runs by editing `refine.ini`. + +You can modify the Mac application by editing `info.plist`. + +On Linux, you can edit `refine.ini`. + +Some settings, such as changing memory allocations, are already set inside these files, and all you have to do is change the values. Some lines need to be un-commented to work. + +For example, inside `refine.ini`, you should see: +``` +no_proxy="localhost,127.0.0.1" +#REFINE_PORT=3334 +#REFINE_HOST=127.0.0.1 +#REFINE_WEBAPP=main\webapp + +# Memory and max form size allocations +#REFINE_MAX_FORM_CONTENT_SIZE=1048576 +REFINE_MEMORY=1400M + +# Set initial java heap space (default: 256M) for better performance with large datasets +REFINE_MIN_MEMORY=1400M +... +``` + +##### JVM preferences {#jvm-preferences} + +Further modifications can be performed by using JVM preferences. These JVM preferences are different options and have different syntax than the key/value descriptions used on the command line. + +Some of the most common keys (with their defaults) are: +* The project [autosave](starting#autosaving) frequency: `-Drefine.autosave` (5 [minutes]) +* The workspace director: `-Drefine.data_dir` (/) +* Development mode: `-Drefine.development` (false) +* Headless mode: `-Drefine.headless` (false) +* IP: `-Drefine.host` (127.0.0.1) +* Port: `-Drefine.port` (3333) +* The application folder: `-Drefine.webapp` (main/webapp) + +The syntax is as follows: + + + + + +Locate the `refine.l4j.ini` file, and insert lines in this way: + +``` +-Drefine.port=3334 +-Drefine.host=127.0.0.2 +-Drefine.webapp=broker/core +``` + +In `refine.ini`, use a similar syntax, but set multiple parameters within a single line starting with `JAVA_OPTIONS=`: + +``` +JAVA_OPTIONS=-Drefine.data_dir=C:\Users\user\Documents\OpenRefine\ -Drefine.port=3334 + +``` + + + + +Locate the `info.plist`, and find the `array` element that follows the line + +``` +JVMOptions +``` + +Typically this looks something like: + +``` +JVMOptions + +-Xms256M +-Xmx1024M +-Drefine.version=2.6-beta.1 +-Drefine.webapp=$APP_ROOT/Contents/Resource/webapp + +``` + +Add in values such as: + +``` +JVMOptions + +-Xms256M +-Xmx1024M +-Drefine.version=2.6-beta.1 +-Drefine.webapp=$APP_ROOT/Contents/Resource/webapp +-Drefine.autosave=2 +-Drefine.port=3334 + + +``` + + + + + +Locate the `refine.ini` file, and add `JAVA_OPTIONS=` before the `-Drefine.preference` declaration. You can un-comment and edit the existing suggested lines, or add lines: + +``` +JAVA_OPTIONS=-Drefine.autosave=2 +JAVA_OPTIONS=-Drefine.port=3334 +JAVA_OPTIONS=-Drefine.data_dir=usr/lib/OpenRefineWorkspace +``` + + + + + + +--- + +Refer to the [official Java documentation](https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html) for more preferences that can be set. + +## The home screen {#the-home-screen} + +When you first launch OpenRefine, you will see a screen with a menu on the left hand side that includes Create Project, Open Project, Import Project, and Language Settings. This is called the “home screen,†where you can manage your projects and general settings. + +In the lower left-hand corner of the screen, you'll see Preferences, Help, and About. + +### Language settings {#language-settings} + +From the home screen, look in the options to the left for Language Settings. You can set your preferred interface language here. This language setting will persist until you change it again in the future. Languages are translated as a community effort; some languages are partially complete and default back to English where unfinished. Currently OpenRefine supports the following languages for 75% or more of the interface: + +* Cebuano +* German +* English (UK) +* English (US) +* Spanish +* Filipino +* French +* Hebrew +* Magyar +* Italian +* Japanese (日本語) +* Portuguese (Brazil) +* Tagalog +* Chinese (简体中文) + +To leave the Language Settings screen, click on the diamond “OpenRefine†logo. + +:::info Help us Translate OpenRefine +We use Weblate to provide translations for the interface. You can check [our profile on Weblate](https://hosted.weblate.org/projects/openrefine/translations/) to see which languages are in the process of being supported. See [our technical reference if you are interested in contributing translation work](../technical-reference/translating) to make OpenRefine accessible to people in other languages. +::: + +### Preferences {#preferences} + +In the bottom left corner of the screen, look for Preferences. At this time you can set preferences using a key/value pair: that is, selecting one of the keys below and setting a value for it. + +|Setting|Key|Value syntax|Default|Example|Version| +|---|---|---|---|---|---| +|Interface language|userLang|[ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) two-digit code|en|fr|—| +|Maximum facets|ui.browsing.listFacet.limit|Number|2000|5000|—| +|Timeout for Google Drive import|googleReadTimeOut|Number (microseconds)|180000|500000|—| +|Timeout for Google Drive authorization|googleConnectTimeOut|Number (microseconds)|180000|500000|—| +|Maximum lag for Wikidata edit retries|wikibase.upload.maxLag|Number (seconds)|5|10|—| +|Display of the reconciliation preview on hover|cell-ui.previewMatchedCells|Boolean|true|false|v3.2| +|Width of the panel for facets/history|ui.browsing.facetsHistoryPanelWidth|Number (pixel)|300|500|v3.5| + +To leave the Preferences screen, click on the diamond “OpenRefine†logo. + +If the preference you’re looking for isn’t here, look at the options you can set from the [command line or in an `.ini` file](#starting-with-modifications). + +## The project screen {#the-project-screen} + +The project screen (or work screen) is where you will spend most of your time once you have [begun to work on a project](starting). This is a quick walkthrough of the parts of the interface you should familiarize yourself with. + +![A screenshot of the project screen.](/img/projectscreen.png) + +### The project bar {#the-project-bar} + +The project bar runs across the very top of the project screen. It contains the the OpenRefine logo, the project title, and the project control buttons on the right side. + +At any time you can close your current project and go back to the home screen by clicking on the OpenRefine logo. If you’d like to open another project in a new browser tab or window, you can right-click on the logo and use “Open in a new tab.†You will lose [your current facets and view settings](#facetfilter) if you close your project (but data transformations will be saved in the [History](#history-undoredo) of the project). + +:::caution +Don’t click the “back†button on your browser - it will likely close your current project and you will lose your facets and view settings. +::: + +You can rename a project at any time by clicking inside the project title, which will turn into a text field. Project names don’t have to be unique, as OpenRefine organizes them based on a unique identifier behind the scenes. + +The Permalink allows you to return to a project at a specific view state - that is, with [facets and filters](facets) applied. The Permalink can help you pick up where you left off if you have to close your project while working with facets and filters. It puts view-specific information directly into the URL: clicking on it will load this current-view URL in the existing tab. You can right-click and copy the Permalink URL to copy the current view state to your clipboard, without refreshing the tab you’re using. + +The Open… button will open up a new browser tab showing the Create Project screen. From here you can change settings, start a new project, or open an existing project. + +Export is a dropdown menu that allows you to pick a format for exporting a dataset. Many of the export options will only export rows and records that are currently visible - the currently selected facets and filters, not the total data in the project. + +Help will open up a new browser tab and bring you to this user manual on the web. + +### The grid header {#the-grid-header} + +The grid header sits below the project bar and above the project grid (where the data of your project is displayed). The grid header will tell you the total number of rows or records in your project, and indicate whether you are in [rows or records mode](exploring#rows-vs-records). + +It will also tell you if you’re currently looking at a select number of rows via facets or filtering, rather than the entire dataset, by displaying either, for example, “180 rows†or “67 matching rows (180 total).†+ +Directly below the row number, you have the ability to switch between [row mode and records mode](exploring#rows-vs-records). OpenRefine stores projects persistently in one of the two modes, and displays your data as records by default if you are. + +To the right of the rows/records selection is the array of options for how many rows/records to view on screen at one time. At the far right of the screen you can navigate through your entire dataset one page at a time. + +### Extensions {#extensions} + +The Extensions dropdown offers you options for extending your data - most commonly by uploading your edited statements to Wikidata, or by importing or exporting schema. You can learn more about these functions on the [Wikidata page](wikidata). Other extensions may also add functions to this dropdown menu. + +### The grid {#the-grid} + +The area of the project screen that displays your dataset is called the “grid†(or the “data grid,†or the “project gridâ€). The grid presents data in a tabular format, which may look like a normal spreadsheet program to you. + +Columns widths are automatically set based on their contents; some column headers may be cut off, but can be viewed by mousing over the headers. + +In each column header you will see a small arrow. Clicking on this arrow brings up a dropdown menu containing column-specific data exploration and transformation options. You will learn about each of these options in the [Exploring data](exploring) and [Transforming data](transforming) sections. + +The first column in every project will always be All, which contains options to flag, star, and do non-column-specific operations. The All column is also where rows/records are numbered. Numbering shows the permanent order of rows and records; a temporary sorting or facet may reorder the rows or show a limited set, but numbering will show you the original identifiers unless you make a permanent change. + +The project grid may display with both vertical and horizontal scrolling, depending on the number and width of columns, and the number of rows/records displayed. You can control the display of the project grid by using [Sort and View options](exploring#sort-and-view). + +Mousing over individual cells will allow you to [edit cells individually](cellediting#edit-one-cell-at-a-time). + +### Facet/Filter {#facetfilter} + +The Facet/Filter tab is one of the main ways of exploring your data: displaying the patterns and trends in your data, and helping you narrow your focus and modify that data. [Facets](facets) and [filters](facets#text-filter) are explained more in [Exploring data](exploring). + +![A screenshot of facets and filters in action.](/img/facetfilter.png) + +In the tab, you will see three buttons: Refresh, Reset all, and Remove all. + +Refreshing your facets will ensure you are looking at the latest information about each facet, for example if you have changed the counts or eliminated some options. + +Resetting your facets will remove any inclusion or exclusion you may have set - the facet options will stay in the sidebar, but your view settings will be undone. + +Removing your facets will clear out the sidebar entirely. If you have written custom facets using [expressions](expressions), these will be lost. + +You can preserve your facets and filters for future use by copying a [Permalink](#the-project-bar). + +### History (Undo/Redo) {#history-undoredo} + +In OpenRefine, any activity that changes the data can be undone. Changes are tracked from the very beginning, when a project is first created. The change history of each project is saved with the project's data, so quitting OpenRefine does not erase the steps you've taken. When you restart OpenRefine, you can view and undo changes that you made before you quit OpenRefine. OpenRefine [autosaves](starting#autosaving) your actions every five minutes by default, and when you close OpenRefine properly (using Ctrl + C). You can [change this interval](running#jvm-preferences). + +Project history gets saved when you export a project archive, and restored when you import that archive to a new installation of OpenRefine. + +![A screenshot of the History (Undo/Redo) tab with 13 steps.](/img/history.png "A screenshot of the History (Undo/Redo) tab with 13 steps.") + +When you click on the Undo / Redo tab in the sidebar of any project, that project’s history is shown as a list of changes in order, with the first “change†being the action of creating the project itself. (That first change, indexed as step zero, cannot be undone.) Here is a sample history with 3 changes: + +``` +0. Create project +1. Remove 7 rows +2. Create new column Last Name based on column Name with grel:value.split(" ") +3. Split 230 cell(s) in column Address into several columns by separator +``` + +The current state of the project is highlighted with a dark blue background. If you move back and forth on the timeline you will see the current state become highlighted, while the actions that came after that state will be grayed out. + +To revert your data back to an earlier state, simply click on the last action in the timeline you want to keep. In the example above, if we keep the removal of 7 rows but revert everything we did after that, then click on “Remove 7 rows.†The last 2 changes will be undone, in order to bring the project back to state #1. + +In this example, changes #2 and #3 will now be grayed out. You can redo a change by clicking on it in the history - everything up to and including it will be redone. + +If you have moved back one or more states, and then you perform a new operation on your data, the later actions (everything that’s greyed out) will be erased and cannot be re-applied. + +The Undo/Redo tab will indicate which step you’re on, and if you’re about to risk erasing work - by saying something like “4/5" or “1/7†at the end. + +#### Reusing operations {#reusing-operations} + +Operations that you perform in OpenRefine can be reused. For example, a formula you wrote inside one project can be copied and applied to another project later. + +To reuse one or more operations, first extract it from the project where it was first applied. Click to the Undo/Redo tab and click Extract…. This brings up a box that lists all operations up to the current state (it does not show undone operations). Select the operation or operations you want to extract using the checkboxes on the left, and they will be encoded as JSON on the right. Copy that JSON to the clipboard. + +Move to the second project, go to the Undo/Redo tab, click Apply… and paste in that JSON. + +Not all operations can be extracted. Edits to a single cell, for example, can’t be replicated. + +## Advanced OpenRefine uses {#advanced-openrefine-uses} + +### Running OpenRefine's Linux version on a Mac {#running-openrefines-linux-version-on-a-mac} + +You can run OpenRefine from the command line in Mac by using the Linux installation package. We do not promise support for this method. Follow the instructions in the Linux section. + +### Running as a server {#running-as-a-server} + +:::caution +Please note that if your machine has an external IP (is exposed to the Internet), you should not do this, or should protect it behind a proxy or firewall, such as nginx. Proceed at your own risk. +::: + +By default (and for security reasons), OpenRefine only listens to TCP requests coming from localhost (127.0.0.1) on port 3333. If you want to share your OpenRefine instance with colleagues and respond to TCP requests to any IP address of the machine, start it from the command line like this: +``` +./refine -i 0.0.0.0 +``` + +or set this option in `refine.ini`: +``` +REFINE_HOST=0.0.0.0 +``` + +or set this JVM option: +``` +-Drefine.host=0.0.0.0 +``` + +On Mac, you can add a specific entry to the `Info.plist` file located within the app bundle (`/Applications/OpenRefine.app/Contents/Info.plist`): +``` +JVMOptions + + + -Drefine.host=0.0.0.0 + … + +``` + +:::caution +OpenRefine has no built-in security or version control for multi-user scenarios. OpenRefine has a single data model that is not shared, so there is a risk of data operations being overwritten by other users. Care must be taken by users. +::: + +### Automating OpenRefine {#automating-openrefine} + +Some users may wish to employ OpenRefine for batch processing as part of a larger automated pipeline. Not all OpenRefine features can work without human supervision and advancement (such as clustering), but many data transformation tasks can be automated. + +:::caution +The following are all third-party extensions and code; the OpenRefine team does not maintain them and cannot guarantee that any of them work. +::: + +Some examples: + +* This project allows OpenRefine to be run from the command line using [operations saved in a JSON file](#reusing-operations): [OpenRefine batch processing](https://github.com/opencultureconsulting/openrefine-batch) +* A Python project for applying a JSON file of operations to a data file, outputting the new file, and deleting the temporary project, written by David Huynh and Max Ogden: [Python client library for Google Refine](https://github.com/maxogden/refine-python) +* And the same in Ruby: [Refine-Ruby](https://github.com/maxogden/refine-ruby) +* Another Python client library, by Paul Makepeace: [OpenRefine Python Client Library](https://github.com/PaulMakepeace/refine-client-py) + +To look for other instances, search our Google Groups [for users](https://groups.google.com/g/openrefine) and [for developers](https://groups.google.com/g/openrefine-dev), where [these projects were originally posted](https://groups.google.com/g/openrefine/c/GfS1bfCBJow/m/qWYOZo3PKe4J). diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/sortview.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/sortview.md new file mode 100644 index 000000000..a45a4b887 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/sortview.md @@ -0,0 +1,35 @@ +--- +id: sortview +title: Sort and view +sidebar_label: Sort and view +--- + +## Sort {#sort} + +You can temporarily sort your rows by one column. You can sort based on [data type](exploring#data-types): +* text alphabetically or reverse +* numbers by largest or smallest +* dates by earliest or latest +* boolean values by false first or true first. + +You can also choose where to place errors and blank cells in the sorting. Text can be case-sensitive or not: if so, cells that start with lowercase characters will appear ahead of those that start with uppercase characters. + +![A screenshot of the Sort window.](/img/sort.png) + +After you apply a sorting method, you can make it permanent, remove it, reverse it, or apply a subsequent sorting. When it is applied, you’ll find Sort in the project grid header to the right of the rows-display setting, which will show all current sorting settings. + +If you have multiple sorting methods applied, they will work in the order you applied them (represented in order in the Sort menu). For example, you can sort an “authors†column alphabetically, and then sort their books by publication date, for those authors that have more than one book. If you apply those in a different order - sort all the publication dates in the dataset first, and then alphabetically by author - your dataset will look different. + +![Temporarily sorted rows.](/img/sort2.png) + +When the sorting method you've applied is temporary, you will see that the rows retain their original numbering. When you make that sorting method permanent, by selecting Reorder rows permanently, the row numbers will change and the Sort menu in the project grid header will disappear. This will apply all current sorting methods. + +## View {#view} + +You can control what data you view in the grid. On each column, you will see a View menu option. From there, you can “collapse†(hide) that specific column, all other columns, all columns to the left, and all columns to the right. Using the View option that appears in the All column’s dropdown menu, you can collapse all columns, and expand all the columns that you previously collapsed. + +### Show/hide “null†{#showhide-null} + +You can find, under All → View, the option to show and hide [“null†values](exploring#data-types). A small grey “null†will appear in each applicable cell. Remember that a null cell is not the same thing as an empty cell. + +![A screenshot of what a null value looks like.](/img/null.png) diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/starting.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/starting.md new file mode 100644 index 000000000..819a09df4 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/starting.md @@ -0,0 +1,194 @@ +--- +id: starting +title: Starting a project +sidebar_label: Starting a project +--- + +## Overview {#overview} + +An OpenRefine project is started by importing in some existing data - OpenRefine doesn’t allow you to create a dataset from nothing. + +No matter where your data comes from, OpenRefine won’t modify your original data source. It copies all the information from your input, creates its own project file, and stores it in your [workspace directory](installing#set-where-data-is-stored). + +The data and all of your edits are [automatically saved](#autosaving) inside the project file. When you’re finished modifying the data, you can [export it back out](exporting) into the file format of your choice. + +You can also receive and open other people’s projects, or send them yours, by [exporting a project archive](exporting#export-a-project) and [importing it](#import-a-project). + +## Create a project by importing data {#create-a-project-by-importing-data} + +When you start OpenRefine, you’ll be taken to the Create Project screen. You’ll see on the left side of the screen that your options are to: + +* import data from one or more files on your computer +* import data from one or more links on the web +* import data by pasting in text from your clipboard +* import data from a database (using SQL), and +* import one or more Sheets from Google Drive. + +From these sources, you can load any of the following file formats: + +* comma-separated values (CSV) or text-separated values (TSV) +* Text files +* Fixed-width columns +* JSON +* XML +* OpenDocument spreadsheet (ODS) +* Excel spreadsheet (XLS or XLSX) +* PC-Axis (PX) +* MARC +* RDF data (JSON-LD, N3, N-Triples, Turtle, RDF/XML) +* Wikitext + +More formats can be imported by [adding extensions to provide that functionality](https://openrefine.org/download.html). + +If you supply two or more files for one project, the files’ rows will be loaded in the order that you specify, and OpenRefine will create a column at the beginning of the dataset with the source URL or file name in it to help you identify where each row came from. If the files have columns with identical names, the data will load in those columns; if not, the successive files will append all of their new columns to the end of the dataset: + +|File|Fruit|Quantity|Berry|Berry source| +|---|---|---|---|---| +|fruits.csv|Orange|4| +|fruits.csv|Apple|6| +|berries.csv||9|Mulberry|Greece| +|berries.csv||2|Blueberry|Canada| + +You cannot combine two datasets into one project by appending data within rows. You can, however, combine two projects later using functions such as [cross()](grelfunctions/#crosscell-s-projectname-s-columnname), or [fetch further data](columnediting) using other methods. + +For whichever method you choose to start your project, when you click Next >> you will be given a preview and a chance to configure the way OpenRefine interprets the data you input. + +### Get data from this computer {#get-data-from-this-computer} + +Click on Browse… and select a file (or several) on your hard drive. All files will be shown, not just compatible ones. + +If you import an archive file (something with the extension `.zip`, `.tar.gz`, `.tgz`, `.tar.bz2`, `.gz`, or `.bz2`), OpenRefine detects the files inside it, shows you a preview screen, and allows you to select which ones to load. This does not work with `.rar` files. + +### Web addresses (URLs) {#web-addresses-urls} + +Type or paste the URL to a data file into the field provided. You can add as many fields as you want. OpenRefine will download the file and preview the project for you. + +If you supply two or more file URLs, OpenRefine will identify each one and ask you to choose which (or all) to load. + +Do not use this form to load a Google Sheet by its link; use [the Google Data form instead](#google-data). + +### Clipboard {#clipboard} + +You can copy and paste in data from anywhere. OpenRefine will recognize comma-separated, tab-separated, or table-formatted information copied from sources such as word-processing documents, spreadsheets, and tables in PDFs. You can also just paste in a list of items that you want to turn into rows. OpenRefine recognizes each new text line as a row. + +This can be useful if you want to pre-select a specific number of rows from your source data, or paste together rows from different places, rather than delete unwanted rows later in the project interace. + +This can also be useful if you would like to paste in a list of URLs, which you can use later to [fetch more data](columnediting). + +### Database (SQL) {#database-sql} + +If you are an administrator or have SQL access to a database of information, you may want to pull the latest dataset directly from there. This could include an online catalogue, a content management system, or a digital repository or collection management system. You can also load a database (`.db`) file saved locally. You will need to use an [SQL query](https://www.w3schools.com/sql/) to import your intended data. + +There are some publicly-accessible databases you can query, such as [one provided by Rfam](https://docs.rfam.org/en/latest/database.html). The instructions provided by Rfam can help you understand how to connect to and query from other databases. + +OpenRefine can connect to PostgreSQL, MySQL, MariaDB, and SQLite database systems. It will automatically populate the Port field based on which of these you choose, but you can manually edit this if needed. + +If you have a `.db` file, you can supply the path to the file on your computer in the Database field at the bottom of the form. You can leave the rest of the fields blank. + +To import data directly from a database, you will need the database type (such as MySQL), database name, the hostname (either an IP address or the domain that hosts the database), and the port on the host. You will need an account authorized for access, and you may need to add OpenRefine's IP address or host to the "allowable hosts" for that account. You can find that information by pressing Test and getting the IP address from the error message that results. + +You can either connect just once to gather data, or save the connection to use it again later. If you press Connect without saving, OpenRefine will forget all the information you just entered. If you’d like to save the connection, name your connection in a way you will recognize later. Click Save and it will appear in the Saved Connections list on the left. From now on, you can click on the ... ellipsis to the right of the connection you’ve saved, and click Connect. + +If your connection is successful, you will see a Query Editor where you can run your SQL query. OpenRefine will give you an error if you write a statement that tries to modify the source database in any way. + +### Google data {#google-data} + +You have two ways to load in data from Google Sheets: +* providing a link to an accessible Google Sheet (that is, one with link-sharing turned on), and +* selecting a Google Sheet in your Google Drive. + +#### Google Sheet by URL {#google-sheet-by-url} + +You can import data from any Google Sheet that has link-sharing turned on. Paste in a URL that looks something like + +``` +https://docs.google.com/spreadsheets/………/edit?usp=sharing +``` + +This will only work with Sheets, not with any other Google Drive file that might have an available link, including `.xls` and other valid files that are hosted in Google Drive. These links will not work when attempting to start a project [by URL](#web-addresses-urls) either, so you need to download those files to your computer. + +#### Google Sheet from Drive {#google-sheet-from-drive} + +You can authorize OpenRefine to access your Google Drive data and import data from any Google Sheet it finds there. This will include Sheets that belong to you and Sheets that are shared with you, as well as Sheets that are in your trash. + +When you select a Google option (either here, or [when exporting project data to Google Drive or Google Sheets](exporting), you will see a pop-up window that asks you to select a Google account to authorize with. You may see an error message when you authorize: if so, try your import or export operation again and it should succeed. + +OpenRefine will not show spreadsheets that are in your email inbox or stored in any other Google property - only in Drive. It also won’t show all compatible file formats, only Sheets files. + +OpenRefine will generate a list of all Sheets it finds, with the most recently modified Sheets at the top. If a file you’ve just added isn’t showing in this list, you can close and restart OpenRefine, or simply navigate to an existing project, open it, then head back to the Create Project window and check again. + +When you click Preview the Sheet will open in a new browser tab. When you click the Sheet title, OpenRefine will begin to process the data. + + +## Project preview {#project-preview} + +Once OpenRefine is ready to import the data, you will see a screen with Configure Parsing Options at the top. You’ll see a preview of the first 100 rows and all identified columns. + +At the bottom of the screen you will find options for telling OpenRefine how to process what it has found. You can tell it which row(s) to parse as column headers, as well as to ignore any number of rows at the top. You can also select a specific range of rows to work with, by discarding some rows at the top (excluding the header) and limiting the total number of rows it loads. + +OpenRefine tries to guess how to parse your data based on the file extension. For example, `.xml` files are going to be parsed as though they are formatted in XML. An unknown file extension (or your clipboard copy-paste) is assumed to be either tab-separated or comma-separated. OpenRefine looks for a tab character, and if one is found, it assumes you have imported tab-separated data. + +If OpenRefine isn’t certain what format you imported, it will provide a list of possibilities under Parse data as and some settings. You can specify a custom separator now, or split columns later while [transforming your data](transforming). + +If you imported a spreadsheet with multiple worksheets, they will be listed along with the number of rows they contain. You can only select data from one worksheet. + +Note that OpenRefine does not preserve any formatting, such as cell or text colour, that my have been in the original data file. Hyperlinked text will be input as plain text, but OpenRefine will recognize links and make them clickable inside the project interface. + +:::info Encoding issues? +Look for character encoding issues at this stage. You may want to manually select an encoding, such as UTF-8, UTF-16, or ASCII, if OpenRefine does not display some characters correctly in the preview. Once your project is created, you can specify another encoding for specific columns using the [reinterpret() function](grelfunctions#reinterprets-s-encoder). +::: + +You should create a project name at this stage. You can also supply tags to keep your projects organized. When you’re happy with the preview, click Create Project. + + +## Import a project {#import-a-project} + +Because OpenRefine only runs locally on your computer, you can’t have a project accessible to more than one person at the same time. + +The best way to collaborate with another person is to export and import projects that save all your changes, so that you can pick up where someone else left off. You can also [export projects](exporting#export-a-project) and import them to other computers, such as for working on the same project from the office and from home. + +An exported project will include all of the [history](running#history-undoredo), so you can see (and undo) all the changes from the previous user. It is essentially a point-in-time snapshot of their work. OpenRefine only exports projects as `.tar.gz` files at this time. +:::caution +If you wish to hide the original state of your data and your history of edits (for example, if you are using OpenRefine to anonymize information), export your cleaned dataset only and do not share your project archive. +::: + +Once someone has sent you a project archive file from their computer, you can save it anywhere. OpenRefine will import it like a new project and save its information to your workspace directory. + +In the left-hand menu of the home screen, click Import Project. Click Browse… and navigate to wherever you saved the file you were sent (for example, your Downloads folder). + +You can rename the project if you’d like - we recommend adding your name, a date, or a version number, if you’re planning to continue collaborating with another person (or working from multiple computers). + +Then, click Import Project. Your project should appear with a step count beside Undo/Redo if steps were saved by the exporter. + +OpenRefine will store the project in its own workspace directory, so you can now delete the original file that was sent to you. + + +## Project management {#project-management} + +You can access all of your created projects by clicking on Open Project. Your project list can be organized by modification date, title, row count, and other metadata you can supply (such as subject, descripton, tags, or creator). To edit the fields you see here, click About to the left of each project. There you can edit a number of available fields. You can also see the project ID that corresponds to the name of the folder in your work directory. + +### Naming projects {#naming-projects} + +You may have multiple projects from the same dataset, or multiple versions from sharing a project with another person. OpenRefine automatically generates a project name from the imported file, or “clipboard†when you use Clipboard importing. Project names don’t have to be unique, and OpenRefine will create many projects with the same name unless you intervene. + +You can edit a project's name when you create it or import it, and you can rename a project later by opening it and clicking on the project name at the top of the screen. + +### Autosaving {#autosaving} + +OpenRefine [saves all of your actions](running#history-undoredo) (everything you can see in the Undo/Redo panel). That includes flagging and starring rows. + +It doesn’t, however, save your facets, filters, or any kind of view you may have in place while you work. This includes the number of rows showing, and any sorting or column collapsing you may have done. A good rule of thumb is: if it’s not showing in Undo/Redo, you will lose it when you leave the project workspace. + +Autosaving happens by default every five minutes. You can [change this preference by following these directions](running#jvm-preferences). + +You can only save and share facets and filters, not any other type of view. To save current facets and filters, click Permalink. The project will reload with a different URL, which you can then copy and save elsewhere. This permalink will save both the facets and filters you’ve set, and the settings for each one (such as sorting by count rather than by name). + +### Deleting projects {#deleting-projects} + +You can delete projects, which will erase the project files from the workspace directory on your computer. This is immediate and cannot be undone. + +Go to Open Project and find the project you want to delete. Click on the X to the left of the project name. There will be a confirmation dialog. + +### Project files {#project-files} + +You can find all of your raw project files in your work directory. They will be named according to the unique “Project ID†that OpenRefine has assigned them, which you can find on the Open Project screen, under the “About†link for each project. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/transforming.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/transforming.md new file mode 100644 index 000000000..53a436370 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/transforming.md @@ -0,0 +1,34 @@ +--- +id: transforming +title: Transforming data +sidebar_label: Overview +--- + +## Overview {#overview} + +OpenRefine gives you powerful ways to clean, correct, codify, and extend your data. Without ever needing to type inside a single cell, you can automatically fix typos, convert things to the right format, and add structured categories from trusted sources. + +This section of ways to improve data are organized by their appearance in the menu options in OpenRefine. You can: + +* change the order of [rows](#edit-rows) or [columns](columnediting#rename-remove-and-move) +* edit [cell contents](cellediting) within a particular column +* [transform](transposing) rows into columns, and columns into rows +* [split or join columns](columnediting#split-or-join) +* [add new columns](columnediting) based on existing data, with fetching new information, or through [reconciliation](reconciling) +* convert your rows of data into [multi-row records](exploring#rows-vs-records). + +## Edit rows {#edit-rows} + +Moving rows around is a permanent change to your data. + +You can [sort your data](sortview#sort) based on the values in one column, but that change is a temporary view setting. With that setting applied, you can make that new order permanent. + +![A screenshot of where to find the Sort menu with a sorting applied.](/img/sortPermanent.png) + +In the project grid header, the word “Sort†will appear when a sort operation is applied. Click on it to show the dropdown menu, and select Reorder rows permanently. You will see the numbering of the rows change under the All column. + +:::info Reordering all rows +Reordering rows permanently will affect all rows in the dataset, not just those currently viewed through [facets and filters](facets). +::: + +You can undo this action using the [History tab](running#history-undoredo). \ No newline at end of file diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/transposing.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/transposing.md new file mode 100644 index 000000000..6b5ec0dc8 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/transposing.md @@ -0,0 +1,234 @@ +--- +id: transposing +title: Transposing +sidebar_label: Transposing +--- + +## Overview {#overview} + +These functions were created to solve common problems with reshaping your data: pivoting cells from a row into a column, or pivoting cells from a column into a row. You can also transpose from a repeated set of values into multiple columns. + +## Transpose cells across columns into rows {#transpose-cells-across-columns-into-rows} + +Imagine personal data with addresses in this format: + +|Name|Street|City|State/Province|Country|Postal code| +|---|---|---|---|---|---| +|Jacques Cousteau|23, quai de Conti|Paris||France|75270| +|Emmy Noether|010 N Merion Avenue|Bryn Mawr|Pennsylvania|USA|19010| + +You can transpose the address information from this format into multiple rows. Go to the “Street†column and select Transpose → Transpose cells across columns into rows. From there you can select all of the five columns, starting with “Street†and ending with “Postal code,†that correspond to address information. Once you begin, you should put your project into [records mode](exploring#rows-vs-records) to associate the subsequent rows with “Name†as the key column. + +![A screenshot of the transpose across columns window.](/img/transpose1.png) + +### One column {#one-column} + +You can transpose the multiple address columns into a series of rows: + +|Name|Address| +|---|---| +|Jacques Cousteau|23, quai de Conti| +| |Paris| +| |France| +| |75270| +|Emmy Noether|010 N Merion Avenue| +||Bryn Mawr| +||Pennsylvania| +||USA| +||19010| + +You can choose one column and include the column-name information in each cell by prepending it to the value, with or without a separator: + +|Name|Address| +|---|---| +|Jacques Cousteau|Street: 23, quai de Conti| +| |City: Paris| +| |Country: France| +| |Postal code: 75270| +|Emmy Noether|Street: 010 N Merion Avenue| +||City: Bryn Mawr| +||State/Province: Pennsylvania| +||Country: USA| +||Postal code: 19010| + +### Two columns {#two-columns} + +You can retain the column names as separate cell values, by selecting Two new columns and naming the key and value columns. + +|Name|Address part|Address| +|---|---|---| +|Jacques Cousteau|Street|23, quai de Conti| +| |City|Paris| +| |Country|France| +| |Postal code|75270| +|Emmy Noether|Street|010 N Merion Avenue| +||City|Bryn Mawr| +||State/Province|Pennsylvania| +||Country|USA| +||Postal code|19010| + +## Transpose cells in rows into columns {#transpose-cells-in-rows-into-columns} + +Imagine employee data in this format: + +|Column| +|---| +|Employee: Karen Chiu| +|Job title: Senior analyst| +|Office: New York| +|Employee: Joe Khoury| +|Job title: Junior analyst| +|Office: Beirut| +|Employee: Samantha Martinez| +|Job title: CTO| +|Office: Tokyo| + +The goal is to sort out all of the information contained in one column into separate columns, but keep it organized by the person it represents: + +|Name |Job title |Office| +|---|---|---| +|Karen Chiu |Senior analyst |New York| +|Joe Khoury |Junior analyst |Beirut| +|Samantha Martinez |CTO |Tokyo| + +By selecting Transpose → Transpose cells in rows into columns... a window will appear that simply asks how many rows to transpose. In this case, each employee record has three rows, so input “3†(do not subtract one for the original column). The original column will disappear and be replaced with three columns, with the name of the original column plus a number appended. + +|Column 1 |Column 2 |Column 3| +|---|---|---| +|Employee: Karen Chiu |Job title: Senior analyst |Office: New York| +|Employee: Joe Khoury |Job title: Junior analyst |Office: Beirut| +|Employee: Samantha Martinez |Job title: CTO |Office: Tokyo| + +From here you can use Cell editing → Replace to remove “Employee: â€, “Job title: â€, and “Office: †if you wish, or use [expressions](expressions) with Edit cells → Transform... to clean out the extraneous characters: + +``` +value.replace("Employee: ", "") +``` + +If your dataset doesn't have a predictable number of cells per intended row, such that you cannot specify easily how many columns to create, try Columnize by key/value columns. + +## Columnize by key/value columns {#columnize-by-keyvalue-columns} + +This operation can be used to reshape a dataset that contains key and value columns: the repeating strings in the key column become new column names, and the contents of the value column are moved to new columns. This operation can be found at Transpose → Columnize by key/value columns. + +![A screenshot of the Columnize window.](/img/transpose2.png) + +Consider the following example, with flowers, their colours, and their International Union for Conservation of Nature (IUCN) identifiers: + +|Field |Data | +|--------|----------------------| +|Name |Galanthus nivalis | +|Color |White | +|IUCN ID |162168 | +|Name |Narcissus cyclamineus | +|Color |Yellow | +|IUCN ID |161899 | + +In this format, each flower species is described by multiple attributes on consecutive rows. The “Field†column contains the keys and the “Data†column contains the values. In the Columnize by key/value columns window you can select each of these from the available columns. It transforms the table as follows: + +| Name | Color | IUCN ID | +|-----------------------|----------|---------| +| Galanthus nivalis | White | 162168 | +| Narcissus cyclamineus | Yellow | 161899 | + +### Entries with multiple values in the same column {#entries-with-multiple-values-in-the-same-column} + +If a new row would have multiple values for a given key, then these values will be grouped on consecutive rows, to form a [record structure](exploring#rows-vs-records). + +For instance, flowers can have multiple colors: + +| Field | Data | +|-------------|-----------------------| +| Name | Galanthus nivalis | +| _Color_ | _White_ | +| _Color_ | _Green_ | +| IUCN ID | 162168 | +| Name | Narcissus cyclamineus | +| Color | Yellow | +| IUCN ID | 161899 | + +This table is transformed by the Columnize operation to: + +| Name | Color | IUCN ID | +|-----------------------|----------|---------| +| Galanthus nivalis | White | 162168 | +| | Green | | +| Narcissus cyclamineus | Yellow | 161899 | + +The first key encountered by the operation serves as the record key, so the “Green†value is attached to the “Galanthus nivalis†name. See the [Row order](#row-order) section for more details about the influence of row order on the results of the operation. + +### Notes column {#notes-column} + +In addition to the key and value columns, you can optionally add a column for notes. This can be used to store extra metadata associated to a key/value pair. + +Consider the following example: + +| Field | Data | Source | +|---------|---------------------|-----------------------| +| Name | Galanthus nivalis | IUCN | +| Color | White | Contributed by Martha | +| IUCN ID | 162168 | | +| Name | Narcissus cyclamineus | Legacy | +| Color | Yellow | 2009 survey | +| IUCN ID | 161899 | | + +If the “Source†column is selected as the notes column, this table is transformed to: + +| Name | Color | IUCN ID | Source: Name | Source: Color | +|-----------------------|----------|---------|---------------|-----------------------| +| Galanthus nivalis | White | 162168 | IUCN | Contributed by Martha | +| Narcissus cyclamineus | Yellow | 161899 | Legacy | 2009 survey | + +Notes columns can therefore be used to preserve provenance or other context about a particular key/value pair. + +### Row order {#row-order} + +The order in which the key/value pairs appear matters. The Columnize operation will use the first key it encounters as the delimiter for entries: every time it encounters this key again, it will produce a new row, and add the following key/value pairs to that row. + +Consider for instance the following table: + +| Field | Data | +|----------|-----------------------| +| _Name_ | Galanthus nivalis | +| Color | White | +| IUCN ID | 162168 | +| _Name_ | Crinum variabile | +| _Name_ | Narcissus cyclamineus | +| Color | Yellow | +| IUCN ID | 161899 | + +The occurrences of the “Name†value in the “Field†column define the boundaries of the entries. Because there is no other row between the “Crinum variabile†and the “Narcissus cyclamineus†rows, the “Color†and “IUCN ID†columns for the “Crinum variabile†entry will be empty: + +| Name | Color | IUCN ID | +|-----------------------|----------|---------| +| Galanthus nivalis | White | 162168 | +| Crinum variabile | | | +| Narcissus cyclamineus | Yellow | 161899 | + +This sensitivity to order is removed if there are extra columns: in that case, the first extra column will serve as the key for the new rows. + +### Extra columns {#extra-columns} + +If your dataset contains extra columns, that are not being used as the key, value, or notes columns, they can be preserved by the operation. For this to work, they must have the same value in all old rows corresponding to a new row. + +In the following example, the “Field†and “Data†columns are used as key and value columns respectively, and the “Wikidata ID†column is not selected: + +| Field | Data | Wikidata ID | +|---------|-----------------------|-------------| +| Name | Galanthus nivalis | Q109995 | +| Color | White | Q109995 | +| IUCN ID | 162168 | Q109995 | +| Name | Narcissus cyclamineus | Q1727024 | +| Color | Yellow | Q1727024 | +| IUCN ID | 161899 | Q1727024 | + +This will be transformed to: + +| Wikidata ID | Name | Color | IUCN ID | +|-------------|-----------------------|----------|---------| +| Q109995 | Galanthus nivalis | White | 162168 | +| Q1727024 | Narcissus cyclamineus | Yellow | 161899 | + +This actually changes the operation: OpenRefine no longer looks for the first key (“Nameâ€) but simply pivots all information based on the first extra column's values. Every old row with the same value gets transposed into one new row. If you have more than one extra column, they are pivoted as well but not used as the new key. + +You can use [Fill down](cellediting#fill-down-and-blank-down) to put identical values in the extra columns if you need to. \ No newline at end of file diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/troubleshooting.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/troubleshooting.md new file mode 100644 index 000000000..67b4aef6c --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/troubleshooting.md @@ -0,0 +1,31 @@ +--- +id: troubleshooting +title: Troubleshooting +sidebar_label: Troubleshooting +--- + +## Frequently asked questions {#frequently-asked-questions} + +We collect and share FAQs and responses on Github at [https://github.com/OpenRefine/OpenRefine/wiki/FAQ](https://github.com/OpenRefine/OpenRefine/wiki/FAQ). + +If you don’t find your problem and solution there, continue on to the resources in the Community section below to see more conversations and look for solutions. + +## Community {#community} + +### If you’re having a problem: {#if-youre-having-a-problem} +* Search the [User forum](https://groups.google.com/g/openrefine) to see if the problem is already reported +* Search [Github issues](https://github.com/OpenRefine/OpenRefine/issues) to see if the problem is already reported +* Read [Stack Overflow](https://stackoverflow.com/questions/tagged/openrefine) to see if others had a similar problem +* Check [Twitter](https://twitter.com/search?f=tweets&vertical=default&q=OpenRefine%20OR%20%22Open%20Refine%22%20OR%20%23OpenRefine&src=typd) to see if others are discussing the problem +* Report an issue: + * First as a new thread (conversation) in the [User forum](https://groups.google.com/g/openrefine). + * Then, if you wish, you can create a Github issue. + +### If you want to contribute: {#if-you-want-to-contribute} +* [Help us translate the tool into more languages](../technical-reference/translating), using Weblate +* [We have a guide to contributing](../technical-reference/contributing) in the [Technical Reference](../technical-reference/technical-reference-index) section +* Contribute your feature requests in the [User forum](https://groups.google.com/g/openrefine) or as [Github issues](https://github.com/OpenRefine/OpenRefine/issues/new/choose) +* Join the User Forum and/or the [Developer Forum](https://groups.google.com/g/openrefine-dev) +* Share your successes and use cases with us, in the User forum +* Add your [blog posts, guides, tips, tricks, tutorials to our list](https://github.com/OpenRefine/OpenRefine/wiki/External-Resources) +* Keep an eye out for and respond to our biennial user survey. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/manual/wikidata.md b/OpenRefine/docs/versioned_docs/version-3.4/manual/wikidata.md new file mode 100644 index 000000000..6f462f1af --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/manual/wikidata.md @@ -0,0 +1,190 @@ +--- +id: wikidata +title: Wikidata +sidebar_label: Wikidata +--- + +## Overview {#overview} + +OpenRefine provides powerful ways to both pull data from Wikidata and add data to it. + +You do not need a Wikidata account to reconcile your local OpenRefine project to Wikidata. If you wish to [upload your cleaned dataset to Wikidata](#editing-wikidata-with-openrefine), you will need an [autoconfirmed](https://www.wikidata.org/wiki/Wikidata:Autoconfirmed_users) account, and you must [authorize OpenRefine with that account](#manage-wikidata-account). + +:::info A better resource +The best source for information about how OpenRefine works with Wikidata is [on Wikidata itself, under Tools](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine). That page has tutorials, guidelines on editing, and spaces for discussion and help. The following text on this page reviews the basics and can help you get set up, but the Wikidata help page is more regularly updated when technology or policies change. Links to the Wikidata help page are included throughout this page. +::: + +OpenRefine’s connections to Wikidata were formerly an optional extension, but are now included automatically with installation. The Wikidata extension can be removed manually by navigating to your OpenRefine installation folder, and then looking inside `webapp/extensions/` and deleting the `wikidata` folder found there. + +## Reconciling with Wikidata {#reconciling-with-wikidata} + +The Wikidata [reconciliation service](reconciling) for OpenRefine [supports](https://reconciliation-api.github.io/testbench/): +* A large number of potential types to reconcile against +* Previewing and viewing entities +* Suggesting entities, types, and properties +* Augmenting your project with more information pulled from Wikidata. + +You can find documentation and further resources on the reconciliation API [here](https://wikidata.reconci.link/). + +For the most part, Wikidata reconciliation behaves the same way other reconciliation services do, but there are a few processes and features specific to Wikidata. + +### Language settings {#language-settings} + +You can install a version of the Wikidata reconciliation service that uses your language. First, you need the language code: this is the [two-letter code found on this list](https://en.wikipedia.org/wiki/List_of_Wikipedias), or in the domain name of the desired Wikipedia/Wikidata (for instance, “fr†if your Wikipedia is https://fr.wikipedia.org/wiki/). + +Then, open the reconciliation window (under Reconcile → Start reconciling...) and click Add Standard Service. The URL to enter is `https://wikidata.reconci.link/fr/api`, where “fr†is your desired language code. + +When reconciling using this interface, items and properties will be displayed in your chosen language if the label is available. The matching score of the reconciliation is not influenced by your choice of language for the service: items are matched by considering all labels and returning the best possible match. The language of your dataset is also irrelevant to your choice of language for the reconciliation service; it simply determines which language labels to return based on the entity chosen. + +### Restricting matches by type {#restricting-matches-by-type} + +In Wikidata, types are items themselves. For instance, the [university of Ljubljana (Q1377)](https://www.wikidata.org/wiki/Q1377) has the type [public university (Q875538)](https://www.wikidata.org/wiki/Q875538), using the [instance of (P31)](https://www.wikidata.org/wiki/Property:P31) property. Types can be subclasses of other types, using the [subclass of (P279)](https://www.wikidata.org/wiki/Property:P279) property. For instance, [public university (Q875538)](https://www.wikidata.org/wiki/Q875538) is a subclass of [university (Q3918)](https://www.wikidata.org/wiki/Q3918). You can visualize these structures with the [Wikidata Graph Builder](https://angryloki.github.io/wikidata-graph-builder/). + +When you select or enter a type for reconciliation, OpenRefine will include that type and all of its subtypes. For instance, if you select [university (Q3918)](https://www.wikidata.org/wiki/Q3918), then [university of Ljubljana (Q1377)](https://www.wikidata.org/wiki/Q1377) will be a possible match, though that item isn't directly linked to Q3918 - because it is directly linked to Q875538, the subclass of Q3918. + +Some items and types may not yet be set as an instance or subclass of anything (because Wikidata is crowdsourced). If you restrict reconciliation to a type, items without the chosen type will not appear in the results, except as a fallback, and will have a lower score. + +### Reconciling via unique identifiers {#reconciling-via-unique-identifiers} + +You can supply a column of unique identifiers (in the form "Q###" for entities) directly to Wikidata in order to pull more data, but [these strings will not be “reconciled†against the external dataset](reconciling#reconciling-with-unique-identifiers). Apply the operation Reconcile → Use values as identifiers on your column of QIDs. All cells will appear as dark blue “confirmed†matches. Some of the “matches†may be errors, which you will need to hover over or click on to identify. You cannot use this to reconcile properties (in the form "P###"). + +If the identifier you submit is assigned to multiple Wikidata items (because Wikidata is crowdsourced), all of the items are returned as candidates, with none automatically matched. + +### Property paths, special properties, and subfields {#property-paths-special-properties-and-subfields} + +Wikidata's hierarchical property structure can be called by using property paths (using |, /, and . symbols). Labels, aliases, descriptions, and sitelinks can also be accessed. You can also match values against subfields, such as latitude and longitude subfields of a geographical coordinate. + +For information on how to do this, read the [documentation and further resources here](https://wikidata.reconci.link/#documentation). + +## Editing Wikidata with OpenRefine {#editing-wikidata-with-openrefine} + +The best resource is the [Editing section](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing) on Wikidata. + +As a user-maintained data source, Wikidata can be edited by anyone. OpenRefine makes it simple to upload information in bulk. You simply need to get your information into the correct format, and ensure that it is new (not redundant to information already on Wikidata) and does not conflict with existing Wikidata information. + +Wikidata is built by creating entities (such as people, organizations, or places, identified with unique numbers starting with Q), defining properties (unique numbers starting with P), and using properties to define relationships between entities (a Q has a property P, with a value of another Q). + +For example, you may wish to create entities for local authors and the books they've set in your community. Each writer will be an entity with the occupation [author (Q482980)](https://www.wikidata.org/wiki/Q482980), each book will be an entity with the property “instance of†([P31](https://www.wikidata.org/wiki/Property:P31)) linking it to a class such as [literary work (Q7725634)](https://www.wikidata.org/wiki/Q7725634), and books will be related to authors through a property [author (P50)](https://www.wikidata.org/wiki/Property:P50). Books can have places where they are set, with the property [narrative location (P840)](https://www.wikidata.org/wiki/Property:P840). + +To do this with OpenRefine, you'll need a column of publication titles that you have reconciled (and create new items where needed); each publication will have one or more locations in a “setting†column, which is also reconciled to municipalities or regions where they exist (and create new items where needed). Then you can add those new relationships, and create new entities for authors, books, and places where needed. You do not need columns for properties; those are defined later, in the creation of your [schema](#edit-wikidata-schema). + +There is a list of [tutorials and walkthroughs on Wikidata](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing) that will allow you to see the full process. You can save your schemas and drafts in OpenRefine, and your progress stays in draft until you are ready to upload it to Wikidata. You can also find information on [how to design a schema](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing/Schema_alignment) and [how OpenRefine evaluates your proposed edits for issues](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing/Quality_assurance). + +Batches of edits to Wikidata that are created with OpenRefine can be undone. You can test out the uploading process by reconciling to several “sandbox†entities created specifically for drafting edits and learning about Wikidata: +* https://www.wikidata.org/wiki/Q4115189 +* https://www.wikidata.org/wiki/Q13406268 +* https://www.wikidata.org/wiki/Q15397819 +* https://www.wikidata.org/wiki/Q64768399 + +If you upload edits that are redundant (that is, all the statements you want to make have already been made), nothing will happen. If you upload edits that conflict with existing information (such as a different birthdate than one already in Wikidata), it will be added as a second statement. OpenRefine produces no warnings as to whether your data replicates or conflicts with existing Wikidata elements. + +You can use OpenRefine's reconciliation preview to look at the target Wikidata elements and see what information they already have, and whether the elements' histories have had similar edits reverted in the past. + +### Edit Wikidata schema {#edit-wikidata-schema} + +The best resource is the [Schema alignment page](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing/Schema_alignment) on Wikidata. + +A [schema](https://en.wikipedia.org/wiki/Database_schema) is a plan for how to structure information in a database. In OpenRefine, the schema operates as a template for how Wikidata edits should be applied: how to translate your tabular data into statements. With a schema, you can: +* preview the Wikidata edits and inspect them manually; +* analyze and fix any issues highlighted by OpenRefine; +* upload your changes to Wikidata by logging in with your own account; +* export the changes to the QuickStatements v1 format. + +For example, if your dataset has columns for authors, publication titles, and publication years, your schema can be conceptualized as: [publication title] has the author [author], and was published in [publication year]. To establish these facts, you need to establish one or more columns as “items,†for which you will make “statements†that relate them to other columns. + +You can export any schema you create, and import an existing schema for use with a new dataset. This can help you work in batches on a large amount of data while minimizing redundant labor. + +Once you select Edit Wikidata schema under the Extensions dropdown menu, your project interface will change. You’ll see new tabs added to the right of “X rows/records" in the grid header: “Schema,†“Issues,†and “Preview.†You can now switch between the tabular grid format of your dataset and the screens that allow you to prepare data for uploading. + +OpenRefine presents you with an easy visual way to map out the relationships in your dataset. Each of the columns of your project will appear at the top of the sceren, and you can simply drag and drop them into the appropriate slots. To get start, select one column as an item. + +![A screenshot of the schema construction window in OpenRefine.](/img/wikidata-schema.png) + +You may wish to refer to [this Wikidata tutorial on how OpenRefine handles Wikidata schema](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing/Tutorials/Basic_editing). + +#### Editing terms with your schema {#editing-terms-with-your-schema} + +With OpenRefine, you can edit the terms (labels, aliases, descriptions, or sitelinks) of Wikidata entities as well as establish relationships between entities. For example, you may wish to upload pseudonyms, pen names, maiden names, or married names for authors. + +![An author with a number of aliases indicating pseudonyms.](/img/wikidata-terms.png) + +You can do so by putting the preferred names in one column of your dataset and alternative names in another column. In the schema interface, add an item for the preferred values, then click “Add term†on the right-hand side of the screen. Select “Alias†from the dropdown, enter in “English†in the language field, and drop your alternative names column into the space. For this example, you should also consider adding those alternative names to the authors' entries using the property [pseudonym (P742)](https://www.wikidata.org/wiki/Property:P742). The "description" and "label" terms can only contain one value, so there is an option to override existing values if needed. Aliases can be potentially infinite. + +![The schema window showing a term being edited.](/img/wikidata-terms2.png) + +Terms must always have an associated language. You can select the term's language by typing in the “lang†field, which will auto-complete for you. You cannot edit multiple languages at once, unless you supply a suitable column instead. For example, suppose you had translated publication titles, with data in the following format: + +|English title|Translated title|Translation language| +|---|---|---| +|Possession|Besessen|German| +||Обладать|Russian| +|Disgrace|Disgrâce|French| +||Vergogna|Italian| +|Wolf Hall|En la corte del lobo|Spanish| +||ウルフ・ホール|Japanese| + +You could upload the “Translated titles†to “Label†with the language specified by “Translation language.†You may wish to fetch the two-letter language code and use that instead for better language matches. + +![Constructing a schema with aliases and languages.](/img/wikidata-translated.png) + +### Manage Wikidata account {#manage-wikidata-account} + +To edit Wikidata directly from OpenRefine, you must log in with a Wikidata account. OpenRefine can only upload edits with Wikidata user accounts that are “[autoconfirmed](https://www.wikidata.org/wiki/Wikidata:Autoconfirmed_users)†- at this time, that means accounts that have more than 50 edits and have existed for longer than four days. + +Use the Extensions menu to select Manage Wikidata account and you will be presented with the following window: + +![The Wikidata authorization window in OpenRefine.](/img/wikidata-login.png) + +For security reasons, you should not use your main account authorization with OpenRefine. Wikidata allows you to set special passwords to access your account through software. You can find [this setting for your account here](https://www.wikidata.org/wiki/Special:BotPasswords) once logged in. Creating bot access will prompt you for a unique name. You should then enable the following required settings: +* High-volume editing +* Edit existing pages +* Create, edit, and move pages + +It will then generate a username (in the form of “yourwikidatausername@yourbotnameâ€) and password for you to use with OpenRefine. + +If your account or your bot is not properly authorized, OpenRefine will not display a warning or error when you try to upload your edits. + +You can store your unencrypted username and password in OpenRefine, saved locally to your computer and available for future use. For security reasons, you may wish to leave this box unchecked. You can also save your OpenRefine-specific bot password in your browser or with a password management tool. + +### Import and export schema {#import-and-export-schema} + +You can save time on repetitive processes by defining a schema on one project, then exporting it and importing for use on new datasets in the future. Or you and your colleagues can share a schema with each other to coordinate your work. + +You can export a schema from a project using Export → Wikidata schema, or by using Extensions → Export schema. OpenRefine will generate a JSON file for you to save and share. You may experience issues with pop-up windows in your browser: consider allowing pop-ups from the OpenRefine URL (`127.0.0.1`) from now on. + +You can import a schema using Extensions → Import schema. You can upload a JSON file, or paste JSON statements directly into a field in the window. An imported schema will look for columns with the same names, and you will see an error message if your project doesn't contain matching columns. + +### Upload edits to Wikidata {#upload-edits-to-wikidata} + +The best resource is the [Uploading page](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing/Uploading) on Wikidata. + +There are two menu options in OpenRefine for applying your edits to Wikidata. Under Export you will see Wikidata edits... and under Extensions you will see Upload edits to Wikidata. Both will bring up the same window for you to [log in with a Wikidata account](#manage-wikidata-account). + +Once you are authorized, you will see a window with any outstanding issues. You can ignore these issues, but we recommend you resolve them. + +If you are ready to upload your edits, you can provide an “Edit summary†- a short message describing the batch of edits you are making. It can be helpful to leave notes for yourself, such as “batch 1: authors A-G†or other indicators of your workflow progress. OpenRefine will show the progress of the upload as it is happening, but does not show a confirmaton window. + +If your edits have been successful, you will see them listed on [your Wikidata user contributions page](https://www.wikidata.org/wiki/Special:Contributions/), and on the [Edit groups page](https://editgroups.toolforge.org/). All edits can be undone from this second interface. + +### QuickStatements export {#quickstatements-export} + +Your OpenRefine data can be exported in a format recognized by [QuickStatements](https://www.wikidata.org/wiki/Help:QuickStatements), a tool that creates Wikidata edits using text commands. OpenRefine generates “version 1†QuickStatements commands. + +There are advantages to using QuickStatements rather than uploading your edits directly to Wikidata, including the way QuickStatements resolves duplicates and redundancies. You can learn more on QuickStatements' [Help page](https://www.wikidata.org/wiki/Help:QuickStatements), and on OpenRefine's [Uploading page](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing/Uploading). + +In order to use QuickStatements, you must authorize it with a Wikidata account that is [autoconfirmed](https://www.wikidata.org/wiki/Wikidata:Autoconfirmed_users) (it may appear as “MediaWiki†when you authorize). + +Follow the [steps listed on this page](https://www.wikidata.org/wiki/Help:QuickStatements#Running_QuickStatements). +To prepare your OpenRefine data into QuickStatements, select Export → QuickStatements file, or Extensions → Export to QuickStatements. Exporting your schema from OpenRefine will generate a text file called `statements.txt` by default. Paste the contents of the text file into a new QuickStatements batch using version 1. You can find [version 1 of the tool (no longer maintained) here](https://wikidata-todo.toolforge.org/quick_statements.php). The text commands will be processed into Wikidata edits and previewed for you to review before submitting. + +### Schema alignment {#schema-alignment} + +The best resource is the [Schema alignment page](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing/Schema_alignment) on Wikidata. + +### Issue detection {#issue-detection} + +The best resource is the [Quality assurance page](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing/Quality_assurance) on Wikidata. + +OpenRefine will analyze your schema and make suggestions. It does not check for conflicts in your proposed edits, or tell you about redundancies. + +One of the most common suggestions is to attach [a reference to your edits](https://www.wikidata.org/wiki/Help:Sources) - a citation for where the information can be found. This can be a book or newspaper citation, a URL to an online page, a reference to a physical source in an archival or special collection, or another source. If the source is itself an item on Wikidata, use the relationship [stated in (P248)](https://www.wikidata.org/wiki/Property:P248); otherwise, use [reference URL (P854)](https://www.wikidata.org/wiki/Property:P854) to identify an external source. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/architecture.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/architecture.md new file mode 100644 index 000000000..e80d7015a --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/architecture.md @@ -0,0 +1,283 @@ +--- +id: architecture +title: Architecture +sidebar_label: Architecture +--- + +OpenRefine is a web application, but is designed to be run locally on your own machine. The server-side maintains states of the data (undo/redo history, long-running processes, etc.) while the client-side maintains states of the user interface (facets and their selections, view pagination, etc.). The client-side makes GET and POST ajax calls to cause changes to the data and to fetch data and data-related states from the server-side. + +This architecture provides a good separation of concerns (data vs. UI); allows the use of familiar web technologies (HTML, CSS, Javascript) to implement user interface features; and enables the server side to be called by third-party software through standard GET and POST operations. + +## Technology stack {#technology-stack} + +The server-side part of OpenRefine is implemented in Java as one single servlet which is executed by the [Jetty](http://jetty.codehaus.org/jetty/) web server + servlet container. The use of Java strikes a balance between performance and portability across operating systems (there is very little OS-specific code and has mostly to do with starting the application). + +OpenRefine has no database. It uses its own in-memory data-store that is built up-front to be optimized for the operations required by faceted browsing and infinite undo. + +The client-side part of OpenRefine is implemented in HTML, CSS and Javascript and uses the following libraries: +* [jQuery](http://jquery.com/) +* [jQueryUI](http:jqueryui.com/) +* [Recurser jquery-i18n](https://github.com/recurser/jquery-i18n) + +The functional extensibility of OpenRefine is provided by a fork of the [SIMILE Butterfly](https://github.com/OpenRefine/simile-butterfly) modular web application framework. + +Several projects provide the functionality to read and write custom format files (POI, opencsv, JENA, marc4j). + +String clustering is provided by the [SIMILE Vicino](http://code.google.com/p/simile-vicino/) project. + +OAuth functionality is provided by the [Signpost](https://github.com/mttkay/signpost) project. + +## Server-side architecture {#server-side-architecture} + +OpenRefine's server-side is written entirely in Java (`main/src/`) and its entry point is the Java servlet `com.google.refine.RefineServlet`. By default, the servlet is hosted in the lightweight Jetty web server instantiated by `server/src/com.google.refine.Refine`. Note that the server class itself is under `server/src/`, not `main/src/`; this separation leaves the possibility of hosting `RefineServlet` in a different servlet container. + +The web server configuration is in `main/webapp/WEB-INF/web.xml`; that's where `RefineServlet` is hooked up. `RefineServlet` itself is simple: it just reacts to requests from the client-side by routing them to the right `Command` class in the packages `com.google.refine.commands.**`. + +As mentioned before, the server-side maintains states of the data, and the primary class involved is `com.google.refine.ProjectManager`. + +### Projects {#projects} + +In OpenRefine there's the concept of a workspace similar to that in Eclipse. When you run OpenRefine it manages projects within a single workspace, and the workspace is embodied in a file directory with sub-directories. The default workspace directories are listed in the [FAQs](https://github.com/OpenRefine/OpenRefine/wiki/FAQ-Where-Is-Data-Stored). You can get OpenRefine to use a different directory by specifying a -d parameter at the command line. + +The class `ProjectManager` is what manages the workspace. It keeps in memory the metadata of every project (in the class `ProjectMetadata`). This metadata includes the project's name and last modified date, and any other information necessary to present and let the user interact with the project as a whole. Only when the user decides to look at the project's data would `ProjectManager` load the project's actual data. The separation of project metadata and data is to minimize the amount of stuff loaded into memory. + +A project's _actual_ data includes the columns, rows, cells, reconciliation records, and history entries. + +A project is loaded into memory when it needs to be displayed or modified, and it remains in memory until 1 hour after the last time it gets modified. Periodically the project manager tries to save modified projects, and it saves as many modified projects as possible within 30 seconds. + +### Data Model {#data-model} + +A project's data consists of + +- _raw data_: a list of rows, each row consisting of a list of cells +- _models_ on top of that raw data that give high-level presentation or interpretation of that data. This design lets the same raw data be viewed in different ways by different models, and let the models be changed without costly changes to the raw data. + +#### Column Model {#column-model} + +Cells in rows are not named and can only be addressed by their list position indices. So, a _column model_ is needed to give a name to each list position. The column model also stores other metadata for each column, including the type that cells in the column have been reconciled to and the overall reconciliation statistics of those cells. + +Each column also acts as a cache for data computed from the raw data related to that column. + +Columns in the column model can be removed and re-ordered without changing the raw data--the cells in the rows. This makes column removal and ordering operations really quick. + +##### Column Groups {#column-groups} + +Consider the following data: + +![Illustration of row groups in OpenRefine](https://raw.github.com/OpenRefine/OpenRefine/2.0/graphics/row-groups.png) + +Although the data is in a grid, we humans can understand that it is a tree. First of all, all rows contain data ultimately linked to the movie Austin Powers, although only one row contains the text "Austin Powers" in the "movie title" column. We also know that "USA" and "Germany" are not related to Elizabeth Hurley and Mike Myers respectively (say, as their nationality), but rather, "USA" and "Germany" are related to the movie (where it was released). We know that Mike Myers played both the character "Austin Powers" and the character "Dr. Evil"; and for the latter he received 2 awards. We humans can understand how to interpret the grid as a tree based on its visual layout as well as some knowledge we have about the movie domain but is not encoded in the table. + +OpenRefine can capture our knowledge of this transformation from grid to tree using _column groups_, also stored in the column model. Each column group illustrated as a blue bracket above specifies which columns are grouped together, as well as which of those columns is the key column in that group (blue triangle). One column group can span over columns grouped by another column group, and in this way, column groups form a hierarchy determined by which column group envelopes another. This hierarchy of column groups allows the 2-dimensional (grid-shaped) table of rows and cells to be interpreted as a list of hierarchical (tree-shaped) data records. + +Blank cells play a very important role. The blank cell in a key column of a row (e.g., cell "character" on row 4) makes that row (row 4) _depend_ on the first preceding row with that column filled in (row 3). This means that "Best Comedy Perf" on row 4 applies to "Dr. Evil" on row 3. Row 3 is said to be a _context row_ for row 4. Similarly, since rows 2 - 6 all have blank cells in the first column, they all depend on row 1, and all their data ultimately applies to the movie Austin Powers. Row 1 depends on no other row and is said to be a _record row_. Rows 1 - 6 together form one _record_. + +Currently (as of 12th December 2017) only the XML and JSON importers create column groups, and while the data table view does display column groups but it doesn't support modifying them. + +### Changes, History, Processes, and Operations {#changes-history-processes-and-operations} + +All changes to the project's data are tracked (N.B. this does not include changes to a project's metadata - such as the project name.) + +Changes are stored as `com.google.refine.history.Change` objects. `com.google.refine.history.Change` is an interface, and implementing classes are in `com.google.refine.model.changes.**`. Each change object stores enough data to modify the project's data when its `apply()` method is called, and enough data to revert its effect when its `revert()` method is called. It's only supposed to _store_ data, not to actually _compute_ the change. In this way, it's like a .diff patch file for a code base. + +Some change objects can be huge, as huge as the project itself. So change objects are not kept in memory except when they are to be applied or reverted. However, since we still need to show the user some information about changes (as displayed in the History panel in the UI), we keep metadata of changes separate from the change objects. For each change object there is one corresponding `com.google.refine.history.HistoryEntry` for storing its metadata, such as the change's human-friendly description and timestamp. + +Each project has a `com.google.refine.history.History` object that contains an ordered list of all `HistoryEntry` objects storing metadata for all changes that have been done since after the project was created. Actually, there are 2 ordered lists: one for done changes that can be reverted (undone), an done for undone changes that can be re-applied (redone). Changes must be done or redone in their exact orders in these lists because each change makes certain assumptions about the state of the project before and after it is applied. As changes cannot be undone/redone out of order, when one change fails to revert, it blocks the whole history from being reverted to any state preceding that change (as happened in [Issue #2](https://github.com/OpenRefine/OpenRefine/issues/2)). + +As mentioned before, a change contains only the diff and does not actually compute that diff. The computation is performed by a `com.google.refine.process.Process` object--every change object is created by a process object. A process can be immediate, producing its change object synchronously within a very short period of time (e.g., starring one row); or a process can be long-running, producing its change object after a long time and a lot of computation, including network calls (e.g., reconciling a column). + +As the user interacts with the UI on the client-side, their interactions trigger ajax calls to the server-side. Some calls are meant to modify the project. Those are handled by commands that instantiates processes. Processes are queued in a first-in-first-out basis. The first-in process gets run and until it is done all the other processes are stuck in the queue. + +A process can effect a change in one thing in the project (e.g., edit one particular cell, star one particular row), or a process can effect changes in _potentially_ many things in the project (e.g., edit zero or more cells sharing the same content, starring all rows filtered by some facets). The latter kind of process is generalizable: it is meaningful to apply them on another similar project. Such a process is associated with an _abstract operation_ `com.google.refine.model.AbstractOperation` that encodes the information necessary to create another instance of that process, but potentially for a different project. When you click "extract" in the History panel, these abstract operations are called to serialize their information to JSON; and when you click "apply" in the History panel, the JSON you paste in is used to re-construct these abstract operations, which in turn create processes, which get run sequentially in a queue to generate change object and history entry pairs. + +In summary, + +- change objects store diffs +- history entries store metadata of change objects +- processes compute diffs and create change object and history entry pairs +- some processes are long-running and some are immediate; processes are run sequentially in a queue +- generalizable processes can be re-constructed from abstract operations + +## Client-side architecture {#client-side-architecture} +The client-side part of OpenRefine is implemented in HTML, CSS and Javascript and uses the following Javascript libraries: +* [jQuery](http://jquery.com/) +* [jQueryUI](http:jqueryui.com/) +* [Recurser jquery-i18n](https://github.com/recurser/jquery-i18n) + +### Importing architecture {#importing-architecture} + +OpenRefine has a sophisticated architecture for accommodating a diverse and extensible set of importable file formats and work flows. The formats range from simple CSV, TSV to fixed-width fields to line-based records to hierarchical XML and JSON. The work flows allow the user to preview and tweak many different import settings before creating the project. In some cases, such as XML and JSON, the user also has to select which elements in the data file to import. Additionally, a data file can also be an archive file (e.g., .zip) that contains many files inside; the user can select which of those files to import. Finally, extensions to OpenRefine can inject functionalities into any part of this architecture. + +### The Index Page and Action Areas {#the-index-page-and-action-areas} + +The opening screen of OpenRefine is implemented by the file refine/main/webapp/modules/core/index.vt and will be referred to here as the index page. Its default implementation contains 3 finger tabs labeled Create Project, Open Project, and Import Project. Each tab selects an "action area". The 3 default action areas are for, obviously, creating a new project, opening an existing project, and importing a project .tar file. + +Extensions can add more action areas in Javascript. For example, this is how the Create Project action area is added (refine/main/webapp/modules/core/scripts/index/create-project-ui.js): + +```javascript +Refine.actionAreas.push({ + id: "create-project", + label: "Create Project", + uiClass: Refine.CreateProjectUI +}); +``` + +The UI class is a constructor function that takes one argument, a jQuery-wrapped HTML element where the tab body of the action area should be rendered. + +If your extension requires a very unique importing work flow, or a very novel feature that should be exposed on the index page, then add a new action area. Otherwise, try to use the existing work flows as much as possible. + +### The Create Project Action Area {#the-create-project-action-area} + +The Create Project action area is itself extensible. Initially, it embeds a set of finger tabs corresponding to a variety of "source selection UIs": you can select a source of data by specifying a file on your computer, or you can specify the URL to a publicly accessible data file or data feed, or you can paste in from the clipboard a chunk of data. + +There are actually 3 points of extension in the Create Project action area, and the first is invisible. + +#### Importing Controllers {#importing-controllers} + +The Create Project action area manages a list of "importing controllers". Each controller follows a particular work flow (in UI terms, think "wizard"). Refine comes with a "default importing controller" (refine/main/webapp/modules/core/scripts/index/default-importing-controller/controller.js) and its work flow assumes that the data can be retrieved and cached in whole before getting processed in order to generate a preview for the user to inspect. (If the data cannot be retrieved and cached in whole before previewing, then another importing controller is needed.) + +An importing controller is just programming logic, but it can manifest itself visually by registering one or more data source UIs and one or more custom panels in the Create Project action area. The default importing controller registers 3 such custom panels, which act like pages of a wizard. + +An extension can register any number of importing controller. Each controller has a client-side part and a server-side part. Its client-side part is just a constructor function that takes an object representing the Create Project action area (usually named `createProjectUI`). The controller (client-side) is expected to use that object to register data source UIs and/or create custom panels. The controller is not expected to have any particular interface method. The default importing controller's client-side code looks like this (refine/main/webapp/modules/core/scripts/index/default-importing-controller/controller.js): + +```javascript +Refine.DefaultImportingController = function(createProjectUI) { + this._createProjectUI = createProjectUI; // save a reference to the create project action area + + this._progressPanel = createProjectUI.addCustomPanel(); // create a custom panel + this._progressPanel.html('...'); // render the custom panel + ... do other stuff ... +}; +Refine.CreateProjectUI.controllers.push(Refine.DefaultImportingController); // register the controller +``` + +We will cover the server-side code below. + +#### Data Source Selection UIs {#data-source-selection-uis} + +Data source selection UIs are another point of extensibility in the Create Project action area. As mentioned previously, by default there are 3 data source UIs. Those are added by the default importing controller. + +Extensions can also add their own data source UIs. A data source selection UI object can be registered like so + +```javascript +createProjectUI.addSourceSelectionUI({ + label: "This Computer", + id: "local-computer-source", + ui: theDataSourceSelectionUIObject +}); +``` + +`theDataSourceSelectionUIObject` is an object that has the following member methods: + +- `attachUI(bodyDiv)` +- `focus()` + +If you want to install a data source selection UI that is managed by the default importing controller, then register its UI class with the default importing controller, like so (refine/main/webapp/modules/core/scripts/index/default-importing-sources/sources.js): + +```javascript +Refine.DefaultImportingController.sources.push({ + "label": "This Computer", + "id": "upload", + "uiClass": ThisComputerImportingSourceUI +}); +``` + +The default importing controller will assume that the `uiClass` field is a constructor function and call it with one argument--the controller object itself. That constructor function should save the controller object for later use. More specifically, for data source UIs that use the default importing controller, they can call the controller to kickstart the process that retrieves and caches the data to import: + +```javascript +controller.startImportJob(form, "... status message ..."); +``` + +The argument `form` is a jQuery-wrapped FORM element that will get submitted to the server side at the command /command/core/create-importing-job. That command and the default importing controller will take care of uploading or downloading the data, caching it, updating the client side's progress display, and then showing the next importing step when the data is fully cached. + +See refine/main/webapp/modules/core/scripts/index/default-importing-sources/sources.js for examples of such source selection UIs. While we write about source selection UIs managed by the default importing controller here, chances are your own extension will not be adding such a new source selection UI. Your extension probably adds with a new importing controller as well as a new source selection UI that work together. + +#### File Selection Panel {#file-selection-panel} +Documentation not currently available + +#### Parsing UI Panel {#parsing-ui-panel} +Documentation not currently available + +### Server-side Components {#server-side-components} + +#### ImportingController {#importingcontroller} +Documentation not currently available + +#### UrlRewriter {#urlrewriter} +Documentation not currently available + +#### FormatGuesser {#formatguesser} +Documentation not currently available + +#### ImportingParser {#importingparser} +Documentation not currently available + + +## Faceted browsing architecture {#faceted-browsing-architecture} + +Faceted browsing support is core to OpenRefine as it is the primary and only mechanism for filtering to a subset of rows on which to do something _en masse_ (ie in bulk). Without faceted browsing or an equivalent querying/browsing mechanism, you can only change one thing at a time (one cell or row) or else change everything all at once; both kinds of editing are practically useless when dealing with large data sets. + +In OpenRefine, different components of the code need to know which rows to process from the faceted browsing state (how the facets are constrained). For example, when the user applies some facet selections and then exports the data, the exporter serializes only the matching rows, not all rows in the project. Thus, faceted browsing isn't only hooked up to the data view for displaying data to the user, but it is also hooked up to almost all other parts of the system. + +### Engine Configuration {#engine-configuration} + +As OpenRefine is a web app, there might be several browser windows opened on the same project, each in a different faceted browsing state. It is best to maintain the faceted browsing state in each browser window while keeping the server side completely stateless with regard to faceted browsing. Whenever the client-side needs something done by the server, it transfers the entire faceted browsing state over to the server-side. The faceted browsing state behaves much like the `WHERE` clause in a SQL query, telling the server-side how to select the rows to process. + +In fact, it is best to think of the faceted browsing state as just a database query much like a SQL query. It can be passed around the whole system, to any component needing to know which rows to process. It is serialized into JSON to pass between the client-side and the server side, or to save in an abstract operation's specification. The job of the faceted browsing subsystem on the client-side is to let the user interactively modify this "faceted browsing query", and the job of the faceted browsing subsystem on the server side is to resolve that query. + +In the code, the faceted browsing state, or faceted browsing query, is actually called the *engine configuration* or *engine config* for short. It consists mostly of an array facet configurations. For each facet, it stores the name of the column on which the facet is based (or an empty string if there is no base column). Each type of facet has different configuration. Text search facets have queries and flags for case-sensitivity mode and regular expression mode. Text facets (aka list facets) and numeric range facets have expressions. Each list facet also has an array of selected choices, an invert flag, and flags for whether blank and error cells are selected. Each numeric range facet has, among other things, a "from" and a "to" values. If you trace the AJAX calls, you'd see the engine configs being shuttled, e.g., + +```json +{ + "facets" : [ + { + "type": "text", + "name": "Shrt_Desc", + "columnName": "Shrt_Desc", + "mode": "text", + "caseSensitive": false, + "query": "cheese" + }, + { + "type": "list", + "name": "Shrt_Desc", + "columnName": "Shrt_Desc", + "expression": "grel:value.toLowercase().split(\",\")", + "omitBlank": false, + "omitError": false, + "selection": [], + "selectBlank":false, + "selectError":false, + "invert":false + }, + { + "type": "range", + "name": "Water", + "expression": "value", + "columnName": "Water", + "selectNumeric": true, + "selectNonNumeric": true, + "selectBlank": true, + "selectError": true, + "from": 0, + "to": 53 + } + ], + "includeDependent": false + } +``` + +### Server-Side Subsystem {#server-side-subsystem} + +From an engine configuration like the one above, the server-side faceted browsing subsystem is capable of producing: + +- an iteration over the rows matching the facets' constraints +- information on how to render the facets (e.g., choice and count pairs for a list facet, histogram for a numeric range facet) + +When the engine config JSON arrives in an HTTP request on the server-side, a `com.google.refine.browsing.Engine` object is constructed and initialized with that JSON. It in turns constructs zero or more `com.google.refine.browsing.facets.Facet` objects. Then for each facet, the engine calls its `getRowFilter()` method, which returns `null` if the facet isn't constrained in anyway, or a `com.google.refine.browsing.filters.RowFilter` object. Then, to when iterating over a project's rows, the engine calls on all row filters' `filterRow()` method. If and only if all row filters return `true` the row is considered to match the facets' constraints. How each row filter works depends on the corresponding type of facet. + +To produce information on how to render a particular facet in the UI, the engine follows the same procedure described in the previous except it skips over the facet in question. In other words, it produces an iteration over all rows constrained by the other facets. Then it feeds that iteration to the facet in question by calling the facet's `computeChoices()` method. This gives the method a chance to compute the rendering information for its UI counterpart on the client-side. When all facets have been given a chance to compute their rendering information, the engine calls all facets to serialize their information as JSON and returns the JSON to the client-side. Only one HTTP call is needed to compute all facets. + +### Client-side subsystem {#client-side-subsystem} + +On the client-side there is also an engine object (implemented in Javascript rather than Java) and zero or more facet objects (also in Javascript, obviously). The engine is responsible for distributing the rendering information computed on the server-side to the right facets, and when the user interacts with a facet, the facet tells the engine to update the whole UI. To do so, the engine gathers the configuration of each facet and composes the whole engine config as a single JSON object. Two separate AJAX calls are made with that engine config, one to retrieve the rows to render, and one to re-compute the rendering information for the facets because changing one facet does affect all the other facets. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/build-test-run.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/build-test-run.md new file mode 100644 index 000000000..085070e64 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/build-test-run.md @@ -0,0 +1,270 @@ +--- +id: build-test-run +title: How to build, test and run +sidebar_label: How to build, test and run +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; + + +You will need: +* [OpenRefine source code](https://github.com/OpenRefine/OpenRefine) +* [Java JDK](http://java.sun.com/javase/downloads/index.jsp) (Get [OpenJDK from here](https://jdk.java.net/archive/). At the moment you cannot use JDK > 15, see [Issue on Github](https://github.com/OpenRefine/OpenRefine/issues/4106).) +* [Apache Maven](https://maven.apache.org) (OPTIONAL) +* A Unix/Linux shell environment OR the Windows command line + +From the top level directory in the OpenRefine application you can build, test and run OpenRefine using the `./refine` shell script (if you are working in a \*nix shell), or using the `refine.bat` script from the Windows command line. Note that the `refine.bat` on Windows only supports a subset of the functionality, supported by the `refine` shell script. The example commands below are using the `./refine` shell script, and you will need to use `refine.bat` if you are working from the Windows command line. + +### Set up JDK {#set-up-jdk} + +You must [install JDK](https://jdk.java.net/15/) and set the JAVA_HOME environment variable (please ensure it points to the JDK, and not the JRE). + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + + +1. On Windows 10, click the Start Menu button, type `env`, and look at the search results. Click Edit the system environment variables. (If you are using an earlier version of Windows, use the “Search†or “Search programs and files†box in the Start Menu.) + +![A screenshot of the search results for 'env'.](/img/env.png "A screenshot of the search results for 'env'.") + +2. Click Environment Variables… at the bottom of the Advanced window. +3. In the Environment Variables window that appears, click New… and create a variable with the key `JAVA_HOME`. You can set the variable for only your user account, as in the screenshot below, or set it as a system variable - it will work either way. + +![A screenshot of 'Environment Variables'.](/img/javahome.png "A screenshot of 'Environment Variables'.") + +4. Set the `Value` to the folder where you installed JDK, in the format `D:\Programs\OpenJDK`. You can locate this folder with the Browse directory... button. + + + + + +First, find where Java is on your computer with this command: + +``` +which java +``` + +Check the environment variable `JAVA_HOME` with: + +``` +$JAVA_HOME/bin/java --version +``` + +To set the environment variable for the current Java version of your MacOS: + +``` +export JAVA_HOME="$(/usr/libexec/java_home)" +``` + +Or, for Java 13.x: + +``` +export JAVA_HOME="$(/usr/libexec/java_home -v 13)" +``` + + + + + +##### With the terminal {#with-the-terminal} + +Enter the following: + +``` +sudo apt install default-jre +``` + +This probably won’t install the latest JDK package available on the Java website, but it is faster and more straightforward. (At the time of writing, it installs OpenJDK 11.0.7.) + +##### Manually {#manually} + +First, [extract the JDK package](https://openjdk.java.net/install/) to the new directory `usr/lib/jvm`: + +``` +sudo mkdir -p /usr/lib/jvm +sudo tar -x -C /usr/lib/jvm -f /tmp/openjdk-14.0.1_linux-x64_bin.tar.gz +``` + +Then, navigate to this folder and confirm the final path (in this case, `usr/lib/jvm/jdk-14.0.1`). Open a terminal and type + +``` +sudo gedit /etc/profile +``` + +In the text window that opens, insert the following lines at the end of the `profile` file, using the path above: + +``` +JAVA_HOME=/usr/lib/jvm/jdk-14.0.1 +PATH=$PATH:$HOME/bin:$JAVA_HOME/bin +export JAVA_HOME +export PATH +``` + +Save and close the file. When you are back in the terminal, type + +``` +source /etc/environment +``` + +Exit the terminal and restart your system. You can then check that `JAVA_HOME` is set properly by opening another terminal and typing +``` +echo $JAVA_HOME +``` + +It should show the path you set above. + + + + + +--- + + + +### Maven (Optional) {#maven-optional} +OpenRefine's build script will download Maven for you and use it, if not found already locally installed. + +If you will be using your Maven installation instead of OpenRefine's build script download installation, then set the `MVN_HOME` environment variable. You may need to reboot your machine after setting these environment variables. If you receive a message `Could not find the main class: com.google.refine.Refine. Program will exit.` it is likely `JAVA_HOME` is not set correctly. + +Ensure that you set your `MAVEN_HOME` environment variable, for example: + +```shell +MAVEN_HOME=E:\Downloads\apache-maven-3.5.4-bin\apache-maven-3.5.4\ +``` + +NOTE: You can use Maven commands directly, but running some goals in isolation might fail (try adding the `compile test-compile` goals in your invocation if that is the case). + +### Building {#building} + +To see what functions are supported by OpenRefine's build system, type +```shell +./refine -h +``` + +To build the OpenRefine application from source type: +```shell +./refine clean +./refine build +``` + +### Testing {#testing} +Since OpenRefine is composed of two parts, a server and a in-browser UI, the testing system reflects that: + +* on the server side, it's powered by [TestNG](http://testng.org/) and the unit tests are written in Java; +* on the client side, we use [Cypress](https://www.cypress.io/) and the tests are written in Javascript + +To run all tests, use: +```shell +./refine test +``` +**this option is not available when using refine.bat** + + +If you want to run only the server side portion of the tests, use: +```shell +./refine server_test +``` + +If you are running the UI tests for the first time, [you must go through the installation process.](functional-tests) +If you want to run only the client side portion of the tests, use: +```shell +./refine ui_test chrome +``` + +## Running {#running} +To run OpenRefine from the command line (assuming you have been able to build from the source code successfully) +```shell +./refine +``` +By default, OpenRefine will use [refine.ini](https://github.com/OpenRefine/OpenRefine/blob/master/refine.ini) for configuration. You can copy it and rename it to `refine-dev.ini`, which will be used for configuration instead. `refine-dev.ini` won't be tracked by Git, so feel free to put your custom configurations into it. + +## Building Distributions (Kits) {#building-distributions-kits} + +The Refine build system uses Apache Ant to automate the creation of the installation packages for the different operating systems. The packages are currently optimized to run on Mac OS X which is the only platform capable of creating the packages for all three OS that we support. + +To build the distributions type + +```shell +./refine dist +``` +where 'version' is the release version. + +## Building, Testing and Running OpenRefine from Eclipse {#building-testing-and-running-openrefine-from-eclipse} +OpenRefine' source comes with Maven configuration files which are recognized by [Eclipse](http://www.eclipse.org/) if the Eclipse Maven plugin (m2e) is installed. + +At the command line, go to a directory **not** under your Eclipse workspace directory and check out the source: + +```shell +git clone https://github.com/OpenRefine/OpenRefine.git +``` + +In Eclipse, invoke the `Import...` command and select `Existing Maven Projects`. + +![Screenshot of Import a Maven project option](/img/eclipse-import-maven-project-1.png) + +Choose the root directory of your clone of the repository. You get to choose which modules of the project will be imported. You can safely leave out the `packaging` module which is only used to generate the Linux, Windows and MacOS distributions. + +Screenshot of Select maven projects to import + +To run and debug OpenRefine from Eclipse, you will need to add an execution configuration on the `server` sub-project. +Right click on the `server` subproject, click `Run as...` and `Run configurations...` and create a new `Maven Build` run configuration. Rename the run configuration `OpenRefine`. Enter the root directory of the project as `Base directory` and use `exec:java` as a Maven goal. + +![Screenshot of Add a run configuration with the exec:java goal](/img/eclipse-exec-config.png) + +This will add a run configuration that you can then use to run OpenRefine from Eclipse. + +## Testing in Eclipse {#testing-in-eclipse} + +You can run the server tests directly from Eclipse. To do that you need to have the TestNG launcher plugin installed, as well as the TestNG M2E plugin (for integration with Maven). If you don't have it, you can get it by [installing new software](https://help.eclipse.org/2020-03/index.jsp?topic=/org.eclipse.platform.doc.user/tasks/tasks-129.htm) from this update URL http://dl.bintray.com/testng-team/testng-eclipse-release/ + +Once the TestNG launching plugin is installed in your Eclipse, right click on the source folder "main/tests/server/src", select `Run As` -> `TestNG Test`. This should open a new tab with the TestNG launcher running the OpenRefine tests. + +### Test coverage in Eclipse {#test-coverage-in-eclipse} + +It is possible to analyze test coverage in Eclipse with the `EclEmma Java Code Coverage` plugin. It will add a `Coverage as…` menu similar to the `Run as…` and `Debug as…` menus which will then display the covered and missed lines in the source editor. + +### Debug with Eclipse {#debug-with-eclipse} +Here's an example of putting configuration in Eclipse for debugging, like putting values for the Google Data extension. Other type of configurations that can be set are memory, Wikidata login information and more. + +![Screenshot of Eclipse debug configuration](/img/eclipse-debug-config.png) + +## Building, Testing and Running OpenRefine from IntelliJ idea {#building-testing-and-running-openrefine-from-intellij-idea} + +At the command line, go to a directory you want to save the OpenRefine project and execute the following command to clone the repository: + +```shell +git clone https://github.com/OpenRefine/OpenRefine.git +``` + +Then, open the IntelliJ idea and go to `file -> open` and select the location of the cloned repository. + +![Screenshot of Open option on the IntelliJ File menu](/img/intellij-setup-1.png) + +It will prompt you to add as a maven project as the source code contains a pom.xml file in it. Allow `auto-import` so that it can add it as a maven project. +If it doesn't prompt something like this then you can go on the right side of the IDE and click on maven then, click on `reimport all the maven projects` that will add all the dependencies and jar files required for the project. + +![Screenshot of Maven project controls in IntelliJ](/img/intellij-maven.png) + +After this, you will be able to properly build, test, and run the OpenRefine project from the terminal. +But if you will go to any of the test folders and open some file it will show you some import errors because the project isn't yet set up at the module level. + +For removing those errors, and enjoying the features of the IDE like ctrl + click, etc you need to set up the project at the module level too. Open the different modules like `extensions/wikidata`, `main` as a project in the IDE. Then, right-click on the project folder and open the module settings. + +![Screenshot of open module settings menu in IntelliJ](/img/intellij-open-module-settings.png) + +In the module settings, add the source folder and test source folders of that module. + +![Screenshot of module settings in IntelliJ](/img/intellij-module-settings.png) + +Then, do the same thing for the main OpenRefine project and now you are good to go. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/contributing.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/contributing.md new file mode 100644 index 000000000..241f5698c --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/contributing.md @@ -0,0 +1,69 @@ +--- +id: contributing +title: Contributing +sidebar_label: Contributing +--- + +Please read the general [guidelines on contributing to OpenRefine](https://github.com/OpenRefine/OpenRefine/blob/master/CONTRIBUTING.md) first, then review the information on [reporting and tracking issues](#reporting-and-tracking-issues), and on making your [first pull request](#your-first-pull-request) below) + +## Reporting and tracking issues {#reporting-and-tracking-issues} + +If you need to file a bug or request a feature, [create an Issue in the OpenRefine Github repository](https://github.com/OpenRefine/OpenRefine/issues). Github issues should be used for reporting specific bugs and requesting specific features. If you just don't know how to do something using OpenRefine, or want to discuss some ideas, please: + +- [Try the user manual](/) +- [post to our OpenRefine mailing list](http://groups.google.com/group/openrefine/) + +## Contributing to the documentation {#contributing-to-the-documentation} + +We use [Docusaurus](https://docusaurus.io/) for our docs. For small documentation changes, you should be able to edit the Markdown files directly and submit them as a pull request. A preview of the docs will be generated automatically. But it is also +possible to preview your changes locally. Assuming you have [Node.js](https://nodejs.org/en/download/) installed (which includes npm), you can install Docusaurus with: + +You will need to install [Yarn](https://yarnpkg.com/getting-started/install) before you can build the site. +```sh +npm install -g yarn +``` + +Once you have installed yarn, navigate to docs directory & set-up the dependencies. + +```sh +cd docs +yarn +``` + +Once this is done, generate the docs with: + +```sh +yarn build +``` + +You can also spin a local web server to serve the docs for you, with auto-refresh when you edit the source files, with: +```sh +yarn start +``` + +## Your first code pull request {#your-first-code-pull-request} + +This describes the overall steps to your first code contribution in OpenRefine. If you have trouble with any of these steps feel free to reach out on the [developer mailing list](https://groups.google.com/forum/#!forum/openrefine-dev) or the [Gitter channel](https://gitter.im/OpenRefine/OpenRefine). + +- Install OpenRefine, learn to use it by following some tutorials or watching [some videos](http://openrefine.org/). That will ensure you understand the user workflows and get familiar with the terminology used in the tool. + +- Fork the GitHub repository, clone it on your machine and set up your IDE to work on it. We have [instructions for this](https://github.com/OpenRefine/OpenRefine/wiki/Building-OpenRefine-From-Source). + +- Browse through the list of issues to find an issue that you find interesting. You should pick one where you understand what the problem is as a user, you can see why fixing it would be an improvement to the tool. It is also a good idea to pick an issue that matches your technical skills: some require work on the backend (in Java) or in the frontend (Javascript), often both. We try to maintain a list of [good first issues](https://github.com/OpenRefine/OpenRefine/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) which should be easier than others and should not require any difficult design decision. + +- Reproduce the issue locally, by following the steps described in the issue. You might need to locate a particular dialog, use a specific importer on a sample file, or follow any other user workflow. If you have followed all the steps described in the issue and cannot observe the issue mentioned, write a comment on the issue explaining that you are not able to reproduce it (perhaps it was fixed by another change). + +- Locate the code that is relevant for the issue you want to solve. Text search across files is often useful for that. For instance, if the issue you want to solve is about a dialog entitled "Columnize by key/values", you can search for "Columnize" in the entire source code. + +- Study how the current code works. You might want to use a debugger to put breakpoints at the relevant locations (for inspecting the backend, use your IDE's debugger, for the frontend, use your browser's developer tools). + +- Create a git branch for your fix. The name of your branch should contain the issue number, and a few words to describe the topic of the fix, for instance "issue-1234-columnize-layout". + +- Make changes to the code to fix the issue. If you are changing backend code, it would be great if you could also write a test in Java to demonstrate the fix. You can imitate existing tests for that. We currently do not have frontend tests. + +- commit your changes, using a message that contains "closes #1234" or "fixes #1234", this will link the commit to the issue you are working on. + +- push your branch to your fork and create a pull request for it, explaining the approach you have used, any design decisions you have made. + + +Thank you! diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/data-extension-api.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/data-extension-api.md new file mode 100644 index 000000000..683fbced9 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/data-extension-api.md @@ -0,0 +1,261 @@ +--- +id: data-extension-api +title: Data extension API +sidebar_label: Data extension API +--- + +This page describes a new optional API for reconciliation services, allowing clients to pull properties of reconciled records. It is supported from OpenRefine 2.8 onwards. A sample server implementation is available in the [Wikidata reconciliation interface](https://tools.wmflabs.org/openrefine-wikidata/). + +## Overview of the workflow {#overview-of-the-workflow} + +1. Reconcile a column with a standard reconciliation service + +2. Click "Add column from reconciled values" + +3. The user is proposed some properties to fetch, based on the type they reconciled their column against (if any). They can also pick their own property with the suggest widget (same as for the reconciliation dialog). + +4. A preview of the columns to be fetched is displayed on the right-hand side of the dialog, based on a sample of the rows. + +5. Once the user has clicked "OK", columns are fetched and added to the project. Columns corresponding to other items from the service are directly reconciled, and the column is marked as reconciled against the type suggested by the service for that +property. The user can run data extension again from that column. + +[GIF Screencast](http://pintoch.ulminfo.fr/92dcdd20f3/recorded.gif) + +## Specification {#specification} + +Services supporting data extension must add an `extend` field in their service metadata. This field is expected to have the following subfields, all optional: +* `propose_properties` stores the endpoint of an API which will be used to suggest properties to fetch (see specification below). The field contains an object with a `service_url` and `service_path` which will be concatenated to obtain the URL where the endpoint is available, just like the other services in the metadata. If this field is not provided, no property will be suggested in the dialog (the user will have to input them manually). +* `property_settings` stores the specification of a form where the user will be able to configure how a given property should be fetched (see specification below). If this field is not provided, the user will not be proposed with settings. + +The service endpoint must also accept a new parameter `extend` (in addition to `queries` which is used for reconciliation). Its behaviour is described in the following section. + +Example service metadata: +```json + "extend": { + "propose_properties": { + "service_url": "https://tools.wmflabs.org/openrefine-wikidata", + "service_path": "/en/propose_properties" + }, + "property_settings": [] + } +``` +### Property proposal protocol {#property-proposal-protocol} + +The role of the property proposal endpoint is to suggest a list of properties to fetch. As only input, it accepts GET parameters: +* the `type` of a column was reconciled against. If no type is provided, it should suggest properties for a column reconciled against no type. +* a `limit` on the number of results to return + +The type is specified by its id in the `type` GET parameter of the endpoint, as follows: + +https://tools.wmflabs.org/openrefine-wikidata/en/propose_properties?type=Q3354859&limit=3 + +The endpoint returns a JSON response as follows: + +```json + { + "properties": [ + { + "id": "P969", + "name": "located at street address" + }, + { + "id": "P1449", + "name": "nickname" + }, + { + "id": "P17", + "name": "country" + }, + ], + "type": "Q3354859", + "limit": 3 + } +``` +This endpoint must support JSONP via the `callback` parameter (just like all other endpoints of the reconciliation service). + +### Data extension protocol {#data-extension-protocol} + +After calling the property proposal endpoint, the consumer (OpenRefine) calls the service endpoint with a JSON object in the `extend` parameter, containing the following fields: +* `ids` is a list of strings, each of which being an identifier of a record as returned by the reconciliation method. These are the records whose properties should be retrieved. +* `properties` is a list of JSON objects. They specify the properties to be fetched for each item, and contain the following fields: + * `id` (a string): the identifier of the property as returned by the property suggest service (and optionally the property proposal service) + * `settings`: a JSON object storing parameters about how the property should be fetched (see below). + +Example: +```json + { + "ids": [ + "Q7205598", + "Q218765", + "Q845632", + "Q5661356" + ], + "properties": [ + { + "id": "P856" + }, + { + "id": "P159" + } + ] + } +``` +The service returns a JSON response formatted as follows: + +* `meta` contains a list of column metadata. The order of the properties must be the same + as the one provided in the query. Each element is an object containing the following keys: + * `id` (mandatory): the identifier of the property + * `name` (mandatory): the human-readable name of the property + * `type` (optional): an object with `id` and `name` keys representing the expected + type of values for that property. The notion of type is the same as the one + used for reconciliation. The `type` field should only be provided when the property returns + reconciled items. +* `rows` contains an object. Its keys must be exactly the record ids (`ids`) passed in the query. + The value for each record id is an object representing a row for that id. The keys of a row object must be exactly the property ids passed in the query (`"P856"` and `"P159"` in the example above). The value for a property id should be a list of cell objects. + +Cell objects are JSON objects which contain the representation of an OpenRefine cell. +* an object with a single `"str"` key and a string value for it represents + a cell with a (bare) string in it. + Example: `{"str": "193.54.0.0/15"}` + +* an object with `"id"` and `"name"` represents a reconciled value + (from the same reconciliation service). It will be stored as + a matched cell (with maximum reconciliation score). + Example: `{"name": "Warsaw","id": "Q270"}` + +* an empty object `{}` represents an empty cell + +* an object with `"date"` and an ISO-formatted date string represents a point in time. + Example: `{"date": "1987-02-01T00:00:00+00:00"}` + +* an object with `"float"` and a numerical value represents a quantity. + Example: `{"float": 48.2736}` + +* an object with `"int"` and an integer represents a number. + Example: `{"int": 54}` + +* an object with `"bool"` and `true` or `false` represents a boolean. + Example: `{"bool": false}` + +Example of a full response (for the example query above): +```json + { + "rows": { + "Q5661356": { + "P159": [], + "P856": [] + }, + "Q7205598": { + "P159": [ + { + "name": "Warsaw", + "id": "Q270" + } + ], + "P856": [ + { + "str": "http://www.polkomtel.com.pl/english" + }, + { + "str": "http://www.polkomtel.com.pl/" + } + ] + }, + "Q845632": { + "P159": [ + { + "name": "Bærum", + "id": "Q57076" + } + ], + "P856": [ + { + "str": "http://www.telenor.com/" + } + ] + }, + "Q218765": { + "P159": [ + { + "name": "Paris", + "id": "Q90" + } + ], + "P856": [ + { + "str": "http://www.sfr.fr/" + } + ] + } + }, + "meta": [ + { + "id": "P159", + "name": "headquarters location", + "type": { + "id": "Q7540126", + "name": "headquarters", + } + }, + { + "id": "P856", + "name": "official website", + } + ] + } +``` +### Settings specification {#settings-specification} + +The `property_settings` field in the service metadata allows the service to declare it accepts some settings for the properties it fetches. They are specified as a list of JSON objects which define the fields which should be exposed to the user. + +Each setting object looks like this: +```json + { + "default": 0, + "type": "number", + "label": "Limit", + "name": "limit", + "help_text": "Maximum number of values to return per row (0 for no limit)" + } +``` +It is essentially a definition of a form field in JSON, with self-explanatory fields. +The `type` field specifies the type of the form field (among `number`, `select`, `text`, `checkbox`). +The field `default` gives the default value of the form: the service must assume this value if the +client does not specify this setting. + +For the `select` field, an additional `choices` field defines the possible choices, with both labels and values: +```json + { + "default": "any", + "label": "References", + "name": "references", + "type": "select", + "choices": [ + { + "value": "any", + "name": "Any statement" + }, + { + "value": "referenced", + "name": "At least one reference" + }, + { + "value": "no_wiki", + "name": "At least one non-wiki reference" + } + ], + "help_text": "Filter statements by their references" + } +``` +When querying the service for rows, the client can pass an optional `settings` object in each of the requested columns: +```json + { + "id": "P342", + "settings": { + "limit": "20", + "references": "referenced", + } + } +``` +Each key of the settings object must correspond to one form field proposed by the service. The value of that key is the value of the form field represented as a string (for uniformity and consistency with JSON form serialization). +The settings are intended to modify the results returned by the service: of course, the semantics of the settings is up to the service (as the service defines itself what settings it accepts). diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/development-roadmap.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/development-roadmap.md new file mode 100644 index 000000000..da35f2f77 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/development-roadmap.md @@ -0,0 +1,29 @@ +--- +id: development-roadmap +title: Development roadmap +sidebar_label: Development roadmap +--- + +Please be aware that the OpenRefine roadmap is subject to change at any time, so please check back regularly, and monitor [milestones](https://github.com/OpenRefine/OpenRefine/milestones), [projects](https://github.com/OpenRefine/OpenRefine/projects) and [issues](https://github.com/OpenRefine/OpenRefine/issues) in Github to keep up to date with current plans. + +If there are features you would like to see that are not currently listed here or in current [milestones](https://github.com/OpenRefine/OpenRefine/milestones), [projects](https://github.com/OpenRefine/OpenRefine/projects) and [issues](https://github.com/OpenRefine/OpenRefine/issues), please add them to the [issue tracker](https://github.com/OpenRefine/OpenRefine/issues). + + +## Planned releases {#planned-releases} + +### 4.0 {#40} +[New backend storage option to allow using much bigger datasets at the expense of real-time feedback.](https://github.com/OpenRefine/OpenRefine/milestone/7) + +New UI (possibly Vue or React based) + +## Work in progress {#work-in-progress} +Alongside the planned releases there are often smaller pieces of work in progress. Check for [recently updated issues](https://github.com/OpenRefine/OpenRefine/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) and [pull requests](https://github.com/OpenRefine/OpenRefine/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc) to see what is currently in the works. + +## On the back burner {#on-the-back-burner} +Some aspects of OpenRefine have previously been targeted for release, but have not made it into a release and have not been worked on recently. If you would like to see features in these areas, please create an issue the describes what development you would like to see: + +- Streamlining traditional features +- Views: map, timeline, protovis (D3.js) charts +- Better machinery to guess and re-encode cell values (useful for fixing encoding issues) +- Collaborative editing support (see documentation on the '[broker protocol](https://github.com/OpenRefine/OpenRefine/wiki/Broker-Protocol)' to see where this work was going) +- Column groups diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/functional-tests.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/functional-tests.md new file mode 100644 index 000000000..8cece4b5e --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/functional-tests.md @@ -0,0 +1,239 @@ +--- +id: functional-tests +title: Functional tests +sidebar_label: Functional tests +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; + +## Introduction {#introduction} + +OpenRefine interface is tested with the [Cypress framework](https://www.cypress.io/). +With Cypress, tests are performing assertions using a real browser, the same way a real user would use the software. + +Cypress tests can be ran + +- using the Cypress test runner (development mode) +- using a command line (CI/CD mode) + +If you are writing tests, the Cypress test runner is good enough, and the command-line is mainly used by the CI/CD platform (Github actions) + +## Cypress brief overview {#cypress-brief-overview} + +Cypress operates insides a browser, it's internally using NodeJS. +That's a key difference with tools such as Selenium. + +**From the Cypress documentation:** + +> But what this also means is that your test code **is being evaluated inside the browser**. Test code is not evaluated in Node, or any other server side language. The **only** language we will ever support is the language of the web: JavaScript. + +Good starting points with Cypress are the [Getting started guide](https://docs.cypress.io/guides/getting-started/writing-your-first-test.html#Write-your-first-test), and the [Trade-offs](https://docs.cypress.io/guides/references/trade-offs.html#Permanent-trade-offs-1) + +The general workflow of a Cypress test is to + +- Start a browser (yarn run cypress open) +- Visit a URL +- Trigger user actions +- Assert that the DOM contains expected texts and elements using selectors + +## Getting started {#getting-started} + +If this is the first time you use Cypress, it is recommended for you to get familiar with the tool. + +- [Cypress overview](https://docs.cypress.io/guides/overview/why-cypress.html) +- [Cypress examples of tests and syntax](https://example.cypress.io/) + +### 1. Install Cypress {#1-install-cypress} + +You will need: + +- [Node.js 10 or 12 and above](https://nodejs.org) +- [Yarn or NPM](https://yarnpkg.com/) +- A Unix/Linux shell environment or the Windows command line + +To install Cypress and dependencies, run : + +```shell +cd ./main/tests/cypress +yarn install +``` + +### 2. Start the test runner {#2-start-the-test-runner} + +The test runner assumes that OpenRefine is up and running on the local machine, the tests themselves do not launch OpenRefine, nor restarts it. + +Start OpenRefine with + +```shell +./refine +``` + +Then start Cypress + +```shell +yarn --cwd ./main/tests/cypress run cypress open +``` + +### 3. Run the existing tests {#3-run-the-existing-tests} + +Once the test runner is up, you can choose to run one or several tests by selecting them from the interface. +Click on one of them and the test will start. + +### 4. Add your first test {#4-add-your-first-test} + +- Add a `test.spec.js` into the `main/tests/cypress/cypress/integration` folder. +- The test is instantly available in the list +- Click on the test +- Start to add some code + +## Tests technical documentation {#tests-technical-documentation} + +### A typical test {#a-typical-test} + +A typical OpenRefine test starts with the following code + +```javascript +it('Ensure cells are blanked down', function () { + cy.loadAndVisitProject('food.mini'); + cy.get('.viewpanel-sorting a').contains('Sort').click(); + cy.get('.viewpanel').should('to.contain', 'Something'); +}); +``` + +The first noticeable thing about a test is the description (`Ensure cells are blanked down`), which describes what the test is doing. +Lines usually starts with `cy.something...`, which is the main way to interact with the Cypress framework. + +A few examples: + +- `cy.get('a.my-class')` will retrieve the `` element +- `cy.click()` will click on the element +- eventually, `cy.should()` will perform an assertion, for example that the element contains an expected text with `cy.should('to.contains', 'my text')` + +On top of that, OpenRefine contributors have added some functions for common OpenRefine interactions. +For example + +- `cy.loadAndVisitProject` will create a fresh project in OpenRefine +- `cy.assertCellEquals` will ensure that a cell contains a given value + +See below on the dedicated section 'Testing utilities' + +### Testing guidelines {#testing-guidelines} + +- `cy.wait` should be used in the last resort scenario. It's considered a bad practice, though sometimes there is no other choice +- Tests should remain isolated from each other. It's best to try one feature at the time +- A test should always start with a fresh project +- The name of the files should mirror the OpenRefine UI organization + +### Testing utilities {#testing-utilities} + +OpenRefine contributors have added some utility methods on the top of the Cypress framework. +Those methods perform some common actions or assertions on OpenRefine, to avoid code duplication. + +Utilities can be found in `cypress/support/commands.js`. + +The most important utility method is `loadAndVisitProject`. +This method will create a fresh OpenRefine project based on a dataset given as a parameter. +The fixture parameter can be + +- An arbitrary array, the first row is for the column names, other rows are for the values + Use an arbitrary array **only** if the test requires some specific grid values + **Example:** + + ```javascript + const fixture = [ + ['Column A', 'Column B', 'Column C'], + ['0A', '0B', '0C'], + ['1A', '1B', '1C'], + ['2A', '2B', '2C'], + ]; + cy.loadAndVisitProject(fixture); + ``` + +- A referenced dataset: `food.small` or `food.mini` + Most of the time, tests does not require any specific grid values + Use food.mini as much as possible, it loads 2 rows and very few columns in the grid + Use food.small if the test requires a few hundred rows in the grid + + Those datasets live in `cypress/fixtures` + +### Browsers {#browsers} + +In terms of browsers, Cypress is using what is installed on your operating system. +See the [Cypress documentation](https://docs.cypress.io/guides/guides/launching-browsers.html#Browsers) for a list of supported browsers + +### Folder organization {#folder-organization} + +Tests are located in `main/tests/cypress/cypress` folder. +The test should not use any file outside the cypress folder. + +- `/fixtures` contains CSVs and OpenRefine project files used by the tests +- `/integration` contains the tests +- `/plugins` contains custom plugins for the OR project +- `/screenshots` and `/videos` contains the recording of the tests, Git ignored +- `/support` is a custom library of assertion and common user actions, to avoid code duplication in the tests themselves + +### Configuration {#configuration} + +Cypress execution can be configured with environment variables, they can be declared at the OS level, or when running the test + +Available variables are + +- OPENREFINE_URL, determine on which scheme://url:port to access OpenRefine, default to http://localhost:333 + +Cypress contains [exaustive documentation](https://docs.cypress.io/guides/guides/environment-variables.html#Setting) about configuration, but here are two simple ways to configure the execution of the tests: + +#### Overriding with a cypress.env.json file {#overriding-with-a-cypressenvjson-file} + +This file is ignored by Git, and you can use it to configure Cypress locally + +#### Command-line {#command-line} + +You can pass variables at the command-line level + +```shell +yarn --cwd ./main/tests/cypress run cypress open --env OPENREFINE_URL="http://localhost:1234" +``` + +### Visual testing {#visual-testing} + +Tests generally ensure application behavior by making assertions against the DOM, to ensure specific texts or css attributes are present in the document body. +Visual testing, on the contrary, is a way to test applications by comparing images. +A reference screenshot is taken the first time the test runs, and subsequent runs will compare a new screenshot against the reference, at the pixel level. + +Here is an [introduction to visual testing by Cypress](https://docs.cypress.io/plugins/directory#visual-testing). + +In some cases, we are using visual testing. +We are using [Cypress Image Snapshot](https://github.com/jaredpalmer/cypress-image-snapshot) + +Identified cases are so far: + +- testing images created by OpenRefine backend (scatterplots for example) + +Reference screenshots (Called snapshots), are stored in /cypress/snapshots. +And a snapshot can be taken for the whole page, or just a single part of the page. + +#### When a visual test fails {#when-a-visual-test-fails} + +First, Cypress will display the following error message: + +![Diff image when a visual test fails](/img/visual-test-cypress-failure.png) + +Then, a diff image will be created in /cypress/snapshots, this directory is ignored by Git. +The diff images shows the reference image on the left, the image that was taken during the test run on the right, and the diff in the middle. + +![Diff image when a visual test fails](/img/failed-visual-test.png) + +## CI/CD {#cicd} + +In CI/CD, tests are run headless, with the following command-line + +```shell +./refine ui_test chrome +``` + +Results are displayed in the standard output + +## Resources {#resources} + +[Cypress command line options](https://docs.cypress.io/guides/guides/command-line.html#Installation) +[Lots of good Cypress examples](https://example.cypress.io/) diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/homebrew-cask-process.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/homebrew-cask-process.md new file mode 100644 index 000000000..5615538f4 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/homebrew-cask-process.md @@ -0,0 +1,29 @@ +--- +id: homebrew-cask-process +title: Maintaining OpenRefine's Homebrew cask +sidebar_label: Maintaining OpenRefine's Homebrew cask +--- + +[Homebrew](https://brew.sh) is a popular command-line package manager for macOS. Once Homebrew is installed, OpenRefine can be installed via the simple command, `brew install openrefine`. OpenRefine's presence on Homebrew is found in the Homebrew Cask repository project, as a "cask", at https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/openrefine.rb. + +**Terminology:** "Homebrew Cask" is the segment of Homebrew where pre-built binaries and GUI applications go, whereas the original "Homebrew" project is reserved for command-line utilities that can be built from source. Because the macOS version of OpenRefine is released as an app bundle with GUI components, it is handled as a Homebrew Cask. + +When there is a new release of OpenRefine, registering the new release with Homebrew can be easily accomplished using Homebrew's `brew bump-cask-pr` command. Full directions for this utility as well as procedures for more complex PRs can be found on [the Homebrew Cask CONTRIBUTING page](https://github.com/Homebrew/homebrew-cask/blob/master/CONTRIBUTING.md), but, a simple version bump is a one-line command. For example, to update Homebrew's version of OpenRefine to 3.4.1, use this command: + +``` +brew bump-cask-pr --version 3.4.1 openrefine +``` + +This command will cause your local Homebrew installation to download the new version of OpenRefine, calculate the installer's new SHA-256 fingerprint value, and construct a pull request under your GitHub account. Once the pull request is submitted, continuous integration tests will run, and a member of the Homebrew community will review the PR. At times there is a backlog on the CI servers, but once tests pass, the community review is typically completed in a matter of hours. + +**Note:** It is important that the OpenRefine release tag and version number are identical, so that the Homebrew cask can find the installer's URL. This is because Homebrew's cask for OpenRefine uses the following formula for constructing the URL to OpenRefine's installer for a given release: + +``` +https://github.com/OpenRefine/OpenRefine/releases/download/#{version}/openrefine-mac-#{version}.dmg +``` + +That is, when you tell Homebrew that OpenRefine is now at version `3.4.1`, Homebrew will try to download the OpenRefine installed from the following URL: + +``` +https://github.com/OpenRefine/OpenRefine/releases/download/3.4.1/openrefine-mac-3.4.1.dmg +``` diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/migrating-older-extensions.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/migrating-older-extensions.md new file mode 100644 index 000000000..75f40015e --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/migrating-older-extensions.md @@ -0,0 +1,169 @@ +--- +id: migrating-older-extensions +title: Migrating older Extensions +sidebar_label: Migrating older Extensions +--- + +## Migrating from Ant to Maven {#migrating-from-ant-to-maven} + +### Why are we doing this change? {#why-are-we-doing-this-change} + +Ant is a fairly old (antique?) build system that does not incorporate any dependency management. +By migrating to Maven we are making it easier for developers to extend OpenRefine with new libraries, and stop having to ship dozens of .jar files in the repository. Using the Maven repository also encourages developers to add dependencies to released versions of libraries instead of custom snapshots that are hard to update. + +### When was this change made? {#when-was-this-change-made} + +The migration was done between 3.0 and 3.1-beta with this commit: +https://github.com/OpenRefine/OpenRefine/commit/47323a9e750a3bc9d43af606006b5eb20ca397b8 + +### How to migrate an extension {#how-to-migrate-an-extension} + +You will need to write a `pom.xml` in the root folder of your extension to configure the compilation process with Maven. Sample `pom.xml` files for extensions can be found in the extensions that are shipped with OpenRefine (`gdata`, `database`, `jython`, `pc-axis` and `wikidata`). A sample extension (`sample`) is also provided, with a minimal build file. + +For any library that your extension depends on, you should try to find a matching artifact in the Maven Central repository. If you can find such an artifact, delete the `.jar` file from your extension and add the dependency in your `pom.xml` file. If you cannot find such an artifact, it is still possible to incorporate your own `.jar` file using `maven-install-plugin` that you can configure in your `pom.xml` file as follows: + + + + org.apache.maven.plugins + maven-install-plugin + 2.5.2 + + + install-wdtk-datamodel + process-resources + + ${basedir}/lib/my-proprietary-library.jar + default + com.my.company + my-library + 0.5.3-SNAPSHOT + jar + true + + + install-file + + + + + + +And add the dependency to the `` section as usual: + + + com.my.company + my-library + 0.5.3-SNAPSHOT + + +## Migrating to Wikimedia's i18n jQuery plugin {#migrating-to-wikimedias-i18n-jquery-plugin} + +### Why are we doing this change? {#why-are-we-doing-this-change-1} + +This adds various important localization features, such as the ability to handle plurals or interpolation. This also restores the language fallback (displaying strings in English if they are not available in the target language) which did not work with the previous set up. + +### When was the migration made? {#when-was-the-migration-made} + +The migration was made between 3.1-beta and 3.1, with this commit: https://github.com/OpenRefine/OpenRefine/commit/22322bd0272e99869ab8381b1f28696cc7a26721 + +### How to migrate an extension {#how-to-migrate-an-extension-1} + +You will need to update your translation files, merging nested objets in one global object, concatenating keys. You can do this by running the following Python script on all your JSON translation files: + + import json + import sys + + with open(sys.argv[1], 'r') as f: + j = json.loads(f.read()) + + result = {} + def translate(obj, path): + res = {} + if type(obj) == str: + result['/'.join(path)] = obj + else: + for k, v in obj.items(): + new_path = path + [k] + translate(v, new_path) + + translate(j, []) + + with open(sys.argv[1], 'w') as f: + f.write(json.dumps(result, ensure_ascii=False, indent=4)) + +Then your javascript files which retrieve the translated strings should be updated: `$.i18n._('core-dialogs')['cancel']` becomes `$.i18n('core-dialogs/cancel')`. You can do this with the following `sed` script: + + sed -i "s/\$\.i18n._(['\"]\([A-Za-z0-9/_\\-]*\)['\"])\[['\"]\([A-Za-z0-9\-\_]*\)[\"']\]/$.i18n('\1\/\2')/g" my_javascript_file.js + +You can then chase down the places where you are concatenating translated strings, and replace that with more flexible patterns using [the plugin's features](https://github.com/wikimedia/jquery.i18n#jqueryi18n-plugin). + +## Migrating from org.json to Jackson {#migrating-from-orgjson-to-jackson} + +### Why are we doing this change? {#why-are-we-doing-this-change-2} + +The org.json (or json-java) library has multiple drawbacks. +* First, it has limited functionality - all the serialization and deserialization has to be done explicitly - an important proportion of OpenRefine's code was dedicated to implementing these; +* Second, its implementation is not optimized for speed - multiple projects have reported speedups when migrating to more modern JSON libraries; +* Third, and this was the decisive factor to initiate the migration: [its license](https://json.org/license) is the MIT license with an additional condition which makes it non-free. Getting rid of this dependency was required by the Software Freedom Conservancy as a prerequisite to become a fiscal sponsor for the project. + +### When was the migration made? {#when-was-the-migration-made-1} + +This change was made between 3.1 and 3.2-beta, with this commit: https://github.com/OpenRefine/OpenRefine/commit/5639f1b2f17303b03026629d763dcb6fef98550b + +### How to migrate an extension or fork {#how-to-migrate-an-extension-or-fork} + +You will need to use the Jackson library to serialize the classes that implement interfaces or extend classes exposed by OpenRefine. +The interface `Jsonizable` was deleted. Any class that used to implement this now needs to be serializable by Jackson, producing the same format as the previous serialization code. This applies to any operation, facet, overlay model or GREL function. If you are new to Jackson, have a look at [this tutorial](https://www.baeldung.com/jackson) to learn how to annotate your class for serialization. Once this is done, you can remove the `void write(JSONWriter writer, Properties options)` method from your class. Note that it is important that you do this migration for all classes implementing the `Jsonizable` interface that are exposed to OpenRefine's core. + +We encourage you to migrate out of org.json completely, but this is only required for the classes that interact with OpenRefine's core. + +#### General notes about migrating {#general-notes-about-migrating} + +OpenRefine's ObjectMapper is available at `ParsingUtilities.mapper`. It is configured to only serialize the fields and getters that have been explicitly marked with `@JsonProperty` (to avoid accidental JSON format changes due to refactoring). On deserialization it will ignore any field in the JSON payload that does not correspond to a field in the Java class. It has serializers and deserializers for `OffsetDateTime` and `LocalDateTime`. + +Useful snippets to use in tests: +* deserialize an instance: `MyClass instance = ParsingUtilities.mapper.readValue(jsonString, MyClass.class);` (replaces calls to `Jsonizable.write`); +* serialize an instance: `String json = ParsingUtilities.mapper.writeValueAsString(myInstance);` (replaces calls to static methods such as `load`, `loadStreaming` or `reconstruct`); +* the equivalent of `JSONObject` is `ObjectNode`, the equivalent of `JSONArray` is `ArrayNode`; +* create an empty JSON object: `ParsingUtilities.mapper.createObjectNode()` (replaces `new JSONObject()`); +* create an empty JSON array: `ParsingUtilities.mapper.createArrayNode()` (replaces `new JSONArray()`). + +Before undertaking the migration, we recommend that you write some tests which serialize and deserialize your objects. This will help you make sure that the JSON format is preserved during the migration. One way to do this is to collect some sample JSON representations of your objects, and check in your tests that deserializing these JSON payloads and serializing them back to JSON preserves the JSON payload. Some utilities are available to help you with that in [`TestUtils`](https://github.com/OpenRefine/OpenRefine/blob/master/main/tests/server/src/com/google/refine/tests/util/TestUtils.java) (we had [some to test org.json serialization](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/tests/server/src/com/google/refine/tests/util/TestUtils.java) before we got rid of the dependency, feel free to copy them). + +#### For functions {#for-functions} + +Before the migration, you had to explicitly define JSON serialization of functions with a `write` method. You should now override the getters returning the various documentation fields. + +Example: `Cos` function [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/expr/functions/math/Cos.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/expr/functions/math/Cos.java). + +#### For operations {#for-operations} + +Before the JSON migration we refactored engine-dependent operations so that the engine configuration is represented by an `EngineConfig` object instead of a `JSONObject`. Therefore the constructor for your operation should be updated to use this new class. Your constructor should also be annotated to be used during deserialization. + +Note that you do not need to explicitly serialize the operation type, this is already done for you by `AbstractOperation`. + +Example: `ColumnRemovalOperation` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/operations/column/ColumnRemovalOperation.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/operations/column/ColumnRemovalOperation.java). + +#### For changes {#for-changes} + +Changes are serialized in plain text but often relies on JSON serialization for parts of the data. Just use the methods above with `ParsingUtilities.mapper` to maintain this behaviour. + +Example: `ReconChange` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/model/changes/ReconChange.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/operations/column/ColumnRemovalOperation.java). + +#### For importers {#for-importers} + +The importing options have been migrated from `JSONObject` to `ObjectNode`. Your compiler should help you propagate this change. Utility functions in `JSONUtilities` have been migrated to Jackson so you should have minimal changes if you used them. + +Example: `TabularImportingParserBase` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/importers/TabularImportingParserBase.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/importers/TabularImportingParserBase.java). + +#### For overlay models {#for-overlay-models} + +Migrate serialization and deserialization as for other objects. + +Example: `WikibaseSchema` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/extensions/wikidata/src/org/openrefine/wikidata/schema/WikibaseSchema.java#L203) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/extensions/wikidata/src/org/openrefine/wikidata/schema/WikibaseSchema.java#L60) + +#### For preference values {#for-preference-values} + +Any class that is stored in OpenRefine's preference now needs to implement the `com.google.refine.preferences.PreferenceValue` interface. The static `load` method and the `write` method used previously for deserialization should be deleted and regular Jackson serialization and deserialization should be implemented instead. Note that you do not need to explicitly serialize the class name, this is already done for you by the interface. + +Example: `TopList` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/preference/TopList.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/preference/TopList.java) diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/openrefine-api.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/openrefine-api.md new file mode 100644 index 000000000..c1f0a9c0d --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/openrefine-api.md @@ -0,0 +1,281 @@ +--- +id: openrefine-api +title: OpenRefine API +sidebar_label: OpenRefine API +--- + +This is a generic API reference for interacting with OpenRefine's HTTP API. + +## Create project: {#create-project} + +> **Command:** _POST /command/core/create-project-from-upload_ + +When uploading files you will need to send the data as `multipart/form-data`. This is different to all other API calls which use a mixture of query string and POST parameters. + +multipart form-data: + + 'project-file' : file contents + 'project-name' : project name + 'format' : format of data in project-file (e.g. 'text/line-based/*sv') [optional] + 'options' : json object containing options relevant to the file format [optional - however, some importers may have required options, such as `recordPath` for the JSON & XML importers]. + +The formats supported will depend on the version of OpenRefine you are using and any Extensions you have installed. The common formats include: + +* 'text/line-based': Line-based text files +* 'text/line-based/*sv': CSV / TSV / separator-based files [separator to be used in specified in the json submitted to the options parameter] +* 'text/line-based/fixed-width': Fixed-width field text files +* 'binary/text/xml/xls/xlsx': Excel files +* 'text/json': JSON files +* 'text/xml': XML files + +If the format is omitted OpenRefine will try to guess the format based on the file extension and MIME type. +The values which can be specified in the JSON object submitted to the 'options' parameter will vary depending on the format being imported. If not specified the options will either be guessed at by OpenRefine (e.g. separator being used in a separated values file) or a default value used. The import options for each file format are not currently documented, but can be seen in the OpenRefine GUI interface when importing a file of the relevant format. + +If the project creation is successful, you will be redirected to a URL of the form: + + http://127.0.0.1:3333/project?project= + +From the project parameter you can extract the project id for use in future API calls. The content of the response is the HTML for the OpenRefine interface for viewing the project. + +### Get project models: {#get-project-models} + +> **Command:** _GET /command/core/get-models?_ + + 'project' : project id + +Recovers the models for the specific project. This includes columns, records, overlay models, scripting. In the columnModel a list of the columns is displayed, key index and name, and column groupings. + +### Response: {#response} +**On success:** +```JSON +{ + "columnModel":{ + "columns":[ + { + "cellIndex":0, + "originalName":"email", + "name":"email" + }, + { + "cellIndex":1, + "originalName":"name", + "name":"name" + }, + { + "cellIndex":2, + "originalName":"state", + "name":"state" + }, + { + "cellIndex":3, + "originalName":"gender", + "name":"gender" + }, + { + "cellIndex":4, + "originalName":"purchase", + "name":"purchase" + } + ], + "keyCellIndex":0, + "keyColumnName":"email", + "columnGroups":[ + + ] + }, + "recordModel":{ + "hasRecords":false + }, + "overlayModels":{ + + }, + "scripting":{ + "grel":{ + "name":"General Refine Expression Language (GREL)", + "defaultExpression":"value" + }, + "jython":{ + "name":"Python / Jython", + "defaultExpression":"return value" + }, + "clojure":{ + "name":"Clojure", + "defaultExpression":"value" + } + } +} +``` + + + +## Apply operations {#apply-operations} + +> **Command:** _POST /command/core/apply-operations?_ + +In the parameter + + 'project' : project id + +In the form data + + 'operations' : Valid JSON **Array** of OpenRefine operations + +Example of a Valid JSON **Array** +```JSON +'[ + { + "op":"core/column-addition", + "description":"Create column zip type at index 15 based on column Zip Code 2 using expression grel:value.type()", + "engineConfig":{ + "mode":"row-based", + "facets":[] + }, + "newColumnName":"zip type", + "columnInsertIndex":15, + "baseColumnName":"Zip Code 2", + "expression":"grel:value.type()", + "onError":"set-to-blank" + }, + { + "op":"core/column-addition", + "description":"Create column testing at index 15 based on column Zip Code 2 using expression grel:value.toString()0,5]", + "engineConfig":{ + "mode":"row-based", + "facets":[] + }, + "newColumnName":"testing", + "columnInsertIndex":15, + "baseColumnName":"Zip Code 2", + "expression":"grel:value.toString()[0,5]", + "onError":"set-to-blank" + } +] +``` + +On success returns JSON response +`{ "code" : "ok" }` + +## Export rows {#export-rows} + +> **Command:** _POST /command/core/export-rows_ + +In the parameter + + 'project' : project id + 'format' : format... (e.g 'tsv', 'csv') + +In the form data + + 'engine' : JSON string... (e.g. '{"facets":[],"mode":"row-based"}') + +Returns exported row data in the specified format. The formats supported will depend on the version of OpenRefine you are using and any Extensions you have installed. The common formats include: + +* csv +* tsv +* xls +* xlsx +* ods +* html + +## Delete project {#delete-project} + +> **Command:** _POST /command/core/delete-project_ + + 'project' : project id... + +Returns JSON response + +## Check status of async processes {#check-status-of-async-processes} + +> **Command:** _GET /command/core/get-processes_ + + 'project' : project id... + +Returns JSON response + +## Get all projects metadata: {#get-all-projects-metadata} + +> **Command:** _GET /command/core/get-all-project-metadata_ + +Recovers the meta data for all projects. This includes the project's id, name, time of creation and last time of modification. + +### Response: {#response-1} +```json +{ + "projects":{ + "[project_id]":{ + "name":"[project_name]", + "created":"[project_creation_time]", + "modified":"[project_modification_time]" + }, + ...[More projects]... + } +} +``` + +## Expression Preview {#expression-preview} +> **Command:** _POST /command/core/preview-expression_ + +Pass some expression (GREL or otherwise) to the server where it will be executed on selected columns and the result returned. + +### Parameters: {#parameters} +* **cellIndex**: _[column]_ +The cell/column you wish to execute the expression on. +* **rowIndices**: _[rows]_ +The rows to execute the expression on as JSON array. Example: `[0,1]` +* **expression**: _[language]_:_[expression]_ +The expression to execute. The language can either be grel, jython or clojure. Example: grel:value.toLowercase() +* **project**: _[project_id]_ +The project id to execute the expression on. +* **repeat**: _[repeat]_ +A boolean value (true/false) indicating whether or not this command should be repeated multiple times. A repeated command will be executed until the result of the current iteration equals the result of the previous iteration. +* **repeatCount**: _[repeatCount]_ +The maximum amount of times a command will be repeated. + +### Response: {#response-2} +**On success:** +```json +{ + "code": "ok", + "results" : [result_array] +} +``` + +The result array will hold up to ten results, depending on how many rows there are in the project that was specified by the [project_id] parameter. Each result is the string that would be put in the cell if the GREL command was executed on that cell. Note that any expression that would return an array or JSon object will be jsonized, although the output can differ slightly from the jsonize() function. + +**On error:** +```JSON +{ + "code": "error", + "type": "[error_type]", + "message": "[error message]" +} +``` + +## Third-party software libraries {#third-party-software-libraries} +Libraries using the [OpenRefine API](openrefine-api): + +### Python {#python} +* [refine-client-py](https://github.com/PaulMakepeace/refine-client-py/) + * Or this fork of the above with an extended CLI [openrefine-client](https://github.com/felixlohmeier/openrefine-client) +* [refine-python](https://github.com/maxogden/refine-python) + +### Ruby {#ruby} +* [refine-ruby](https://github.com/distillytics/refine-ruby) + * The above is a maintained fork of [google-refine](https://github.com/maxogden/refine-ruby) +* [google_refine](https://github.com/chengguangnan/google_refine) + +### NodeJS {#nodejs} +* [node-openrefine](https://github.com/pm5/node-openrefine) + +### R {#r} +* [rrefine](https://cran.r-project.org/web/packages/rrefine/index.html) + +### PHP {#php} +* [openrefine-php-client](https://github.com/keboola/openrefine-php-client) + +### Java {#java} +* [refine-java](https://github.com/dtap-gmbh/refine-java) + +### Bash {#bash} +* [bash-refine.sh](https://gist.github.com/felixlohmeier/d76bd27fbc4b8ab6d683822cdf61f81d) (templates for shell scripts) diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/reconciliation-api.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/reconciliation-api.md new file mode 100644 index 000000000..222cfef16 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/reconciliation-api.md @@ -0,0 +1,259 @@ +--- +id: reconciliation-api +title: Reconciliation API +sidebar_label: Reconciliation API +--- + +_This page is kept for the record. [A cleaner version of this specification](https://reconciliation-api.github.io/specs/0.1/) was written by the [W3C Entity Reconciliation Community Group](https://www.w3.org/community/reconciliation/), which has been formed to improve and promote this API. Join the community group to get involved!_ + +_This is a technical description of the mechanisms behind the reconciliation system in OpenRefine. For usage instructions, see [Reconciliation](/manual/reconciling)._ + +## Introduction {#introduction} + +A reconciliation service is a web service that, given some text which is a name or label for something, and optionally some additional details, returns a ranked list of potential entities matching the criteria. The candidate text does not have to match each entity's official name perfectly, and that's the whole point of reconciliation--to get from ambiguous text name to precisely identified entities. For instance, given the text "apple", a reconciliation service probably should return the fruit apple, the Apple Inc. company, and New York city (also known as the Big Apple). + +Entities are identified by strong identifiers in some particular identifier space. In the same identifier space, identifiers follow the same syntax. For example, given the string "apple", a reconciliation service might return entities identified by the strings " [Q89](https://www.wikidata.org/wiki/Q89)", "[Q312](https://www.wikidata.org/wiki/Q312)", and "[Q60](https://www.wikidata.org/wiki/Q60)", in the Wikidata ID space. Each reconciliation service can only reconcile to one single identifier space, but several reconciliation services can reconcile to the same identifier space. + +OpenRefine defines a reconciliation API so that users can use the reconciliation features of OpenRefine with various databases (this API was originally developed to work with the now deprecated "[Freebase](https://en.wikipedia.org/wiki/Freebase)" API). + +Informally, the main function of any reconciliation service is to find good candidates in the underlying database, given the following data: + +* A string, which is normally the name or title of the entity, in some language. +* Optionally, a type which can be used to narrow down the search to entities of this type. OpenRefine does not define a particular set of acceptable types: this choice is left to the reconciliation service (see the suggest API for that). +* Optionally, a list of properties and their values, which can be used to refine the search. For instance, when reconciling a database of books, the author name or the publication date are useful bits of information that can be transferred to the reconciliation service. This information will be sent to the reconciliation service if the user binds columns to properties. Again, the notion of property is not predefined in OpenRefine: its definition depends on the reconciliation service. + +A standard reconciliation service is a HTTP-based RESTful JSON-formatted API. It consists of various endpoints, each of which fulfills a specific function. Only the first one is mandatory. + +* The root URL. This is the URL that users will need to add the service to OpenRefine. For instance, the Wikidata reconciliation interface in English has the following URL: [https://tools.wmflabs.org/openrefine-wikidata/en/api](https://tools.wmflabs.org/openrefine-wikidata/en/api) +* _Optional._ The suggest API, which enables autocompletion at various places in OpenRefine; +* _Optional._ The preview API, which lets users preview the reconciled items directly from OpenRefine; +* _Optional._ The data extension API, which lets users add columns from reconciled values based on the properties of the items in the reconciliation service. + +The specification of each of these endpoints is given in the following sections. + +## Workflow overview {#workflow-overview} + +OpenRefine communicates with reconciliation services in the following way. + +* The user adds the service by inputting its endpoint in the dialog. OpenRefine queries this URL to retrieve its [service and metadata](reconciliation-api#service-metadata) which contains basic metadata about the service (such as its name and the available features). +* The user selects a service to configure reconciliation using this service. OpenRefine queries the reconciliation service in [batch mode](reconciliation-api#multiple-query-mode) on the first ten items of the column to be reconciled. The reconciliation results are not presented to the user, but the types of the candidate items are aggregated and proposed to the user to restrict the matching to one of them. For example, if your service reconciles both people and companies, and the query for the first 10 names returns 15 candidates which are people and 7 candidates which are companies, the types will be presented to the user in that order. They can override the order and pick whichever type they want, as well as chosen a different type by hand or choose to reconcile without any type information. +* The user configures the reconciliation. If a [suggest service](reconciliation-api#suggest-apis) is available, it will be used to provide auto-completion in the dialog, to choose types or properties. +* When reconciliation starts, OpenRefine queries the service in [batch mode](reconciliation-api#multiple-query-mode) for small batches of rows and stores the responses of the service. +* Once reconciliation is complete, the results are displayed. The user makes reconciliation decisions based on the choices provided. If a [suggest service](reconciliation-api#suggest-apis) is available, it will be used to input custom reconciliation decisions. If a [preview service](reconciliation-api#preview-api) is available, the user will be able to preview the reconciliation candidates without leaving OpenRefine. + +## Main reconciliation service {#main-reconciliation-service} + +The root URL has two functions: + +* it returns the [service and metadata](reconciliation-api#service-metadata) if no query is provided. +* when given the `queries` parameter, it performs a [set of queries in batch mode](reconciliation-api#multiple-query-mode) and returns the results for each query. This makes it efficient + +There is a deprecated "single query" mode which is used if the `query` parameter is given. This mode is no longer supported or used by OpenRefine and other API consumers should not rely on it. + +### Service metadata {#service-metadata} + +When a service is called with just a JSONP `callback` parameter and no other parameters, it must return its _service metadata_ as a JSON object literal with the following fields: + +* `"name"`: the name of the service, which will be used to display the service in the reconciliation menu; +* `"identifierSpace"`: an URI for the type of identifiers returned by the service; +* `"schemaSpace"`: an URI for the type of types understood by the service. +* `"view"` an object with a template URL to view a given item from its identifier: `"view": {"url":"http://example.com/object/{{id}}"} ` + +The last two parameters are mainly useful to assert that the identifiers returned by two different reconciliation services mean the same thing. Other fields are optional: they are used to specify the URLs for the other endpoints (suggest, preview and extend) described in the next sections. + +Here are two live examples: + +1. [https://tools.wmflabs.org/openrefine-wikidata/en/api](https://tools.wmflabs.org/openrefine-wikidata/en/api) +2. [http://refine.codefork.com/reconcile/viaf](http://refine.codefork.com/reconcile/viaf) + +```json +{ + "name" : "Wikidata Reconciliation for OpenRefine (en)", + "identifierSpace" : "http://www.wikidata.org/entity/", + "schemaSpace" : "http://www.wikidata.org/prop/direct/", + "view" : { + "url" : "https://www.wikidata.org/wiki/{{id}}" + }, + "defaultTypes" : [], + "preview" : { + ... + }, + "suggest" : { + ... + }, + "extend" : { + ... + }, +} +``` + +## Query Request {#query-request} + +### Multiple Query Mode {#multiple-query-mode} + +A call to a standard reconciliation service API for multiple queries looks like this: + + http://foo.com/bar/reconcile?queries={...json object literal...} + +The json object literal has zero or more key/value pairs with arbitrary keys where the value is in the same format as a single query, e.g. + + http://foo.com/bar/reconcile?queries={ "q0" : { "query" : "foo" }, "q1" : { "query" : "bar" } } + +"q0" and "q1" can be arbitrary strings. They will be used to key the results returned. + +For larger data, it can make sense to use POST requests instead of GET: + +```shell +curl -X POST -d 'queries={ "q0" : { "query" : "foo" }, "q1" : { "query" : "bar" } }' http://foo.com/bar/reconcile +``` + +OpenRefine uses POST for all requests, so make sure your service supports the format above. + +### **DEPRECATED** Single Query Mode {#deprecated-single-query-mode} + +A call to a reconciliation service API for a single query looks like either of these: + + http://foo.com/bar/reconcile?query=...string... + http://foo.com/bar/reconcile?query={...json object literal...} + +If the query parameter is a string, then it's an abbreviation of `query={"query":...string...}`. Here are two live examples: + +1. [https://tools.wmflabs.org/openrefine-wikidata/en/api?query=boston](https://tools.wmflabs.org/openrefine-wikidata/en/api?query=boston) +2. [https://tools.wmflabs.org/openrefine-wikidata/en/api?query={%22query%22:%22boston%22,%22type%22:%22Q515%22}](https://tools.wmflabs.org/openrefine-wikidata/en/api?query={%22query%22:%22boston%22,%22type%22:%22Q515%22}) + +### Query JSON Object {#query-json-object} + +The query json object literal has a few fields + +| Parameter | Description | +| --- | --- | +| "query" | A string to search for. Required. | +| "limit" | An integer to specify how many results to return. Optional. | +| "type" | A single string, or an array of strings, specifying the types of result e.g., person, product, ... The actual format of each type depends on the service (e.g., "Q515" as a Wikidata type). Optional. | +| "type\_strict" | A string, one of "any", "all", "should". Optional. | +| "properties" | Array of json object literals. Optional | + +Each json object literal of the `"properties"` array is of this form + +```json +{ + "p" : string, property name, e.g., "country", or + "pid" : string, property ID, e.g., "P17" as a Wikidata property ID + "v" : a single, or an array of, string or number or object literal, e.g., "Japan" + } +``` + +A `"v"` object literal would have a single key `"id"` whose value is an identifier resolved previously to the same identity space. + +Here is an example of a full query parameter: + +```json +{ + "query" : "Ford Taurus", + "limit" : 3, + "type" : "Q3231690", + "type_strict" : "any", + "properties" : [ + { "p" : "P571", "v" : 2009 }, + { "pid" : "P176" , "v" : { "id" : "Q20827633" } } + ] + } +``` + +## Query Response {#query-response} +For multiple queries, the response is a JSON literal object with the same keys as in the request + +```json +{ + "q0" : { + "result" : { ... } + }, + "q1" : { + "result" : { ... } + } + } +``` + +Each result consists of a JSON literal object with the structure + +```json +{ + "result" : [ + { + "id" : ... string, database ID ... + "name" : ... string ... + "type" : ... array of strings ... + "score" : ... double ... + "match" : ... boolean, true if the service is quite confident about the match ... + }, + ... more results ... + ], + ... potentially some useful envelope data, such as timing stats ... + } +``` + +The results should be sorted by decreasing score. +The service must also support JSONP through a callback parameter ie &callback=foo. + +## Preview API {#preview-api} + +The preview service API (complementary to the reconciliation service API) is quite simple. Pass it an identifier and it renders information about the corresponding entity in an HTML page, which will be shown in an iframe inside OpenRefine. The given width and height dimensions tell OpenRefine how to size that iframe. + +## Suggest APIs {#suggest-apis} + +In the "Start Reconciling" dialog box in OpenRefine, you can specify which type of entities the column in question contains. For instance, the column might contains titles of scientific journals. But you don't know the identifier corresponding to the "scientific journal" type. So we need a suggest API that translates "scientific journal" to something like, say, "[Q5633421](https://www.wikidata.org/wiki/Q5633421)" if we're reconciling against Wikidata. + +In the same dialog box, you can specify that other columns should be used to provide more details for the reconciliation. For instance, if there is a column specifying the journals ISSN (a standard identifier for serial publications), passing that data onto the reconciliation service might make reconciliation more accurate. You might want to specify how that second column is related to the column being reconciled, but you might not now how to specify "ISSN" as a precise relationship. So we need a suggest API that translates "ISSN" to something like "[P236](https://www.wikidata.org/wiki/Property:P236)" (once again using Wikidata as an example). + +There is also a need for a suggest service for entities rather than just for types and properties. When a cell has no good candidate, then you would want to perform a search yourself (by clicking on "search for match" in that cell). + +Each suggest API has 2 jobs to do: + +* translate what the user type into a ranked list of entities (and this is similar to the core reconciliation service and might share the same implementation) +* render a flyout when an entity is moused over or highlighted using arrow keys (and this is similar to the preview API and might share the same implementation) + +The metadata for each suggest API (type, property, or entity) is as follows: + +```json +{ + "service_url" : "... url including only the domain ...", + "service_path" : "... optional relative path ...", + "flyout_service_url" : "... optional url including only the domain ...", + "flyout_service_path" : "... optional relative path ..." +} +``` + +The `service_url` field is required and it should look like this: `http://foo.com`. There should be no trailing `/` at the end. The other fields are optional and have defaults if not provided: + +* `service_path` defaults to `/private/suggest` +* `flyout_service_url` defaults to the provided `service_url` field +* `flyout_service_path` defaults to `/private/flyout` + +Refer to [the Suggest API documentation](suggest-api) for further details. + +## Data Extension {#data-extension} + +From OpenRefine 2.8 it is possible to fetch values from reconcilied sources natively. This is only possible for the reconciliation endpoints that support this additional feature, described in the [Data Extension API documentation](Data-Extension-API). + +## Examples {#examples} + +We've cloned a number of the Refine reconciliation services as a way of providing them visibility. They can be found at [https://github.com/OpenRefine](https://github.com/OpenRefine) + +Some examples of reconciliation services which have made code available include: + +* [https://github.com/dergachev/redmine-reconcile](https://github.com/dergachev/redmine-reconcile) - Python & Flask implementation that just returns the given name/number with a base url prepended +* [https://github.com/okfn/helmut](https://github.com/okfn/helmut) - A generic Refine reconciliation API implementation using Python & Flask +* [https://github.com/mblwhoi/reconciliation_service_skeleton](https://github.com/mblwhoi/reconciliation_service_skeleton) - Skeleton for Standalone Python & Flask Reconciliation Service for Refine +* [https://github.com/mikejs/reconcile-demo](https://github.com/mikejs/reconcile-demo) +* [https://github.com/rdmpage/phyloinformatics/tree/master/services) - PHP examples (reconciliation\_\*.php](https://github.com/rdmpage/phyloinformatics/tree/master/services) +* [http://lucene.apache.org/solr/) and Python Django](https://github.com/opensemanticsearch/open-semantic-entity-search-api](https://github.com/opensemanticsearch/open-semantic-entity-search-api) - Open Source REST-API for Named Entity Extraction, Normalization, Reconciliation, Recommendation, Named Entity Disambiguation and Named Entity Linking of named entities in full-text documents by SKOS thesaurus, RDF ontologies, SQL databases and lists of names (powered by [Apache Solr) +* [https://github.com/granoproject/grano-reconcile](https://github.com/granoproject/grano-reconcile) - python example +* [https://github.com/codeforkjeff/conciliator](https://github.com/codeforkjeff/conciliator) - a Java framework for creating reconciliation services over the top of existing data sources. The code includes reconciliation services layered over [the Virtual International Authority File (VIAF)](http://viaf.org), [ORCID](http://orcid.org), [the Open Library](http://openlibrary.org) and [Apache Solr](http://lucene.apache.org/solr/). +* The open-reconcile project provides a complete Java based reconciliation service which queries a SQL database. [https://code.google.com/p/open-reconcile](https://code.google.com/p/open-reconcile) +* The [RDF Extension](http://refine.deri.ie) incorporates, among other things, reconciliation support with different approaches: + * a service to reconciliate against querying a SPARQL endpoint + * reconcile against a provided RDF file + * based on Apache Stanbol ([implementation details](https://github.com/fadmaa/grefine-rdf-extension/pull/59)) +* [Sunlight Labs](https://github.com/sunlightlabs) implemented a reconciliation service using Piston on Django for their [Influence Explorer](https://sunlightlabs.github.io/datacommons/). [The code is available](https://github.com/sunlightlabs/datacommons/blob/master/dcapi/reconcile/handlers.py) + +Also look at the [[Reconcilable Data Sources]] page for other examples of available reconciliation services that are compatible with Refine. Not all of them are open source, but they might spark some ideas. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/suggest-api.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/suggest-api.md new file mode 100644 index 000000000..fdb49299c --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/suggest-api.md @@ -0,0 +1,101 @@ +--- +id: suggest-api +title: Suggest API +sidebar_label: Suggest API +--- + +The Suggest API has 2 entry points: + +- `suggest`: translates some text that the user has typed, optionally constrained in some ways, to a ranked list of entities (this is very similar to a [Reconciliation API](reconciliation-api) and can share the same implementation) +- `flyout` : renders a small view of an entity + +For the `suggest` entry point, it is important to balance speed versus accuracy. The widget must respond in interactive time, meaning about 200 msec, for each change to the user's text input. At the same time, the ranked list of entities must seem quite relevant to what the user types. + +Similarly, for the `flyout` entry point, it is important to respond quickly while providing enough essential details so that the user can visually check if the highlighted entity is the desired one. You probably would want to embed a thumbnail image, as we have found that images are excellent for visual identification. + +## suggest Entry Point {#suggest-entry-point} + +The `suggest` entry point takes the following URL parameters + +Parameter | Description | Required/Optional +----------|-----------------------------|------------------ + "prefix" | a string the user has typed | required + "type" | optional, a single string, or an array of strings, specifying the types of result e.g., person, product, ... The actual format of each type depends on the service | optional | + "type\_strict" | optional, a string, one of "any", "all", "should" | optional | + "limit" | optional, an integer to specify how many results to return | optional | + "start" | optional, an integer to specify the first result to return (thus in conjunction with `limit`, support pagination) | optional | + +The Suggest API should return results as JSON (JSONP must also be supported). The JSON should consist of a 'result' array containing objects with at least a 'name' and 'id'. The JSON response can optionally include other information as illustrated in this structure for a full JSON response: +```json + { + "code" : "/api/status/ok", + "status" : "200 OK", + "prefix" : ... string, the prefix URL parameter echoed back ... + "result" : [ + { + "id" : ... string, identifier of entity ... + "name" : ... string, nameof entity ... + "notable" : [{ + "id" : ... string, identifier of type ... + "name" : ... string, name of type ... + }, ...] + }, + ... more results ... + ], + } +``` + +* `code` (optional) error/success state of the API above the level of HTTP. Use "/api/status/ok" for a successful request and "/api/status/error" if there has been an error. +* `status` (optional) should correspond to the HTTP response code. +* `prefix` (optional) the query string submitted to the Suggest API. +* `result` (required) array containing multiple results from the Suggest API consisting of at least an id and name. +* `id` (required) the id of an entity being suggested by the Suggest API +* `name` (required) a short string which labels or names the entity being suggested by the Suggest API +* `description` (optional) a short description of the item, which will be displayed below the name +* `notable` (optional) is a a list of JSON objects that describes the types of the entity. They are rendered in addition to the entity's name to provide more disambiguation details and stored in the reconciliation data of the cells. This list can also be supplied as a list of type identifiers (such as `["Q5"]` instead of `[{"id":"Q5","name":"human"}]`). + +Here is an example of a minimal request and response using the Suggest API layered over [Wikidata](https://www.wikidata.org): + +URL: https://tools.wmflabs.org/openrefine-wikidata/en/suggest/entity?prefix=A5 +JSON response: + +```json +{ + "result": [ + { + "name": "A5", + "description": "road", + "id": "Q429719" + }, + { + "name": "Apple A5", + "description": null, + "id": "Q420764" + }, + { + "name": "A5 autoroute", + "description": "controlled-access highway from Paris's Francilienne to the A31 near Beauchemin", + "id": "Q788832" + }, + ... + ] +} +``` + +## flyout Entry Point {#flyout-entry-point} + +The `flyout` entry point takes a single URL parameter: `id`, which is the identifier of the entity to render, as a string. It also takes a `callback` parameter to support JSONP. It returns a JSON object literal with a single field: `html`, which is the rendered view of the given entity. + +Here is an example of a minimal request and response using the Suggest API layered over [[Wikidata](https://www.wikidata.org) with only the required fields in each case: + +URL: https://tools.wmflabs.org/openrefine-wikidata/en/flyout/entity?id=Q786288 +JSON response: + +```json +{ + "html": "

national road in Latvia

", + "id": "Q786288" +} +``` + +OpenRefine incorporates a set of `fbs-` CSS class names which can be used in the flyout HTML if desired to render the flyout information in a standard style. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/technical-reference-index.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/technical-reference-index.md new file mode 100644 index 000000000..170b60958 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/technical-reference-index.md @@ -0,0 +1,7 @@ +--- +id: technical-reference-index +title: OpenRefine technical reference +sidebar_label: Technical Reference Index +--- + +Technical reference index diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/translating.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/translating.md new file mode 100644 index 000000000..73de2fee3 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/translating.md @@ -0,0 +1,105 @@ +--- +id: translating +title: Translate the OpenRefine interface +sidebar_label: Translate the OpenRefine interface +--- + +Currently supported languages include English, Spanish, Chinese, French, Hebrew, Italian and Japanese. + +![Translation status](https://hosted.weblate.org/widgets/openrefine/-/287x66-grey.png) + +You can help translate OpenRefine into your language by visiting [Weblate](https://hosted.weblate.org/engage/openrefine/?utm_source=widget) which provides a web based UI to edit and add translations and sends automatic pull requests back to our project. + +Click to help translate --> [Weblate](https://hosted.weblate.org/engage/openrefine/?utm_source=widget) + +## User entry of language data ## {#user-entry-of-language-data-} + +Localized strings are entered in a .json file, one per language. They are located in the folder `main/webapp/modules/core/langs/` in a file named `translation-xx`.json, where xx is the language code (i.e. fr for French). + +### Simple case of localized string ### {#simple-case-of-localized-string-} +This is an example of a simple string, with the start of the JSON file. This example is for French. +``` +{ + "name": "Français", + "core-index/help": "Aide", + (… more lines) +} +``` + +So the key `core-index/help` will render as `"Aide"` in French. + +### Localization with a parameterized value ### {#localization-with-a-parameterized-value-} +In this example, the name of the column (represented by `$1` in this example), will be substituted with the string of the name of the column. + +`"core-facets/edit-facet-title": "Cliquez ici pour éditer le nom de la facette\nColonne : $1",` + +### Localization with a singular/plural value ### {#localization-with-a-singularplural-value-} +In this example, one of the parameter will have a different string depending if the value is 1 or another value. +In this example, the string for page, the second parameter, `$2`, will have an « s » or not depending on the value of `$2`. + +`"core-views/goto-page": "$1 de $2 {{plural:$2|page|pages}}"` + +## Front End Coding {#front-end-coding} + +The OpenRefine front end has been localized using the [Wikidata jquery.i18n library](https://github.com/OpenRefine/OpenRefine/pull/1285. The localized text is stored in a JSON dictionary on the server and retrieved with a new OpenRefine command. + +### Adding a new string {#adding-a-new-string} + +There should be no hard-coded language strings in the HTML or JSON used for the front end. If you need a new string, first check the existing strings to make sure there isn't an equivalent string, **in an equivalent context**, that you can reuse. Context is important because it can affect how the same literal English text is translated. This cuts down on the amount of text which needs to be translated. + +Strings should be entire sentences or phrases and should include substitution variables for any parameters. Do not concatenate strings in either Java or Javascript (or implicitly by laying them out in a specific order). So, instead of `"You have " + count + " row(s)"` (or worse `count != 1 ? " rows" : " row"`), internationalize everything together so that it can be translated taking into account word ordering and plurals for different languages, ie `"You have $1 {{plural $1: row|rows}}"`, passing the parameter(s) into the `$.i18n` call. + +If there's no string you can reuse, allocate an available key in the appropriate translation dictionary and add the default string, e.g. + +```json +..., +"section/newkey": "new default string for this key", +... +``` + +and then set the text (or HTML) of your HTML element using i18n helper method. So given an HTML fragment like: +```html + +``` +we could set its text using: +``` +$('#new-html-element-id').text($.i18n('section/newkey'])); +``` +or, if you need to embed HTML tags: +``` +$('#new-html-element-id').html($.i18n('section/newkey']); +``` + +### Adding a new language {#adding-a-new-language} + +The language dictionaries are stored in the `langs` subdirectory for the module e.g. + +* https://github.com/OpenRefine/OpenRefine/tree/master/main/webapp/modules/core/langs for the main interface +* https://github.com/OpenRefine/OpenRefine/tree/master/extensions/gdata/module/langs for google spreadsheet connection +* https://github.com/OpenRefine/OpenRefine/tree/master/extensions/database/module/langs for database via JDBC +* https://github.com/OpenRefine/OpenRefine/tree/master/extensions/wikidata/module/langs for Wikidata + +To add support for a new language, copy `translation-en.json` to `translation-.json` and have your translator translate all the value strings (ie right hand side). + +#### Main interface {#main-interface} + The translation is best done [with Weblate](https://hosted.weblate.org/engage/openrefine/?utm_source=widget). Files are periodically merged by the developer team. + +Run the latest (hopefully cloned from github) version and check whether translated words fit to the layout. Not all items can be translated word by word, especially into non-IÌ€ndo-European languages. + +If you see any text which remains in English even when you have checked all items, please create bug report in the issue tracker so that the developers can fix it. + +#### Extensions {#extensions} + +Extensions can be translated via Weblate just like the core software. + +The new extension for Wikidata contains lots of domain-specific concepts, with which you may not be familiar. The Wikidata may not have reconciliation service for your language. I recommend checking the glossary(https://www.wikidata.org/wiki/Wikidata:Glossary) to be consistent. + +By default, the system tries to load the language file corresponding to the currently in-use browser language. To override this setting a new menu item ("Language Settings") has been added at the index page. +To support a new language file, the developer should add a corresponding entry to the dropdown menu in this file: `/OpenRefine/main/webapp/modules/core/scripts/index/lang-settings-ui.html`. The entry should look like: +```javascript + +``` + +## Server / Backend Coding {#server--backend-coding} + +Currently no back end functions are translated, so things like error messages, undo history, etc may appear in English form. Rather than sending raw error text to the front end, it's better to send an error code which is translated into text on the front end. This allows for multiple languages to be supported. diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/version-release-process.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/version-release-process.md new file mode 100644 index 000000000..55ea4ec85 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/version-release-process.md @@ -0,0 +1,5 @@ +--- +id: version-release-process +title: How to do an OpenRefine version release +sidebar_label: How to do an OpenRefine version release +--- diff --git a/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/writing-extensions.md b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/writing-extensions.md new file mode 100644 index 000000000..3511cc31f --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.4/technical-reference/writing-extensions.md @@ -0,0 +1,326 @@ +--- +id: writing-extensions +title: Writing Extensions +sidebar_label: Writing Extensions +--- + +## Introduction {#introduction} + +This is a very brief overview of the structure of OpenRefine extensions. For more detailed documentation and step-by-step guides please see the following external documentation/tutorials: + +* Giuliano Tortoreto has [written documentation detailling how to build extension for OpenRefine](https://github.com/giTorto/OpenRefineExtensionDoc/raw/master/main.pdf) +* Owen Stephens has written [a guide to developing an extension which adds new GREL functions to OpenRefine](http://www.meanboyfriend.com/overdue_ideas/2017/05/writing-an-extension-to-add-new-grel-functions-to-openrefine/). + +OpenRefine makes use of a modified version of the [Butterfly framework](https://github.com/OpenRefine/simile-butterfly/tree/openrefine) to provide an extension architecture. OpenRefine extensions are Butterfly modules. You don't really need to know about Butterfly itself, but you might encounter "butterfly" here and there in the code base. + +Extensions that come with the code base are located under [the extensions subdirectory](https://github.com/OpenRefine/OpenRefine/tree/master/extensions), but when you develop your own extension, you can put its code anywhere as long as you point Butterfly to it. That is done by any one of the following methods + +* refer to your extension's directory in [the butterfly.properties file](https://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/WEB-INF/butterfly.properties) through a `butterfly.modules.path` setting. +* specify the butterfly.modules.path property on the command line when you run OpenRefine. This overrides the values in the property file, so you need to include the default values first e.g. `-Dbutterfly.modules.path=modules,../../extensions,/path/to/your/extension` + +Please note that you should bundle any dependencies yourself, so you are insulated from OpenRefine packaging changes over time. + +### Directory Layout {#directory-layout} + +A OpenRefine extension sits in a file directory that contains the following files and sub-directories: + +``` +pom.xml + src/ + com/foo/bar/... *.java source files + module/ + *.html, *.vt files + scripts/... *.js files + styles/... *.css and *.less files + images/... image files + MOD-INF/ + lib/*.jar files + classes/... java class files + module.properties + controller.js +``` + +The file named module.properties (see [example](https://github.com/OpenRefine/OpenRefine/blob/master/extensions/sample/module/MOD-INF/module.properties)) contains the extension's metadata. Of importance is the name field, which gives the extension a name that's used in many other places to refer to it. This can be different from the extension's directory name. + +``` +name = my-extension-name +``` + +Your extension's client-side resources (.html, .js, .css files) stored in the module/ subdirectory will be accessible from http://127.0.0.1:3333/extension/my-extension-name/ when OpenRefine is running. + +Also of importance is the dependency + +``` +requires = core +``` + +which makes sure that the core module of OpenRefine is loaded before the extension attempts to hook into it. + +The file named controller.js is responsible for registering the extension's hooks into OpenRefine. Look at the sample-extension extension's [controller.js](https://github.com/OpenRefine/OpenRefine/blob/master/extensions/sample/module/MOD-INF/controller.js) file for an example. It should have a function called init() that does the hook registrations. + +The `pom.xml` file is an [Apache Maven](http://maven.apache.org/) build file. You can make a copy of the sample extension's `pom.xml` file to get started. The important point here is that the Java classes should be built into the `module/MOD-INF/classes` sub-directory. + +Note that your extension's Java code would need to reference some libraries used in OpenRefine and OpenRefine's Java classes themselves. These dependencies are reflected in the Maven configuration for the extension. + +## Sample extension {#sample-extension} + +The sample extension is included in the code base so that you can copy it and get started on writing your own extension. After you copy it, make sure you change its name inside its `module/MOD-INF/controller.js` file. + +### Basic Structure {#basic-structure} + +The sample extension's code is in `refine/extensions/sample/`. In that directory, Java source code is contained under the `src` sub-directory, and webapp code is under the `module` sub-directory. Here is the full directory layout: + +``` +refine/extensions/sample/ + build.xml (ant build script) + src/ + com/google/refine/sampleExtension/ + ... Java source code ... + module/ + MOD-INF/ + module.properties (module settings) + controller.js (module init and routing logic in Javascript) + classes/ + ... compiled Java classes ... + lib/ + ... Java jars ... + ... velocity templates (.vt) ... + ... LESS css files ... + ... client-side files (.html, .css, .js, image files) ... +``` + +The sub-directory `MOD-INF` contains the Butterfly module's metadata and is what Butterfly looks for when it scans directories for modules. `MOD-INF` serves similar functions as `WEB-INF` in other web frameworks. + +Java code is built into the sub-directory `classes` inside `MOD-INF`, and supporting external Java jars are in the `lib` sub-directory. Those will be automatically loaded by Butterfly. (The build.xml script is wired to compile into the `classes` sub-directory.) + +Client-side code is in the inner `module` sub-directory. They can be plain old .html, .css, .js, and image files, or they can be [LESS](http://lesscss.org/) files that get processed into CSS. There are also Velocity .vt files, but they need to be routed inside `MOD-INF/controller.js`. + +`MOD-INF/controller.js` lets you configure the extension's initialization and URL routing in Javascript rather than in Java. For example, when the requested URL path is either `/` or an empty string, we process and return `MOD-INF/index.vt` ( [see http://127.0.0.1:3333/extension/sample/](http://127.0.0.1:3333/extension/sample/) if OpenRefine is running). + +The `init()` function in `controller.js` allows the extension to register various client-side handlers for augmenting pages served by Refine's core. These handlers are feature-specific. For example, [this is where the jython extension adds its parser](https://github.com/OpenRefine/OpenRefine/blob/master/extensions/jython/module/MOD-INF/controller.js#L46). As for the sample extension, it adds its script `project-injection.js` and style `project-injection.less` into the `/project` page. If you [view the source of the /project page](http://127.0.0.1:3333/project), you will see references to those two files. + +### Wiring Up the Extension {#wiring-up-the-extension} + +The Extensions are loaded by the Butterfly framework. Butterfly refers to these as 'modules'. [The location of modules is set in the `main/webapp/butterfly.properties` file](https://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/WEB-INF/butterfly.properties#L27). Butterfly simply descends into each of those paths and looks for any `MOD-INF` directories. + +For more information, see [Extension Points](https://github.com/OpenRefine/OpenRefine/wiki/Extension-Points). + +## Extension points {#extension-points} + +### Client-side: Javascript and CSS {#client-side-javascript-and-css} + +The UI in OpenRefine for working with a project is coded in [the /main/webapp/modules/core/project.vt file](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/project.vt). The file is quite small, and that's because almost all of its content is to be expanded dynamically through the Velocity variables $scriptInjection and $styleInjection. So that your own Javascript and CSS files get loaded, you need to register them with the ClientSideResourceManager, which is done in the /module/MOD-INF/controller.js file. See [the controller.js file in this sample extension code](http://github.com/OpenRefine/OpenRefine/blob/master/extensions/sample/module/MOD-INF/controller.js) for an example. + +In the registration call, the variable `module` is already available to your code by default, and it refers to your own extension. + +``` +ClientSideResourceManager.addPaths( + "project/scripts", + module, + [ + "scripts/foo.js", + "scripts/subdir/bar.js" + ] + ); +``` + +You can specify one or more files for registration, and their paths are relative to the `module` subdirectory of your extension. They are included in the order listed. + +Javascript Bundling: Note that `project.vt` belongs to the core module and is thus under the control of the core module's [controller.js file](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/MOD-INF/controller.js). The Javascript files to be included in `project.vt` are by default bundled together for performance. When debugging, you can prevent this bundling behavior by setting `bundle` to `false` near the top of that `controller.js` file. (If you have commit access to this code base, be sure not to check that change in.) + +### Client-side: Images {#client-side-images} + +We recommend that you always refer to images through your CSS files rather than in your Javascript code. URLs to images will thus be relative to your CSS files, e.g., + +``` +.foo { + background: url(../images/x.png); + } +``` + +If you really really absolutely need to refer to your images in your Javascript code, then look up your extension's URL path in the global Javascript variable `ModuleWirings`: + +``` +ModuleWirings["my-extension"] + "images/x.png" +``` + +### Client-side: HTML Templates {#client-side-html-templates} + +Beside Javascript, CSS, and images, your extension might also include HTML templates that get loaded on the fly by your Javascript code and injected into the page's DOM. For example, here is [the Cluster edit dialog template](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/scripts/dialogs/clustering-dialog.html), which gets loaded by code in [the equivalent javascript file 'clustering-dialog.js'](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/scripts/dialogs/clustering-dialog.js): + +``` +var dialog = $(DOM.loadHTML("core", "scripts/dialogs/clustering-dialog.html")); +``` + +`DOM.loadHTML` returns the content of the file as a string, and `$(...)` turns it into a DOM fragment. Where `"core"` is, you would want your extension's name. The path of the HTML file is relative to your extension's `module` subdirectory. + +### Client-side: Project UI Extension Points {#client-side-project-ui-extension-points} + +Getting your extension's Javascript code included in `project.vt` doesn't accomplish much by itself unless your code also registers hooks into the UI. For example, you can surely implement an exporter in Javascript, but unless you add a corresponding menu command in the UI, your user can't use your exporter. + +#### Main Menu {#main-menu} + +The main menu can be extended by calling any one of the methods `MenuBar.appendTo`, `MenuBar.insertBefore`, and `MenuBar.insertAfter`. Each method takes 2 arguments: an array of strings that identify a particular existing menu item or submenu, and one new single menu item or submenu or an array of menu items and submenus. For example, to insert 2 menu items and a menu separator before the menu item Project > Export Filtered Rows > Templating..., write this Javascript code wherever that would execute when your Javascript files get loaded: + +``` +MenuBar.insertBefore( + ["core/project", "core/export", "core/export-templating"], + [ + { + "label":"Menu item 1", + "click": function() { ... } + }, + { + "label":"Menu item 2", + "click": function() { ... } + }, + {} // separator + ] + ); +``` + +The array `["core/project", "core/export", "core/export-templating"]` pinpoints the reference menu item. + +See the beginning of [/main/webapp/modules/core/scripts/project/menu-bar.js](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/scripts/project/menu-bar.js) for IDs of menu items and submenus. + +#### Column Header Menu {#column-header-menu} + +The drop-down menu of each column can also be extended, but the mechanism is slightly different compared to the main menu. Because the drop-down menu for a particular column is constructed on the fly when the user actually clicks the drop-down menu button, extending the column header menu can't really be done once at start-up time, but must be done every time a column header menu gets created. So, registration in this case involves providing a function that gets called each such time: + +``` +DataTableColumnHeaderUI.extendMenu(function(column, columnHeaderUI, menu) { ... do stuff to menu ... }); +``` + +That function takes in the column object (which contains the column's name), the column header UI object (generally not so useful), and the menu to extend. In the previous code line where it says "do stuff to menu", you can write something like this: + +``` +MenuSystem.appendTo(menu, ["core/facet"], [ + { + id: "core/text-facet", + label: "My Facet on " + column.name, + click: function() { + ... use column.name and do something ... + } + }, + ]); +``` + +In addition to `MenuSystem.appendTo`, you can also call `MenuSystem.insertBefore` and `MenuSystem.insertAfter` which the same 3 arguments. To see what IDs you can use, see the function `DataTableColumnHeaderUI.prototype._createMenuForColumnHeader` in [/main/webapp/modules/core/scripts/views/data-table/column-header-ui.js](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/scripts/views/data-table/column-header-ui.js). + +### Server-side: Ajax Commands {#server-side-ajax-commands} + +The client-side of OpenRefine gets things done by calling AJAX commands on the server-side. These commands must be registered with the OpenRefine servlet, so that the servlet knows how to route AJAX calls from the client-side. This can be done inside the `init` function in your extension's `controller.js` file, e.g., + +``` +function init() { + var RefineServlet = Packages.com.google.refine.RefineServlet; + RefineServlet.registerCommand(module, "my-command", new Packages.com.foo.bar.MyCommand()); + } +``` + +Your command will then be accessible at [http://127.0.0.1:3333/command/my-extension/my-command](http://127.0.0.1:3333/command/my-extension/my-command). + +### Server-side: Operations {#server-side-operations} + +Most commands change the project's data. Most of them do so by creating abstract operations. See the Changes, History, Processes, and Operations section of the [Server Side Architecture](https://github.com/OpenRefine/OpenRefine/wiki/Server-Side-Architecture) document. + +You can register an operation **class** in the `init` function as follows: + +``` +Packages.com.google.refine.operations.OperationRegistry.registerOperation( + module, + "operation-name", + Packages.com.foo.bar.MyOperation + ); +``` + +Do not call `new` to construct an operation instance. You must register the class itself. The class should have a static function for reconstructing an operation instance from a JSON blob: + +``` +static public AbstractOperation reconstruct(Project project, JSONObject obj) throws Exception { + ... + } +``` + +### Server-side: GREL {#server-side-grel} + +GREL can be extended with new functions. This is also done in the `init` function in `controller.js`, e.g., + +``` +Packages.com.google.refine.grel.ControlFunctionRegistry.registerFunction( + "functionName", new Packages.com.foo.bar.TheFunctionClass()); +``` + +You might also want to provide new variables (beyond just `value`, `cells`, `row`, etc.) available to expressions. This is done by registering a binder that implements the interface `com.google.refine.expr.Binder`: + +``` +Packages.com.google.refine.expr.ExpressionUtils.registerBinder( + new Packages.com.foo.bar.MyBinder()); +``` + +### Server-side: Importers {#server-side-importers} + +You can register an importer as follows: + +``` +Packages.com.google.refine.importers.ImporterRegistry.registerImporter( + "importer-name", new Packages.com.foo.bar.MyImporter()); +``` + +The string `"importer-name"` isn't important at all. It's not really related to file extension or mime-type. Just use something unique. Your importer will be explicitly called to test if it can import something. + +### Server-side: Exporters {#server-side-exporters} + +You can register an exporter as follows: + +``` +Packages.com.google.refine.exporters.ExporterRegistry.registerExporter( + "exporter-name", new Packages.com.foo.bar.MyExporter()); +``` + +The string `"exporter-name"` isn't important at all. It's only used by the client-side to tell the server-side which exporter to use. Just use something unique and, of course, relevant. + +### Server-side: Overlay Models {#server-side-overlay-models} + +Overlay models are objects attached onto a core Project object to store and manage additional data for that project. For example, the schema alignment skeleton is managed by the Protograph overlay model. An overlay model implements the interface `com.google.refine.model.OverlayModel` and can be registered like so: + +``` +Packages.com.google.refine.model.Project.registerOverlayModel( + "model-name", + Packages.com.foo.bar.MyOverlayModel); +``` + +Note that you register the **class** , not an instance. The class should implement the following static method for reconstructing an overlay model instance from a JSON blob: + +``` +static public OverlayModel reconstruct(JSONObject o) throws JSONException { + ... + } +``` + +When the project gets saved, the overlay model instance's `write` method will be called: + +``` +public void write(JSONWriter writer, Properties options) throws JSONException { + ... + } +``` + +### Server-side: Scripting Languages {#server-side-scripting-languages} + +A scripting language (such as Jython) can be registered as follows: + +``` +Packages.com.google.refine.expr.MetaParser.registerLanguageParser( + "jython", + "Jython", + Packages.com.google.refine.jython.JythonEvaluable.createParser(), + "return value" + ); +``` + +The first string is the prefix that gets prepended to each expression so that we know which language the expression is in. This should be short, unique, and identifying. The second string is a user-friendly name of the language. The third is an object that implements the interface `com.google.refine.expr.LanguageSpecificParser`. The final string is the default expression in that language that would return the cell's value. + +In 2018 we are making important changes to OpenRefine to modernize it, for the benefit of users and contributors. This page describes the changes that impact developers of extensions or forks and is intended to minimize the effort required on their end to follow the transition. The instructions are written specifically with extension maintainers in mind, but fork maintainers should also find it useful. + +This document describes the migrations in the order they are committed to the master branch. This means that it should be possible to perform each migration in turn, with the ability to run the software between each stage by checking out the appropriate git commit. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/index.md b/OpenRefine/docs/versioned_docs/version-3.5/index.md new file mode 100644 index 000000000..367347fef --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/index.md @@ -0,0 +1,25 @@ +--- +slug: / +id: index +title: OpenRefine user manual +sidebar_label: Introduction +--- + + +This manual is designed to comprehensively walk through every aspect of setting up and using OpenRefine 3.5.0, including every interface function and feature. + + + +This user manual starts with instructions for [installing or upgrading OpenRefine on Windows, Mac, and Linux computers](manual/installing). It then walks you through [the interface and how to run OpenRefine](manual/running#jvm-preferences) from a program or command line, with or without setting custom preferences and modifications. + +The manual then teaches you how to [start a project](manual/starting) by importing an existing dataset. We work through how to [view and learn about your data](manual/exploring) using facets, filters, and sorting. + +Then we launch into [transforming that data permanently](manual/transforming) through common and custom transformations, clustering, pulling data from the web, [reconciling](manual/reconciling), and [writing expressions](manual/expressions). + +Finally we discuss what to do with your improved dataset, whether [exporting](manual/exporting) it to a file or [uploading statements to Wikidata or another Wikibase instance](manual/wikibase/overview). + +If you're stuck on any aspect and can't find an answer in the manual, try the [Troubleshooting page](manual/troubleshooting) for links to various places to find help. + +If you are new and want to learn how to use OpenRefine using an example dataset, you may wish to start with a user-contributed tutorial from our [recommendations list](https://github.com/OpenRefine/OpenRefine/wiki/External-Resources). diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/cellediting.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/cellediting.md new file mode 100644 index 000000000..103c8ed45 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/cellediting.md @@ -0,0 +1,165 @@ +--- +id: cellediting +title: Cell editing +sidebar_label: Cell editing +--- +## Overview {#overview} + +OpenRefine offers a number of features to edit and improve the contents of cells automatically and efficiently. + +One way of doing this is editing through a [text facet](facets#text-facet). Once you have created a facet on a column, hover over the displayed results in the sidebar. Click on the small “edit†button that appears to the right of the facet, and type in a new value. This will apply to all the cells in the facet. + +You can apply a text facet on numbers, boolean values, and dates, but if you edit a value it will be converted into the text [data type](exploring#data-types) (regardless of whether you edit a date into another correctly-formatted date, or a “true†value into “falseâ€, etc.). + +## Transform {#transform} + +Select Edit cells → Transform... to open up an expressions window. From here, you can apply [expressions](expressions) to your data. The simplest examples are GREL functions such as [`toUppercase()`](grelfunctions#touppercases) or [`toLowercase()`](grelfunctions#tolowercases), used in expressions as `toUppercase(value)` or `toLowercase(value)`. When used on a column operation, `value` is the information in each cell in the selected column. + +Use the preview to ensure your data is being transformed correctly. + +You can also switch to the Undo / Redo tab inside the expressions window to reuse expressions you’ve already attempted in this project, whether they have been undone or not. + +OpenRefine offers you some frequently-used transformations in the next menu option, Common transforms. For more custom transforms, read up on [expressions](expressions). + +## Common transforms {#common-transforms} + +### Trim leading and trailing whitespace {#trim-leading-and-trailing-whitespace} + +Often cell contents that should be identical, and look identical, are different because of space or line-break characters that are invisible to users. This function will get rid of any characters that sit before or after visible text characters. + +### Collapse consecutive whitespace {#collapse-consecutive-whitespace} + +You may find that some text cells contain what look like spaces but are actually tabs, or contain multiple spaces in a row. This function will remove all space characters that sit in sequence and replace them with a single space. + +### Unescape HTML {#unescape-html} + +Your data may come from an HTML-formatted source that expresses some characters through references (such as “&nbsp;†for a space, or “%u0107†for a ć) instead of the actual Unicode characters. You can use the “unescape HTML entities†transform to look for these codes and replace them with the characters they represent. For other formatting that needs to be escaped, try a custom transformation with [`escape()`](grelfunctions#escapes-s-mode). + +### Replace smart quotes with ASCII {#replace-smart-quotes-with-ascii} + +Smart quotes (or curly quotes) recognize whether they come at the beginning or end of a string, and will generate an “open†quote (“) and a “close†quote (â€). These characters are not ASCII-compliant (though they are UTF8-compliant) so you can use this tranform to replace them with a straight double quote character (") instead. + +### Case transforms {#case-transforms} + +You can transform an entire column of text into UPPERCASE, lowercase, or Title Case using these three options. This can be useful if you are planning to do textual analysis and wish to avoid case-sensitivity (which some functions are) causing problems in your analysis. Consider also using a [custom facet](facets#custom-text-facet) to temporarily modify cases instead of this permanent operation if appropriate. + +### Data-type transforms {#data-type-transforms} + +As detailed in [Data types](exploring#data-types), OpenRefine recognizes different data types: string, number, boolean, and date. When you use these transforms, OpenRefine will check to see if the given values can be converted, then both transform the data in the cells (such as “3†as a text string to “3†as a number) and convert the data type on each successfully transformed cell. Cells that cannot be transformed will output the original value and maintain their original data type. + +:::caution +Be aware that dates may require manual intervention to transform successfully: see the section on [Dates](exploring#dates) for more information. +::: + +Because these common transforms do not offer the ability to output an error instead of the original cell contents, be careful to look for unconverted and untransformed values. You will see a yellow alert at the top of screen that will tell you how many cells were converted - if this number does not match your current row set, you will need to look for and manually correct the remaining cells. Also consider faceting by data type, with the GREL function [`type()`](grelfunctions#typeo). + +You can also convert cells into null values or empty strings. This can be useful if you wish to, for example, erase duplicates that you have identified and are analyzing as a subset. + +## Fill down and blank down {#fill-down-and-blank-down} + +Fill down and blank down are two functions most frequently used when encountering data organized into [records](exploring#row-types-rows-vs-records) - that is, multiple rows associated with one specific entity. + +If you receive information in rows mode and want to convert it to records mode, the easiest way is to sort your first column by the value that you want to use as a unique records key, [make that sorting permanent](transforming#edit-rows), then blank down all the duplicates in that column. OpenRefine will retain the first unique value and erase the rest. Then you can switch from “Show as rows†to “Show as records†and OpenRefine will associate rows to each other based on the remaining values in the first column. + +Be careful that your data is sorted properly before you begin blanking down - not just the first column but other columns you may want to have in a certain order. For example, you may have multiple identical entries in the first column, one with a value in the second column and one with an empty cell in the second column. In this case you want the row with the second-column value to come first, so that you can clean up empty rows later, once you blank down. + +If, conversely, you’ve received data with empty cells because it was already in something akin to records mode, you can fill down information to the rest of the rows. This will duplicate whatever value exists in the topmost cell with a value: if the first row in the record is blank, it will take information from the next cell, or the cell after that, until it finds a value. The blank cells above this will remain blank. + +## Split multi-valued cells {#split-multi-valued-cells} + +Splitting cells with more than one value in them is a common way to get your data from single rows into [multi-row records](exploring#rows-vs-records). Survey data, for example, frequently allows respondents to “Select all that apply,†or an inventory list might have items filed under more than one category. + +You can split a column based on any character or series of characters you input, such as a semi-colon (;) or a slash (/). The default is a comma. Splitting based on a separator will remove the separator characters, so you may wish to include a space with your separator (; ) if it exists in your data. + +You can use [expressions](expressions) to design the point at which a cell should split itself into two or more rows. This can be used to identify special characters or create more advanced evaluations. You can split on a line-break by entering `\n` and checking the “[regular expression](expressions#regular-expressions)†checkbox. + +Regular expressions can be useful if the split is not straightforward: say, if a capital letter (`[A-Z]`) indicates the beginning of a new string, or if you need to _not_ always split on a character that appears in both the strings and as a separator. Remember that this will remove all the matching characters. + +You can also split based on the lengths of the strings you expect to find. This can be useful if you have predictable data in the cells: for example, a 10-digit phone number, followed by a space, followed by another 10-digit phone number. Any characters past the explicit length you’ve specified will be discarded: if you split by “11, 10†any characters that may come after the 21st character will disappear. If some cells only have one phone number, you will end up with blank rows. + +If you have data that should be split into multiple columns instead of multiple rows, see [Split into several columns](columnediting#split-into-several-columns). + +## Join multi-valued cells {#join-multi-valued-cells} + +Joining will reverse the “split multi-valued cells†operation, or join up information from multiple rows into one row. All the strings will be compressed into the topmost cell in the record, in the order they appear. A window will appear where you can set the separator; the default is a comma and a space (, ). This separator is optional. We suggest the separator | as a sufficiently rare character. + +## Cluster and edit {#cluster-and-edit} + +Creating a facet on a column is a great way to look for inconsistencies in your data; clustering is a great way to fix those inconsistencies. Clustering uses a variety of comparison methods to find text entries that are similar but not exact, then shares those results with you so that you can merge the cells that should match. Where editing a single cell or text facet at a time can be time-consuming and difficult, clustering is quick and streamlined. + +Clustering always requires the user to approve each suggested edit - it will display values it thinks are variations on the same thing, and you can select which version to keep and apply across all the matching cells (or type in your own version). + +OpenRefine will do a number of cleanup operations behind the scenes in order to do its analysis, but only the merges you approve will modify your data. Understanding those different behind-the-scenes cleanups can help you choose which clustering method will be more accurate and effective. + +You can start the process in two ways: using the dropdown menu on your column, select Edit cells → Cluster and edit…; or create a text facet and then press the “Cluster†button that appears in the facet box. + +![A screenshot of the Clustering window.](/img/cluster.png) + +The clustering pop-up window will take a small amount of time to analyze your column, and then make some suggestions based on the clustering method currently active. + +For each cluster identified, you can pick one of the existing values to apply to all cells, or manually type in a new value in the text box. And, of course, you can choose not to cluster them at all. OpenRefine will keep analyzing every time you make a change, with Merge selected & re-cluster, and you can work through all the methods this way. + +You can also export the currently identified clusters as a JSON file, or close the window with or without applying your changes. You can also use the histograms on the right to narrow down to, for example, clusters with lots of matching rows, or clusters of long or short values. + +### Clustering methods {#clustering-methods} + +You don’t need to understand the details behind each clustering method to apply them successfully to your data. The order in which these methods are presented in the interface and on this page is the order we recommend - starting with the most strict rules and moving to the most lax, which require more human supervision to apply correctly. + +The clustering pop-up window offers you a variety of clustering methods: + +* key collision + * fingerprint + * ngram-fingerprint + * metaphone3 + * cologne-phonetic + * Daitch-Mokotoff + * Beider-Morse +* nearest neighbor + * levenshtein + * ppm + +#### Key collision {#key-collision} + +**Key collisions** are very fast and can process millions of cells in seconds: + +**Fingerprinting** is the least likely to produce false positives, so it’s a good place to start. It does the same kind of data-cleaning behind the scenes that you might think to do manually: fix whitespace into single spaces, put all uppercase letters into lowercase, discard punctuation, remove diacritics (e.g. accents) from characters, split up all strings (words) and sort them alphabetically (so “Zhenyi, Wang†becomes “wang zhenyiâ€). + +**N-gram fingerprinting** allows you to set the _n_ value to whatever number you’d like, and will create n-grams of _n_ size (after doing some cleaning), alphabetize them, then join them back together into a fingerprint. For example, a 1-gram fingerprint will simply organize all the letters in the cell into alphabetical order - by creating segments one character in length. A 2-gram fingerprint will find all the two-character segments, remove duplicates, alphabetize them, and join them back together (for example, “banana†generates “ba an na an na,†which becomes “anbanaâ€). + +This can help match cells that have typos, or incorrect spaces (such as matching “lookout†and “look out,†which fingerprinting itself won’t identify because it separates words). The higher the _n_ value, the fewer clusters will be identified. With 1-grams, keep an eye out for mismatched values that are near-anagrams of each other (such as “Wellington†and “Elgin Townâ€). + +##### Phonetic clustering {#phonetic-clustering} + +The next four methods are phonetic algorithms: they identify letters that sound the same when pronounced out loud, and assess text values based on that (such as knowing that a word with an “S†might be a mistype of a word with a “Zâ€). They are great for spotting mistakes made by not knowing the spelling of a word or name after hearing it spoken aloud. + +**Metaphone3 fingerprinting** is an English-language phonetic algorithm. For example, “Reuben Gevorkiantz†and “Ruben Gevorkyants†share the same phonetic fingerprint in English. + +**Cologne fingerprinting** is another phonetic algorithm, but for German pronunciation. + +**Daitch-Mokotoff** is a phonetic algorithm for Slavic and Yiddish words, especially names. **Baider-Morse** is a version of Daitch-Mokotoff that is slightly more strict. + +Regardless of the language of your data, applying each of them might find different potential matches: for example, Metaphone clusters “Cornwall†and “Corn Hill†and “Green Hill,†while Cologne clusters “Greenvale†and “Granville†and “Cornwall†and “Green Wall.†+ +#### Nearest neighbor {#nearest-neighbor} + +**Nearest neighbor** clustering methods are slower than key collision methods. They allow the user to set a radius - a threshold for matching or not matching. OpenRefine uses a “blocking†method first, which sorts values based on whether they have a certain amount of similarity (the default is “6†for a six-character string of identical characters) and then runs the nearest-neighbor operations on those sorted groups. + +We recommend setting the block number to at least 3, and then increasing it if you need to be more strict (for example, if every value with “river†is being matched, you should increase it to 6 or more). Note that bigger block values will take much longer to process, while smaller blocks may miss matches. Increasing the radius will make the matches more lax, as bigger differences will be clustered. + +**Levenshtein distance** counts the number of edits required to make one value perfectly match another. As in the key collision methods above, it will do things like change uppercase to lowercase, fix whitespace, change special characters, etc. Each character that gets changed counts as 1 “distance.†“New York†and “newyork†have an edit distance value of 3 (“N†to “nâ€; “Y†to “yâ€; remove the space). It can do relatively advanced edits, such as understand the distance between “M. Makeba†and “Miriam Makeba†(5), but it may create false positives if these distances are greater than other, simpler transformations (such as the one-character distance to “B. Makeba,†another person entirely). + +**PPM (Prediction by Partial Matching)** uses compression to see whether two values are similar or different. In practice, this method is very lax even for small radius values and tends to generate many false positives, but because it operates at a sub-character level it is capable of finding substructures that are not easily identifiable by distances that work at the character level. So it should be used as a “last resort†clustering method. It is also more effective on longer strings than on shorter ones. + +For more of the theory behind clustering, see [Clustering In Depth](https://github.com/OpenRefine/OpenRefine/wiki/Clustering-In-Depth). + +## Replace {#replace} + +OpenRefine provides a find/replace function for you to edit your data. Selecting Edit cells → Replace will bring up a simple window where you can input a string to search and a string to replace it with. You can set case-sensitivity, and set it to only select whole words, defined by a string with spaces or punctuation around it (to prevent, for example, “house†selecting the “house†part of “doghouseâ€). You can use [regular expressions](expressions#regular-expressions) in this field. You may wish to preview the results of this operation by testing it with a [Text filter](facets#text-filter) first. + +You can also perform a sort of find/replace operation by editing one cell, and selecting “apply to all identical cells.†+ +## Edit one cell at a time {#edit-one-cell-at-a-time} + +You can edit individual cells by hovering your mouse over that cell. You should see a tiny blue link labeled “edit.†Click it to edit the cell. That pops up a window with a bigger text field for you to edit. You can change the [data type](exploring#data-types) of that cell, and you can apply these changes to all identical cells (in the same column), using this pop-up window. + +You will likely want to avoid doing this except in rare cases - the more efficient means of improving your data will be through automated and bulk operations. \ No newline at end of file diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/columnediting.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/columnediting.md new file mode 100644 index 000000000..754a61c62 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/columnediting.md @@ -0,0 +1,124 @@ +--- +id: columnediting +title: Column editing +sidebar_label: Column editing +--- + +## Overview {#overview} + +Column editing contains some of the most powerful data-improvement methods in OpenRefine. The operations in the Edit column menu involve using one column of data to add entirely new columns and fields to your dataset. + +## Splitting or joining {#splitting-or-joining} + +Many users find that they frequently need to make their data more granular: for example, splitting a “Firstname Lastname†column into two columns, one for first names and one for last names. The reverse is also often true: you may have several columns of category values that you want to join into one “category†column. +. +### Split into several columns {#split-into-several-columns} + +![A screenshot of the settings window for splitting columns.](/img/columnsplit.png) + +You can find this operation at Edit column → Split into several columns.... Splitting one column into several columns requires you to identify the character, string lengths, or evaluating expression you want to split on. Just like [splitting multi-valued cells into rows](cellediting#split-multi-valued-cells), splitting cells into multiple columns will remove the separator character or string you indicate. Splitting by lengths will discard any information that comes after the specified total length. + +You can also specify a maximum number of new columns to be made: separator characters after this limit will be ignored, and the remaining characters will end up in the last column. + +New columns will be named after the original column, with a number: “Location 1,†“Location 2,†etc. You can choose to remove the original column with this operation, and you can have [data types](exploring#data-types) identified where possible. This function will work best with converting strings to numbers, and may not work with [dates](exploring#dates). + +### Join columns {#join-columns} + +![A screenshot of the settings window for joining columns.](/img/columnjoin.png) + +You can join columns by selecting Edit column → Join columns.... All the columns currently in your dataset will appear in the pop-up window. You can select or un-select all the columns you want to join, and drag columns to put them in the order you want to join them in. You will define a separator character (optional) and define a string to insert into empty cells (nulls). + +The joined data will appear in the column you originally selected, or you can create a new column for this content and specify a name. You can delete all the columns that were used in this join operation. + +## Add column based on this column {#add-column-based-on-this-column} + +Selecting Edit column → Add column based on this column... will open up an [expressions](expressions) window where you can transform the data from this column (using `value`), or write a more complex expression that takes information from any number of columns or from external sources. + +Expressions used in this operation will rely on your knowledge of variables. You can learn more in the [Expressions section on variables](expressions#variables). + +The simplest way to use this operation is simply leave the default `value` in the expression field, to create an exact copy of your column. For a column of [reconciled data](reconciling), you can use the variable `cell` instead, to copy both the original string and the existing reconciliation data. This will include matched values, candidates, and new items. + +One useful expression is to create a column based on concatenating (merging) two other columns. Select either of the source columns, choose Edit column → Add column based on this column..., name your new column, and use the following format in the expression window: + +``` +cells["Column 1"].value + cells["Column 2"].value +``` + +If your column names do not contain spaces, you can use the following format instead: + +``` +cells.Column1.value + cells.Column2.value +``` + +If you are in records mode instead of rows mode, you can concatenate using the following format: + +``` +row.record.cells.Column1.value + row.record.cells.Column2.value +``` + +You may wish to add separators or spaces, or modify your input during this operation with more advanced expressions. + +## Add column by fetching URLs {#add-column-by-fetching-urls} + +Through the Add column by fetching URLs function, OpenRefine supports the ability to fetch HTML or data from web pages or services. In this operation you will be building URL strings based on your column of data, by using `value` to insert a relevant substring. Your chosen column needs to contains parts of paths to valid HTML pages or files online. + +If you have a column of URLs and want to fetch the information that they point to, you can simply run the expression as `value`. If your column has, for example, unique identifiers for Wikidata entities (numerical values starting with Q), you can download the JSON-formatted metadata about each entity with + +``` +"https://www.wikidata.org/wiki/Special:EntityData/" + value + ".json" +``` + +or whatever metadata format you prefer. Information about the format options in Wikidata can be found [here](https://www.wikidata.org/wiki/Wikidata:Data_access). The service you are fetching data from may have similar documentation on its provided options. + +![A screenshot of the settings window for fetching URLs.](/img/fetchingURLs.png) + +This service is more useful when getting metadata files instead of HTML, but you may wish to work with a page’s entire HTML contents and then parse out information from that. + +:::caution +Be aware that the fetching process can take quite some time and that servers may not want to fulfill hundreds or thousands of page requests in seconds. Fetching allows you to set a “throttle delay†which determines the amount of time between requests. The default is 5 seconds per row in your dataset (5000 milliseconds). We recommend leaving this at 1000 or greater. +::: + +Note the following: +* Before pressing “OK,†copy and paste a URL or two from the preview and test them in another browser tab to make sure they work. +* In some situations you may need to set [HTTP request headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers). To set these, click the small “Show†button next to “HTTP headers to be used when fetching URLs†in the settings window. The authorization credentials get logged in your operation history in plain text, which may be a security concern for you. You can set the following request headers: + * [User-Agent](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) + * [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) + * [Authorization](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) + +### Common errors {#common-errors} + +When OpenRefine attempts to fetch information from a web service, it can fail in a variety of ways. The following information is meant to help troubleshoot and fix problems encountered when using this function. + +First, make sure that your fetching operation is storing errors (check “store errorâ€). Then run the fetch and look at the error messages. + +**“HTTP error 403 : Forbiddenâ€** can be simply down to you not having access to the URL you are trying to use. If you can access the same URL with your browser, the remote site may be blocking OpenRefine because it doesn't recognize its request as valid. Changing the [User-Agent](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) request header may help. If you believe you should have access to a site but are “forbidden,†you may wish to contract the administrators. + +**“HTTP error 404 : Not Foundâ€** indicates that the information you are requesting does not exist, perhaps due to a problem with your cell values if it only happening in certain rows. + +**“HTTP error 500 : Internal Server Errorâ€** indicates the remote server is having a problem filling your request. You may wish to simply wait and try again later, or double-check the URLs. + +**“error: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failureâ€** can occur when you are trying to retrieve information over HTTPS but the remote site is using an encryption not supported by the Java virtual machine being used by OpenRefine. + +You can check which encryption methods are supported by your OpenRefine/Java installation by using a service such as **How's my SSL**. Add the URL `https://www.howsmyssl.com/a/check` to an OpenRefine cell and run “Add column by fetching URLs†on it, which will provide a description of the SSL client being used. + +You can try installing additional encryption supports by installing the [Java Cryptography Extension](https://www.oracle.com/java/technologies/javase-jce8-downloads.html). +Note that for Mac users and for Windows users with the OpenRefine installation with bundled JRE, these updated cipher suites need to be dropped into the Java install within the OpenRefine application: + +* On Mac, it will look something like `/Applications/OpenRefine.app/Contents/PlugIns/jdk1.8.0_60.jdk/Contents/Home/jre/lib/security`. +* On Windows: `\server\target\jre\lib\security`. + +**“javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failedâ€** can appear when the remote site is using an HTTPS certificate not trusted by your local Java installation. You will need to make sure that the certificate, or (more likely) the root certificate, is trusted. + +The list of trusted certificates is stored in an encrypted file called `cacerts` in your local Java installation. This can be read and updated by a tool called “keytool.†You can find directions on how to add a security certificate to the list of trusted certificates for a Java installation [here](http://magicmonster.com/kb/prg/java/ssl/pkix_path_building_failed.html) and [here](http://javarevisited.blogspot.co.uk/2012/03/add-list-certficates-java-keystore.html). + +Note that for Mac users and for Windows users with the OpenRefine installation with bundled JRE, the `cacerts` file within the OpenRefine application needs to be updated. + +* On Mac, it will look something like `/Applications/OpenRefine.app/Contents/PlugIns/jdk1.8.0_60.jdk/Contents/Home/jre/lib/security/cacerts`. +* On Windows: `\server\target\jre\lib\security\`. + +## Renaming, removing, and moving {#renaming-removing-and-moving} + +Every column's Edit column dropdown contains options to move it (to the beginning, end, left, or right), rename it, and delete it. +These operations can be undone, but a removed column cannot be restored later if you keep modifying your data. If you wish to temporarily hide a column, go to [View](sortview#view) → Collapse this column instead. + +Be cautious about moving columns in [records mode](cellediting#rows-vs-records): if you change the first column in your dataset (the key column), your records may change in unintended ways. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/exploring.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/exploring.md new file mode 100644 index 000000000..23bafc1a7 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/exploring.md @@ -0,0 +1,116 @@ +--- +id: exploring +title: Exploring data +sidebar_label: Overview +--- + +## Overview {#overview} + +OpenRefine offers lots of features to help you learn about your dataset, even if you don’t change a single character. In this section we cover different ways for sorting through, filtering, and viewing your data. + +Unlike spreadsheets, OpenRefine doesn’t store formulas and display the output of those calculations; it only shows the value inside each cell. It doesn’t support cell colors or text formatting. + +## Data types {#data-types} + +Each piece of information (each cell) in OpenRefine is assigned a data type. Some file formats, when imported, can set data types that are recognized by OpenRefine. Cells without an associated data type on import will be considered a “string†at first, but you can have OpenRefine convert cell contents into other data types later. This is set at the cell level, not at the column level. + +You can see data types in action when you preview a new project: check the box next to Attempt to parse cell text into numbers, and cells will be converted to the “number†data type based on their contents. You’ll see numbers change from black text to green if they are recognized. + +The data type will determine what you can do with the value. For example, if you want to add two values together, they must both be recognized as the number type. + +You can check data types at any time by: +* clicking “edit†on a single cell (where you can also edit the type) +* creating a Custom Text Facet on a column, and inserting `type(value)` into the Expression field. This will generate the data type in the preview, and you can facet by data type if you press OK. + +The data types supported are: +* string (one or more text characters) +* number (one or more characters of numbers only) +* boolean (values of “true†or “falseâ€) +* [date](#dates) (ISO-8601-compliant extended format with time in UTC: YYYY-MM-DDTHH:MM:SSZ) + +OpenRefine recognizes two further data types as a result of its own processes: +* error +* null + +An “error†data type is created when the cell is storing an error generated during a transformation in OpenRefine. + +A “null†data type is a special type that means “this cell has no value.†It’s distinct from cells that have values such as “0†or “falseâ€, or cells that look empty but have whitespace in them, or cells that contain empty strings. When you use `type(value)`, it will show you that the cell’s value is “null†and its type is “undefined.†You can opt to [show “null†values](sortview#showhide-null), by going to All → View → Show/Hide ‘null’ values in cells. + +Changing a cell's data type is not the same operation as transforming its contents. For example, using a column-wide transform such as Transform → Common transforms → To date may not convert all values successfully, but going to an individual cell, clicking “editâ€, and changing the data type can successfully convert text to a date. These operations use different underlying code. Learn more about date formatting and transformations in the next section. + +To transform data from one type to another, see [Transforming data](cellediting#data-type-transforms) for information on using common tranforms, and see [Expressions](expressions) for information on using [toString()](grelfunctions#tostringo-string-format-optional), [toDate()](grelfunctions#todateo-b-monthfirst-s-format1-s-format2-), and other functions. + + +### Dates {#dates} + +A “date†type is created when a column is [transformed into dates](transforming#to-date), when an expression is used to [convert cells to dates](grelfunctions#todateo-b-monthfirst-s-format1-s-format2-) or when individual cells are set to have the data type “dateâ€. + +Date-formatted data in OpenRefine relies on a number of conversion tools and standards. For something to be considered a date in OpenRefine, it will be converted into the ISO-8601-compliant extended format with time in UTC: YYYY-MM-DDTHH:MM:SSZ. + +When you run Edit cells → Common transforms → To date, the following column of strings on the left will transform into the values on the right: + +|Input|→|Output| +|---|---|---| +|23/12/2019|→|2019-12-23T00:00:00Z| +|14-10-2015|→|2015-10-14T00:00:00Z| +|2012 02 16|→|2012-02-16T00:00:00Z| +|August 2nd 1964|→|1964-08-02T00:00:00Z| +|today|→|today| +|never|→|never| + +OpenRefine uses a variety of tools to recognize, convert, and format [dates](exploring#dates) and so some of the values above can be reformatted using other methods. In this case, clicking the “today†cell and editing its data type manually will convert “today†into a value such as “2020-08-14T00:00:00Zâ€. Attempting the same data-type change on “never†will give you an error message and refuse to proceed. + +You can do more precise conversion and formatting using expressions and arguments based on the state of your data: see the GREL functions reference section on [Date functions](grelfunctions#date-functions) for more help. + +You can convert dates into a more human-readable format when you [export your data using the custom tabular exporter](exporting#custom-tabular-exporter). You are given the option to keep your dates in the ISO 8601 format, to output short, medium, long, or full locale formats, or to specify a custom format. This means that you can format your dates into, for example, MM/DD/YY (the US short standard) with or without including the time, after working with ISO-8601-formatted dates in your project. + +The following table shows some example [date and time formatting styles for the U.S. and French locales](https://docs.oracle.com/javase/tutorial/i18n/format/dateFormat.html): + +|Style |U.S. Locale |French Locale| +|---|---|---| +|Default |Jun 30, 2009 7:03:47 AM |30 juin 2009 07:03:47| +|Short |6/30/09 7:03 AM |30/06/09 07:03| +|Medium |Jun 30, 2009 7:03:47 AM |30 juin 2009 07:03:47| +|Long |June 30, 2009 7:03:47 AM PDT |30 juin 2009 07:03:47 PDT| +|Full |Tuesday, June 30, 2009 7:03:47 AM PDT |mardi 30 juin 2009 07 h 03 PDT| + +## Rows vs. records {#rows-vs-records} + +A row is a simple way to organize data: a series of cells, one cell per column. Sometimes there are multiple pieces of information in one cell, such as when a survey respondent can select more than one response. + +In cases where there is more than one value for a single column in one or more rows, you may wish to use OpenRefine’s records mode: this defines a single record as potentially containing more than one row. From there you can transform cells into multiple rows, each cell containing one value you’d like to work with. + +Generally, when you import some data, OpenRefine reads that data in row mode. From the project screen, you can convert the project into records mode. OpenRefine remembers this action and will present you with records mode each time you open the project from then on. + +OpenRefine understands records based on the content of the first column, what we call the “key column.†Splitting a row into a multi-row record will base all association on the first column in your dataset. + +If you have more than one column to split out into multiple rows, OpenRefine will keep your data associated with its original record, and associate subgroups based on the top-most row in each group. + +You can imagine the structure as a tree with many branches, all leading back to the same trunk. + +For example, your key column may be a film or television show, with multiple cast members identified by name, associated to that work. You may have one or more roles listed for each person. The roles are linked to the actors, which are linked to the title. + +|Work|Actor|Role| +|---|---|---| +|The Wizard of Oz|Judy Garland|Dorothy Gale| +||Ray Bolger|"Hunk"| +|||The Scarecrow| +||Jack Haley|"Hickory"| +|||The Tin Man| +||Bert Lahr|"Zeke"| +|||The Cowardly Lion| +||Frank Morgan|Professor Marvel| +|||The Gatekeeper| +|||The Carriage Driver| +|||The Guard| +|||The Wizard of Oz| +||Margaret Hamilton|Miss Almira Gulch| +|||The Wicked Witch of the West| + +Once you are in records mode, you can still move some columns around, but if you move a column to the beginning, you may find your data becomes misaligned. The new key column will sort into records based on empty cells, and values in the old key column will be assigned to the last row in the old record (the key value sitting above those values). + +OpenRefine assigns a unique key behind the scenes, so your records don’t need a unique identifier in the key column. You can keep track of which rows are assigned to each record by the record number that appears under the All column. + +To [split multi-valued cells](transforming#split-multi-valued-cells) and apply other operations that take advantage of records mode, see [Transforming data](transforming). + +Be careful when in records mode that you do not accidentally delete rows based on being blank in one column where there is a value in another. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/exporting.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/exporting.md new file mode 100644 index 000000000..21b1516a9 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/exporting.md @@ -0,0 +1,134 @@ +--- +id: exporting +title: Exporting your work +sidebar_label: Exporting +--- + +## Overview {#overview} + +Once your dataset is ready, you will need to get it out of OpenRefine and into the system of your choice. OpenRefine outputs a number of file formats, can upload your data directly into Google Sheets, and can create or update statements on Wikidata. + +You can also [export your full project data](#export-a-project) so that it can be opened by someone else using OpenRefine (or yourself, on another computer). + +## Export data {#export-data} + +![A screenshot of the Export dropdown.](/img/export-menu.png) + +Many of the options only export data in the current view - that is, with current filters and facets applied. Some will give you the choice to export your entire dataset or just the currently-viewed rows. + +To export data from a project, click the Export dropdown button in the top right corner and pick the format you want. Your options are: + +* Tab-separated value (TSV) or Comma-separated value (CSV) +* HTML-formatted table +* Excel spreadsheet (XLS or XLSX) +* Open Document Format (ODF) spreadsheet (ODS) +* Upload to Google Sheets (requires [Google account authorization](starting#google-sheet-from-drive)) +* [Custom tabular exporter](#custom-tabular-exporter) +* [SQL statement exporter](#sql-statement-exporter) +* [Templating exporter](#templating-exporter), which generates JSON by default + +You can also export reconciled data to Wikidata, or export your Wikidata schema for future use with other OpenRefine projects: + +* [Upload edits to Wikidata](wikibase/uploading#uploading-with-openrefine) +* [Export to QuickStatements](wikibase/uploading#uploading-with-quickstatements) (version 1) +* [Export Wikidata schema](wikibase/overview#import-and-export-schema) + +### Custom tabular exporter {#custom-tabular-exporter} + +![A screenshot of the custom tabular content tab.](/img/custom-tabular-exporter.png) + +With the custom tabular exporter, you can choose which of your data to export, the separator you wish to use, and whether you'd like to download the result to your computer or upload it into a Google Sheet. + +On the Content tab, you can drag and drop the columns appearing in the column list to reorder the output. The options for reconciled and date data are applied to each column individually. + +This exporter is especially useful with reconciled data, as you can choose whether you wish to output the cells' original values, the matched values, or the matched IDs. Ouputting “match entity's nameâ€, “matched entity's IDâ€, or “cell's content†will output, respectively, the contents of `cell.recon.match.name`, `cell.recon.match.id`, and `cell.value`. + +“Output nothing for unmatched cells†will export empty cells for both newly-created matches and cells with no chosen matches. “Link to matched entity's page†will produce hyperlinked text in an HTML table output, but have no effect in other formats. + +At this time, the date-formatting options in this window do not work. You can [keep track of this issue on Github](https://github.com/OpenRefine/OpenRefine/issues/3368). +In the future, you will be able to choose how to [output date-formatted cells](exploring#dates). You can create a custom date output by using [formatting according to the SimpleDateFormat parsing key found here](grelfunctions#todateo-b-monthfirst-s-format1-s-format2-). + +![A screenshot of the custom tabular file download tab.](/img/custom-tabular-exporter2.png) + +On the Download tab, you can generate a preview of how the first ten rows of your dataset will output. If you do not choose one of the file formats on the right, the Download button will generate a text file. On the Upload tab, you can create a new Google Sheet. + +With the Option Code tab, you can copy JSON of your current custom settings to reuse on another export, or you can paste in existing JSON settings to apply to the current project. + +### SQL exporter {#sql-exporter} + +The SQL exporter creates a SQL statement containing the data you’ve exported, which you can use to overwrite or add to an existing database. Choosing Export → SQL exporter will bring up a window with two tabs: one to define what data to output, and another to modify other aspects of the SQL statement, with options to preview and download the statement. + +![A screenshot of the SQL statement content window.](/img/sql-exporter.png) + +The Content tab allows you to craft your dataset into an SQL table. From here, you can choose which columns to export, the data type to export for each (or choose "VARCHAR"), and the maximum character length for each field (if applicable based on the data type). You can set a default value for empty cells after unchecking “Allow null†in one or more columns. + +With this output tool, you can choose whether to output only currently visible rows, or all the rows in your dataset, as well as whether to include empty rows. The option to “Trim column names†will remove their whitespace characters. + +![A screenshot of the SQL statement download window.](/img/sql-exporter2.png) + +The Download tab allows you to finalize your complete SQL statement. + +Include schema means that you will start your statement with the creation of a table. Without that, you will only have an INSERT statement. + +Include content means including the INSERT statement with data from your project. Without that, you will only create empty columns. + +You can include DROP and IF EXISTS if you require them, and set a name for the table to which the statement will refer. + +You can then preview your statement, which will open up a new browser tab/window showing a statement with the first ten rows of your data (if included), or you can save a `.sql` file to your computer. + +### Templating exporter {#templating-exporter} + +If you pick Templating… from the Export dropdown menu, you can “roll your own†exporter. This is useful for formats that we don't support natively yet, or won't support. The Templating exporter generates JSON by default. + +![A screenshot of the Templating exporter generating JSON by default.](/img/templating-exporter.png) + +The Templating Export window allows you to set your own separators, prefix, and suffix to create a complete dataset in the language of your choice. In the Row template section, you can choose which columns to generate from each row by calling them with [variables](expressions#variables). + +This can be used to: +* output [reconciliation data](expressions#reconciliation), such as `cells["ColumnName"].recon.match.name` +* create multiple columns of output from different [member fields](expressions#variables) of a single project column +* employ [expressions](expressions) to modify data for output: for example, `cells["ColumnName"].value.toUppercase()`. + +Anything that appears inside doubled curly braces ({{ }}) is treated as a GREL expression; anything outside is generated as straight text. You can use Jython or Clojure by declaring it at the start: +``` +{{jython:return cells["ColumnName"].value}} +``` + +:::caution +Note that some syntax is different in this tool than elsewhere in OpenRefine: a forward slash must be escaped with a backslash, while other characters do not need escaping. You cannot, at this time, include a closing curly brace (}) anywhere in your expression, or it will cause it to malfunction. +::: + +You can include [regular expressions](expressions#regular-expressions) as usual (inside forward slashes, with any GREL function that accepts them). For example, you could output a version of your cells with punctuation removed, using an expression such as +``` +{{jsonize(cells["ColumnName"].value.replaceChars("/[.!?$&,/]/",""))}} +``` + +You could also simply output a plain-text document inserting data from your project into sentences: for example, "In `{{cells["Year"].value}}` we received `{{cells["RequestCount"].value}}` requests." + +You can use the shorthand `${ColumnName}` (no need for quotes) to insert column values directly. You cannot use this inside an expression, because of the closing curly brace. + +If your projects is in records mode, the Row separator field will insert a separator between records, rather than individual rows. Rows inside a single record will be directly appended to one another as per the content in the Row Template field. + +Once you have created your template, you may wish to save the text you produced in each field, in order to reuse it in the future. Once you click Export OpenRefine will output a simple `.txt` file, and your template will be discarded. + +We have recipes on using the Templating exporter to [produce several different formats](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#12-templating-exporter). + +## Export a project {#export-a-project} + +You can share a project in progress with another computer, a colleague, or with someone who wants to check your history. This can be useful for showing that your data cleanup didn’t distort or manipulate the information in any way. Once you have exported a project, another OpenRefine installation can [import it as a new project](starting#import-a-project). + +You can either save it locally or upload it to Google Drive (which requires you to authorize a Google account). + +:::caution +OpenRefine project archives contain confidential data from previous steps, which will still be accessible to anyone who has the archive. If you are hoping to keep your original dataset hidden for privacy reasons, such as using OpenRefine to anonymize information, do not share your project archive. +::: + +To save your project archive locally: from the Export dropdown, select OpenRefine project archive to file. OpenRefine exports your full project with all of its history. It does not export any current views or applied facets. Existing reconciliation information will be preserved, but the importing computer will need to add the same reconciliation services to keep working with that data. + +OpenRefine exports files in `.tar.gz` format. You can rename the file when you save it; otherwise it will bear the project name. + +To save your project archive to Google Drive: from the Export dropdown, select OpenRefine project archive to Google Drive.... OpenRefine will not share the link with you, only confirm that the file was uploaded. + +## Export operations {#export-operations} + +You can [save and re-apply the history of any project](running#reusing-operations) (all the operations shown in the Undo/Redo tab). This creates JSON that you can save for later reuse on another OpenRefine project. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/expressions.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/expressions.md new file mode 100644 index 000000000..d10420378 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/expressions.md @@ -0,0 +1,208 @@ +--- +id: expressions +title: Expressions +sidebar_label: Overview +--- + +## Overview {#overview} + +You can use expressions in multiple places in OpenRefine to extend data cleanup and transformation. Expressions are available with the following functions: +* Facet: + + * Custom text facet... + * Custom numeric facet… + * Customized facets (click “change†after they have been created to bring up an expressions window) +* Edit cells: + + * Transform… + * Split multi-valued cells… + * Join multi-valued cells… +* Edit column: + + * Split + * Join + * Add column based on this column + * Add column by fetching URLs. + +In the expressions editor window you have the opportunity to select a supported language. The default is [GREL (General Refine Expression Language)](grel); OpenRefine also comes with support for [Clojure](jythonclojure#clojure) and [Jython](jythonclojure#jython). Extensions may offer support for more expressions languages. + +These languages have some syntax differences but support many of the same [variables](#variables). For example, the GREL expression `value.split(" ")[1]` would be written in Jython as `return value.split(" ")[1]`. + +This page is a general reference for available functions, variables, and syntax. For examples that use these expressions for common data tasks, look at the [Recipes section on the wiki](https://github.com/OpenRefine/OpenRefine/wiki/Documentation-For-Users#recipes-and-worked-examples). + +## Expressions {#expressions} + +There are significant differences between OpenRefine's expressions and the spreadsheet formulas you may be used to using for data manipulation. OpenRefine does not store formulas in cells and display output dynamically: OpenRefine’s transformations are one-time operations that can change column contents or generate new columns. These are applied using variables such as `value` or `cell` to perform the same modification to each cell in a column. + +Take the following example: + +|ID|Friend|Age| +|---|---|---| +|1.|John Smith|28| +|2.|Jane Doe|33| + +Were you to apply a transformation to the “friend†column with the expression + +``` + value.split(" ")[1] +``` + +OpenRefine would work through each row, splitting the “friend†values based on a space character. The `value` for row 1 is “John Smith†so the output would be “Smith†(as "[1]" selects the second part of the created output); the `value` for row 2 is “Jane Doe†so the output would be “Doeâ€. Using variables, a single expression yields different results for different rows. The old information would be discarded; you couldn't get "John" and "Jane" back unless you undid the operation in the [History](running#history-undoredo) tab. + +For another example, if you were to create a new column based on your data using the expression `row.starred`, it would generate a column of true and false values based on whether your rows were starred at that moment. If you were to then star more rows and unstar some rows, that data would not dynamically update - you would need to run the operation again to have current true/false values. + +Note that an expression is typically based on one particular column in the data - the column whose drop-down menu is first selected. Many variables are created to stand for things about the cell in that “base column†of the current row on which the expression is evaluated. There are also variables about rows, which you can use to access cells in other columns. + +## The expressions editor {#the-expressions-editor} + +When you select a function that accepts expressions, you will see a window overlay the screen with what we call the expressions editor. + +![The expressions editor window with a simple expression: value + 10.](/img/expression-editor.png) + +The expressions editor offers you a field for entering your formula and shows you a preview of its transformation on your first few rows of cells. + +There is a dropdown menu from which you can choose an expression language. The default at first is GREL; if you begin working with another language, that selection will persist across OpenRefine. Jython and Clojure are also offered with the installation package, and you may be able to add more language support with third-party extensions and customizations. + +There are also tabs for: +* History, which shows you formulas you’ve recently used from across all your projects +* Starred, which shows you formulas from your History that you’ve starred for reuse +* Help, a quick reference to GREL functions. + +Starring formulas you’ve used in the past can be helpful for repetitive tasks you’re performing in batches. + +You can also choose how formula errors are handled: replicate the original cell value, output an error message into the cell, or ouput a blank cell. + +## Regular expressions {#regular-expressions} + +OpenRefine offers several fields that support the use of regular expressions (regex), such as in a Text filter or a Replace… operation. GREL and other expressions can also use regular expression markup to extend their functionality. + +If this is your first time working with regex, you may wish to read [this tutorial specific to the Java syntax that OpenRefine supports](https://docs.oracle.com/javase/tutorial/essential/regex/). We also recommend this [testing and learning tool](https://regexr.com/). + +### GREL-supported regex {#grel-supported-regex} + +To write a regular expression inside a GREL expression, wrap it between a pair of forward slashes (/) much like the way you would in Javascript. For example, in + +``` +value.replace(/\s+/, " ") +``` + +the regular expression is `\s+`, and the syntax used in the expression wraps it with forward slashes (`/\s+/`). Though the regular expression syntax in OpenRefine follows that of Java (normally in Java, you would write regex as a string and escape it like "\\s+"), a regular expression within a GREL expression is similar to Javascript. + +Do not use slashes to wrap regular expressions outside of a GREL expression. + +On the [GREL functions](grelfunctions) page, functions that support regex will indicate that with a “p†for “pattern.†The GREL functions that support regex are: +* [contains](grelfunctions#containss-sub-or-p) +* [replace](grelfunctions#find-and-replace) +* [find](grelfunctions#find-and-replace) +* [match](grelfunctions#matchs-p) +* [partition](grelfunctions#partitions-s-or-p-fragment-b-omitfragment-optional) +* [rpartition](grelfunctions#rpartitions-s-or-p-fragment-b-omitfragment-optional) +* [split](grelfunctions#splits-s-or-p-sep-b-preservetokens-optional) +* [smartSplit](grelfunctions#smartsplits-s-or-p-sep-optional) + +### Jython-supported regex {#jython-supported-regex} + +You can also use [regex with Jython expressions](http://www.jython.org/docs/library/re.html), instead of GREL, for example with a Custom Text Facet: + +``` +python import re g = re.search(ur"\u2014 (.*),\s*BWV", value) return g.group(1) +``` + +### Clojure-supported regex {#clojure-supported-regex} + +[Clojure](https://clojure.org/reference/reader) uses the same regex engine as Java, and can be invoked with [re-find](http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/re-find), [re-matches](http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/re-matches), etc. You can use the #"pattern" reader macro as described [in the Clojure documentation](https://clojure.org/reference/other_functions#regex). For example, to get the nth element of a returned sequence, you can use the nth function: + +``` +clojure (nth (re-find #"\u2014 (.*),\s*BWV" value) 1) +``` + +## Variables {#variables} + +Most OpenRefine variables have attributes: aspects of the variables that can be called separately. We call these attributes “member fields†because they belong to certain variables. For example, you can query a record to find out how many rows it contains with `row.record.rowCount`: `rowCount` is a member field specific to the `record` variable, which is a member field of `row`. Member fields can be called using a dot separator, or with square brackets (`row["record"]`). The square bracket syntax is also used for variables that can call columns by name, for example, `cells["Postal Code"]`. + +|Variable |Meaning | +|-|-| +| `value` | The value of the cell in the current column of the current row (can be null) | +| `row` | The current row | +| `row.record` | One or more rows grouped together to form a record | +| `cells` | The cells of the current row, with fields that correspond to the column names (or row.cells) | +| `cell` | The cell in the current column of the current row, containing value and other attributes | +| `cell.recon` | The cell's reconciliation information returned from a reconciliation service or provider | +| `rowIndex` | The index value of the current row (the first row is 0) | +| `columnName` | The name of the current cell's column, as a string | + +### Row {#row} + +The `row` variable itself is best used to access its member fields, which you can do using either a dot operator or square brackets: `row.index` or `row["index"]`. + +|Field |Meaning | +|-|-| +| `row.index` | The index value of the current row (the first row is 0) | +| `row.cells` | The cells of the row, returned as an array | +| `row.columnNames` | An array of the column names of the project. This will report all columns, even those with null cell values in that particular row. Call a column by number with `row.columnNames[3]` | +| `row.starred` | A boolean indicating if the row is starred | +| `row.flagged` | A boolean indicating if the row is flagged | +| `row.record` | The [record](#record) object containing the current row | + +For array objects such as `row.columnNames` you can preview the array using the expressions window, and output it as a string using `toString(row.columnNames)` or with something like: + +``` +forEach(row.columnNames,v,v).join("; ") +``` + +### Cells {#cells} + +The `cells` object is used to call information from the columns in your project. For example, `cells.Foo` returns a [cell](#cell) object representing the cell in the column named “Foo†of the current row. If the column name has spaces, use square brackets, e.g., `cells["Postal Code"]`. To get the corresponding column's value inside the `cells` variable, use `.value` at the end, for example, `cells["Postal Code"].value`. There is no `cells.value` - it can only be used with member fields. + +### Cell {#cell} + +A `cell` object contains all the data of a cell and is stored as a single object. + +You can use `cell` on its own in the expressions editor to copy all the contents of a column to another column, including reconciliation information. Although the preview in the expressions editor will only show a small representation (“[object Cell]â€), it will actually copy all the cell's data. Try this with Edit Column → Add Column based on this column .... + +|Field |Meaning |Member fields | +|-|-|-| +| `cell` | An object containing the entire contents of the cell | .value, .recon, .errorMessage | +| `cell.value` | The value in the cell, which can be a string, a number, a boolean, null, or an error | | +| `cell.recon` | An object encapsulating reconciliation results for that cell | See the [reconciliation](expressions#reconciliation) section | +| `cell.errorMessage` | Returns the message of an *EvalError* instead of the error object itself (use value to return the error object) | .value | + +### Reconciliation {#reconciliation} + +Several of the fields here provide the data used in [reconciliation facets](reconciling#reconciliation-facets). You must type `cell.recon`; `recon` on its own will not work. + +|Field|Meaning |Member fields | +|-|-|-| +| `cell.recon.judgment` | A string: either “matchedâ€, "newâ€, "none†| | +| `cell.recon.judgmentAction` | A string: either "single†or “similar†(or “unknownâ€) | | +| `cell.recon.judgmentHistory` | A number, the epoch timestamp (in milliseconds) of your judgment | | +| `cell.recon.matched` | A boolean, true if judgment is “matched†| | +| `cell.recon.match` | The recon candidate that has been matched against this cell (or null) | .id, .name, .type | +| `cell.recon.best` | The highest scoring recon candidate from the reconciliation service (or null) | .id, .name, .type, .score | +| `cell.recon.features` | An array of reconciliation features to help you assess the accuracy of your matches | .typeMatch, .nameMatch, .nameLevenshtein, .nameWordDistance | +| `cell.recon.features.typeMatch` | A boolean, true if your chosen type is “matched†and false if not (or “(no type)†if unreconciled) | | +| `cell.recon.features.nameMatch` | A boolean, true if the cell and candidate strings are identical and false if not (or “(unreconciled)â€) | | +| `cell.recon.features.nameLevenshtein` | A number representing the [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance): larger if the difference is greater between value and candidate | | +| `cell.recon.features.nameWordDistance` | A number based on the [word similarity](reconciling#reconciliation-facets) | | +| `cell.recon.candidates` | An array of the top 3 candidates (default) | .id, .name, .type, .score | + +The `cell.recon.candidates` and `cell.recon.best` objects have a few deeper fields: `id`, `name`, `type`, and `score`. `type` is an array of type identifiers for a list of candidates, or a single string for the best candidate. + +Arrays such as `cell.recon.candidates` and `cell.recon.candidates.type` can be joined into lists and stored as strings with something like: +``` +forEach(cell.recon.candidates,v,v.name).join("; ") +``` + +### Record {#record} + +A `row.record` object encapsulates one or more rows that are grouped together, when your project is in records mode. You must call it as `row.record`; `record` will not return values. + +|Field|Meaning | +|-|-| +| `row.record.index` | The index of the current record (starting at 0) | +| `row.record.cells` | An array of the [cells](#cells) in the given column of the record | +| `row.record.fromRowIndex` | The row index of the first row in the record | +| `row.record.toRowIndex` | The row index of the last row in the record + 1 (i.e. the next record) | +| `row.record.rowCount` | A count of the number of rows in the record | + +For example, you can facet by number of rows in each record by creating a Custom Numeric Facet (or a Custom Text Facet) and entering `row.record.rowCount`. \ No newline at end of file diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/facets.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/facets.md new file mode 100644 index 000000000..06e54b751 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/facets.md @@ -0,0 +1,329 @@ +--- +id: facets +title: Exploring facets +sidebar_label: Facets +--- + +## Overview {#overview} + +Facets are one of OpenRefine’s strongest features - that’s where the diamond logo comes from! + +Faceting allows you to look for patterns and trends. Facets are essentially aspects or angles of data variance in a given column. For example, if you had survey data where respondents indicated one of five responses from “Strongly agree†to “Strongly disagree,†those five responses make up a text facet, showing how many people selected each option. + +Faceted browsing gives you a big-picture look at your data (do they agree or disagree?) and also allows you to filter down to a specific subset to explore it more (what do people who disagree say in other responses?). + +Typically, you create a facet on a particular column. That facet selection appears on the left, in the Facet/Filter tab, and you can click on a displayed facet to view all the records that match. You can also “exclude†the facet, to view every record that does _not_ match, and you can select more than one facet by clicking “include.†+ + +### An example {#an-example} + +You can learn about facets and filtering with the following example. You can copy the following table and paste it using the Clipboard method of starting a project if you would like to try it yourself. + +We collected a list of the [10 most populous cities from Wikidata](https://w.wiki/3Em), using an example query of theirs. We removed the GPS coordinates and added the country. + +| cityLabel | population | countryLabel | +|-|-|-| +| Shanghai | 23390000 | People's Republic of China | +| Beijing | 21710000 | People's Republic of China | +| Lagos | 21324000 | Nigeria | +| Dhaka | 16800000 | Bangladesh | +| Mumbai | 15414288 | India | +| Istanbul | 14657434 | Turkey | +| Tokyo | 13942856 | Japan | +| Tianjin | 13245000 | People's Republic of China | +| Guangzhou | 13080500 | People's Republic of China | +| São Paulo | 12106920 | Brazil | + +If we want to see which countries have the most populous cities, we can create a text facet on the “countryLabel†column and OpenRefine will generate a list of all the different strings used in these cells. + +We will see in the sidebar that the countries identified are displayed, along with the number of matches (the “countâ€). We can sort this list alphabetically or by the count. If you sort by count at the top of the facet window, you’ll learn which countries hold the most populous cities. + +|Facet|Count| +|---|---| +|People's Republic of China|4| +|Bangladesh|1| +|Brazil|1| +|India|1| +|Japan|1| +|Nigeria|1| +|Turkey|1| + +If we want to learn more about a particular country, we can click on its appearance in the facet sidebar. This narrows our dataset down temporarily to only rows matching that facet. + +You’ll see the “10 rows†indicator change to “4 matching rows (10 total)†if you click on “People’s Republic of Chinaâ€. In the data grid, you’ll see fewer rows: only the ones matching your current filter. Each row will maintain its original numbering, though - in this case, rows #1, 2, and 8. + +If you want to go back to the original dataset, click Reset All or the small “exclude†text next to the facet. If you want to view the most populous cities in both China and India, click “include†next to each facet. Now you’ll see 5 rows - #1, 2, 5, 8, 9. + +We can also explore our data using the population information. In this case, because population is a number, we can create a numeric facet. This will give us the ability to explore by range rather than by exact matching values. + +With the numeric facet, we are given a scale from the smallest to the largest value in the column. We can drag the range minimum and maximum to narrow the results. In this case, if we narrow down to only cities with more than 20 million in population, we get 3 matching rows out of the original 10. + +When you look back at the text facet display of country names, you should see a smaller list with a reduced count: OpenRefine is now displaying the facets of the 3 matching rows, not the total dataset of 10 rows. + +We can combine these facets - say, by narrowing to only the Chinese cities with populations greater than 20 million - simply by clicking in both. You should see 2 matching rows for both these criteria. + +### Things to know about facets {#things-to-know-about-facets} + +When you have facets applied, you will see “matching rows†in the [project grid header](running#project-grid-header). If you click Export and copy your data out of OpenRefine while facets are active, many of the exporting options will only export the matching rows, not all the rows in your project. + +OpenRefine has several default facets, which you’ll learn about below. The most powerful facets are the ones designed by you - custom facets, written using [expressions](expressions) to transform the data behind the scenes and help you narrow down to precisely what you’re looking for. + +Facets are not saved in the project along with the data. But you can save a link to the current state of the application. Find the [Permalink](running#the-project-bar) next to the project’s name. + +You can modify any facet expression by clicking the “change†button to the right of the column name in the facet sidebar. + +Facet boxes that appear in the sidebar can be resized and rearranged. You can drag and drop the title bar of each box to reorder them, and drag on the bottom bar of text facet boxes. + +## Text facet {#text-facet} + +A text facet can be generated on any column with the “text†data type. Select the column dropdown and go to Facet → Text facet. The created facet will be sorted alphabetically, and can be sorted by count. + +A text facet is very simple: it takes the total contents of the cells of the column in question and matches them up. It does no guessing about typos or near-matches. + +You can edit any entry that appears in the facet display, by hovering over the facet and clicking the “edit†button that appears. You can then type in a new value manually. This will mass-edit every identical cell in the column. This is a great way to fix typos, whitespace, and other issues that may be affecting the way facets appear. You can also automate the cleanup of facets by using [clustering](transforming#cluster-and-edit): a “Cluster†button is displayed within the facet window. It may be most efficient to cluster cells to one value, and then mass-edit that value to your desired string within the clustering operation window. + +Each text facet shows up to 2,000 choices by default. You can [increase this limit on the Preferences screen](running#preferences) if you need to, which may slow down your browser. If your applied facet has more choices than the current limit, you'll be offered the option to increase the limit, which will permanently edit that preference for you. + +The choices and counts displayed in each facet can be copied as tab-separated values. To do so, click on the "X choices" link near the top left corner of the facet. This can be useful to generate small summary tables of your data. + +![A column of years faceted as text and numbers, and with the count ready to be copied.](/img/yeardata.png) + +## Numeric facet {#numeric-facet} + +![A screenshot of an example numeric facet.](/img/numericfacet.png) + +Whereas a text facet groups unique text values into groups, a numeric facet sorts numbers by their range - smallest to biggest. This displays visually as a histogram, and allows you to set a custom facet within that range. You can drag the minimum and maximum range markers to set a range. OpenRefine snaps to some basic equal-sized divisions - 19 in the example set above. + +You will be offered the option to include blank, non-numeric, and error values in your numeric visualization; these will appear in the visual range as “0†values. + +:::info Numbers as text +You can create a text facet on numeric data, which will treat each entry as a string. This can be useful if you wish, for example, to manually include facets instead of selecting a range, or sort by count, or copy that count. +::: + +:::info Faceting customization +As mentioned in the overview, facets can be modified or customized by GREL [expressions](expressions) in many ways. For example, to facet by clusters of [row](expressions#variables) numbers with `row.index/100` or better visualizing numbers greater than 1000 with `max(row.index, 1000)`. +::: + +## Timeline facet {#timeline-facet} + +![A screenshot of an example timeline facet.](/img/timelinefacet.png) + +Much like a numeric facet, a timeline facet will display as a small histogram with the values sorted: in this case, chronologically. A timeline facet only works on cells formatted as the [“date†data type](exploring#dates). + +The facet appears with a count of blank cells and those with errors, which can help you analyze whether your date cells are correctly converted. + +## Scatterplot facet {#scatterplot-facet} + +A scatterplot is a visual representation of two related sets of numeric data. + +You have the option to generate linear scatterplots (where the X and Y axes show continuous increases) or logarithmic scatterplots (where the X and Y axes show exponential or scaled increases). You can also rotate the plot by 45 degrees in either direction, and you can choose the size of the dot indicating a datapoint. You can make these choices in both the preview and in the facet display. + +A scatterplot facet can be generated on any column. You require two or more number columns to generate scatterplots. Selecting Facet → Scatterplot facet will create a preview of data plotted from every number-formatted column in your dataset, comparing every column against every other column. Each scatterplot will show in its own square, allowing you to choose which data comparison you would like to analyze further. You can control which columns are on the X and Y axes by rearranging the columns in your dataset. + +![A simple scatterplot of two numeric values.](/img/scatterplot.png) + +When you click on your desired square, that two-column comparison will appear in the facets sidebar. From here, you can drag your mouse to draw a rectangle inside the scatterplot, which will narrow down to just the rows matching the points plotted inside that rectangle (as shown by the rectangle inside the square in the image above). This rectangle can be resized by dragging any of the four edges. To draw a new rectangle, simply click and drag your mouse again. To add more scatterplots to the facet sidebar, re-run this process and select a different square. + +If you have multiple facets applied, plotted points in your scatterplot displays will be greyed out if they are not part of the current matching data subset. If the rectangle you have drawn within a scatterplot display only includes grey dots, you will see no matching rows. + +If you would like to export a scatterplot, OpenRefine will open a new tab with a generated PNG file that you can save. + +## Custom text facet {#custom-text-facet} + +You may want to explore your textual data with modifications that aren't permanent. Creating custom text facets will load your column into memory, transform the data temporarily, and store those transformations inside the facet. + +You can also use custom text facets to analyze numerical data, such as by analyzing a number as a string, or by creating a test that will return “true†and “false†as values. + +Clicking on Facet → Custom text facet… will bring up an [expressions](expressions) window where you can enter in a GREL, Jython, or Clojure expression to modify how the facet works. + +A custom text facet operates just like a [text facet](#text-facet) by default. Unlike a text facet, however, you cannot click “edit†on the facets that appear in the sidebar and change the matching cells in your dataset - because what they display is modified, not the original entries. + +For example, you may wish to analyze only the first word in a text field - perhaps the first name in a column of “[First Name] [Last Name]†entries. In this case, you can tell OpenRefine to facet only on the information that comes before the first space: + +``` +value.split(" ")[0] +``` + +In this case, `split()` is creating an array of text strings based on every space in the cells ["Firstname", "Lastname"]. Because arrays number their entries starting with 0, we want the first value, so we ask for `[0]`. (Assuming the first name is one word, not something like “Mary Anne.â€) We can do the same splitting and ask for the last name with + +``` +value.split(" ")[1] +``` + +You may want to create a facet that references several columns. For example, let’s say you have two columns, “First Name†and “Last Nameâ€, and you want out how many people have the same initial letter for both names (e.g., Marilyn Monroe, Steven Segal). To do so, create a custom text facet on either column and enter the expression + +``` +cells["First Name"].value[0] == cells["Last Name"].value[0] +``` + +That expression will look for the first letter (the character at index 0) of each entry and compare them. Then it will facet your rows into “true†and “false.†+ +You can learn more about text-modification functions on the [Expressions page](expressions). + +## Custom numeric facet {#custom-numeric-facet} + +You may want to explore your numerical data with modifications that aren't permanent. You can also use custom numeric facets to analyze textual data, such as by getting the length of text strings (with `value.length()`), or by analyzing it as though it were formatted as numbers (with `toNumber(value)`). + +If you would like to build your own version of a numeric facet, you can use the Custom Numeric Facet option. Clicking on Facet → Custom Numeric Facet… will bring up an [expressions](expressions) window where you can enter in a GREL, Jython, or Clojure expression to modify how the facet works. A custom numeric facet operates just like a [numeric facet](#numeric-facet) by default. + +For example, you may wish to create a numeric facet that rounds your value to the nearest integer, enter + +``` +round(value) +``` + +If you have two columns of numbers and for each row you wish to create a numeric facet only on the larger of the two, enter + +``` +max(cells["Column1"].value, cells["Column2"].value) +``` + +If the numeric values in a column are drawn from a power law distribution, then it's better to group them by their logs: + +``` +value.log() +``` + +If the values are periodic you could take the modulus by the period to understand if there's a pattern: + +``` +mod(value, 7) +``` + +You can learn more about numeric-modification functions on the [Expressions page](expressions). + +## Customized facets {#customized-facets} + +Customized facets have been added to expand the number of default facets users can apply with a single click. They represent some common and useful functions you shouldn’t have to work out using an [expression](expressions). + +All facets that display in the Facet/Filter tab can be edited by clicking on the “change†button to the right of the column title. This brings up the expressions window that will allow you to modify and preview the expression being used. + +### Word facet {#word-facet} + +A Word facet is a simple version of a text facet: it splits up the content of the cells based on spaces, and outputs each character string as a facet: + +``` +value.split(" ") +``` + +This can be useful for exploring the language used in a corpus, looking for common first and last names or titles, or seeing what’s in multi-valued cells you don’t wish to split up. + +Word facet is case-sensitive and only splits by spaces, not by line breaks or other natural divisions. + +### Duplicates facet {#duplicates-facet} + +A Duplicates facet will return only rows that have non-unique values in the column you’ve selected. It will create a facet of “true†and “false†values - true being cells that are not unique, and “false†being cells that are. The actual expression being used is + +``` +facetCount(value, 'value', '[Column]') > 1 +``` + +Duplicates facets are case-sensitive and you may wish to filter out things like leading and trailing whitespace or other hard-to-see issues. You can modify the facet expression, for example, with: + +``` +facetCount(trim(toLowercase(value)), 'trim(toLowercase(value))', 'cityLabel') > 1 +``` + +### Numeric log facet {#numeric-log-facet} + +Logarithmic scales reduce wide-ranging quantities to more compact and manageable ranges. A log transformation can be used to make highly skewed distributions less skewed. If your numerical data is unevenly distributed (say, lots of values in one range, and then a long tail extending off into different magnitudes), a Numeric log facet can represent that range better than a simple numeric facet. It will break these values down into more navigable segments than the buckets of a numeric facet. This facet can make patterns in your data more visible. OpenRefine uses a base-10 log, the “common logarithm.†+ +For example, we can look at [this data about the body weight of various mammals](http://wiki.stat.ucla.edu/socr/index.php/SOCR_Data_Brain2BodyWeight): + +|Species|BodyWeight (kg)| +|---|---| +| Newborn_Human | 3.2 | +| Adult_Human | 73 | +| Pithecanthropus_Man | 70 | +| Squirrel | 0.8 | +| Hamster | 0.15 | +| Chimpanzee | 50 | +| Rabbit | 1.4 | +| Dog_(Beagle) | 10 | +| Cat | 4.5 | +| Rat | 0.4 | +| Sperm_Whale | 35000 | +| Turtle | 3 | +| Alligator | 270 | + +Most values will be clustered in the 0-100 range, but 35,000 is many magnitudes above that. A numeric facet will create 36 equal buckets of 1,000 each - containing almost all the cells in the first bucket. A numeric log facet will instead display the data more evenly across the visual range. + +![A screenshot of a numeric facet first and a numeric log facet second.](/img/numericlogfacet.png) + +A 1-bounded numeric log facet can be used if you'd like to exclude all the values below 1 (including zero and negative numbers). + +### Text-length facet {#text-length-facet} + +The Text-length facet returns a numerical value for each cell and plots it on a numeric facet chart. The expression used is + +``` +value.length() +``` + +This can be useful to, for example, look for values that did not successfully split on an earlier split operation, or to validate that data is a certain expected length (such as whether a date in YYYY/MM/DD is eight to ten characters). + +You can also employ a Log of text-length facet that allows you to navigate more easily a wide range of string lengths. This can be useful in the case of web-scraping, where lots of textual data is loaded into single cells and needs to be parsed out. + + +### Unicode character-code facet {#unicode-character-code-facet} + +![A screenshot of the Unicode facet.](/img/unicodefacet.png) + +The Unicode facet identifies and returns [Unicode decimal values](https://en.wikipedia.org/wiki/List_of_Unicode_characters). It generates a list of the Unicode numerical values of each character used in each text cell, which allows you to narrow down and search for special characters, punctuation, and other data formatting issues. + +This facet creates a numerical chart, which offers you the ability to narrow down to a range of numbers. For example, lowercase characters are numbers 97-122, uppercase characters are numbers 65-90, and numerical digits are numbers 48-57. + +### Facet by error {#facet-by-error} + +An error is a data type created by OpenRefine in the process of transforming data. For example, say you had converted a column to the number data type. If one cell had text characters in it, OpenRefine could either output the original text string unchanged or output an error. If you allow errors to be created, you can facet by them later to search for them and fix them. + +![A view of the expressions window with an error converting a string to a number.](/img/error.png) + +To store errors in cells, ensure that you have store error selected for the “On error†option in the expressions window. + +### Facet by null, empty, or blank {#facet-by-null-empty-or-blank} + +Any column can be faceted for [null and/or empty cells](#cell-data-types). These can help you find cells where you want to manually enter content. + +“Blank†means both null values and empty values. All three facets will generate “true†and “false†facets, “true†being blank. + +An empty cell is a cell that is set to contain a string, but doesn’t have any characters in it (a zero-length string). This can be left over from an operation that removed characters, or from manually editing a cell and deleting its contents. + +### Facet by star or flag {#facet-by-star-or-flag} + +Stars and flags offer you the opportunity to mark specific rows for yourself for later focus. Stars and flags persist through closing and opening your project, and thus can provide a different function than using a permalink to persist your facets. Stars and flags can be used in any way you want, although they are designed to help you flag errors and star rows of particular importance. + +You can manually star or flag rows simply by clicking on the icons to the left of each row. + +You can also apply stars or flags to all matching rows by using the All dropdown menu (on the first column) and selecting Edit rows → Star rows or Flag rows. This will create “true†and “false†facets in the Facet/Filter. These operations will modify all matching rows in your current subset. You can unstar or unflag them as well. + +You may wish to create a custom subset of your data through a series of separate faceting activities (rather than successively narrowing down with multiple facets applied). For example, you may wish to: +* apply a facet +* star all the matching rows +* remove that facet +* apply another, unrelated facet +* star all the new matching rows (which will not modify already-starred rows) +* remove that facet +* and then work with all of the cumulative starred rows. + +You can also create a text facet on any column with the expression `row.starred` or `row.flagged`. + +## Text filter {#text-filter} + +Filters allow you to narrow down your data based on whether a given column includes a text string. + +When you choose Text filter a box appears in the Facet/Filter tab that allows you to enter in text. Matching rows will narrow dynamically with every character you enter. You can set the search to be case-sensitive or not, and you can use this box to enter in a regular expression. + +For example, you can enter in “side†as a text filter, and it will return all cells in that column containing “side,†“sideways,†“offside,†etc. + +The text filter field supports [regular expressions](expressions#regular-expressions). For example, you can employ a regular expression to view all properly-formatted emails: + +``` +([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9\-\.]+)\.([a-zA-Z0-9\-]{2,15}) +``` + +You can press “invert†on this facet to then see blank cells or invalid email addresses. + +This filter works differently than facets because it is always active as long as it appears in the sidebar. If you “reset†it, you will delete all the text or expression you have entered. + +You can apply multiple text filters in succession, which will successively narrow your data subset. This can be useful if you apply multiple inverted filters, such as to filter out all rows that respond “yes†or “maybe†and only look at the remaining responses. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/grel.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/grel.md new file mode 100644 index 000000000..7ec90b464 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/grel.md @@ -0,0 +1,154 @@ +--- +id: grel +title: General Refine Expression Language +sidebar_label: General Refine Expression Language +--- + +## Basics {#basics} + +GREL (General Refine Expression Language) is designed to resemble Javascript. Formulas use variables and depend on data types to do things like string manipulation or mathematical calculations: + +|Example|Output| +|---|---| +| `value + " (approved)"` | Concatenate two strings; whatever is in the cell gets converted to a string first | +| `value + 2.239` | Add 2.239 to the existing value (if a number); append text "2.239" to the end of the string otherwise | +| `value.trim().length()`     | Trim leading and trailing whitespace of the cell value and then output the length of the result | +| `value.substring(7, 10)` | Output the substring of the value from character index 7, 8, and 9 (excluding character index 10) | +| `value.substring(13)` | Output the substring from index 13 to the end of the string | + +Note that the operator for string concatenation is `+` (not “&†as is used in Excel). + +Evaluating conditions uses symbols such as <, >, *, /, etc. To check whether two objects are equal, use two equal signs (`value=="true"`). + +See the [GREL functions page for a thorough reference](grelfunctions) on each function and its inputs and outputs. Read on below for more about the general nature of GREL expressions. + +## Syntax {#syntax} + +In GREL, functions can use either of these two forms: +* functionName(arg0, arg1, ...) +* arg0.functionName(arg1, ...) + +The second form is a shorthand to make expressions easier to read. It simply pulls the first argument out and appends it to the front of the function, with a dot: + +|Dot notation |Full notation | +|-|-| +| `value.trim().length()` | `length(trim(value))` | +| `value.substring(7, 10)` | `substring(value, 7, 10)` | + +So, in the dot shorthand, the functions occur from left to right in the order of calling, rather than in the reverse order with parentheses. This allows you to string together multiple functions in a readable order. + +The dot notation can also be used to access the member fields of [variables](expressions#variables). For referring to column names that contain spaces (anything not a continuous string), use square brackets instead of dot notation: + +|Example |Description | +|-|-| +| `FirstName.cells` | Access the cell in the column named “FirstName†of the current row | +| `cells["First Name"]` | Access the cell in the column called “First Name†of the current row | + +Square brackets can also be used to get substrings and sub-arrays, and single items from arrays: + +|Example |Description | +|-|-| +| `value[1,3]` | A substring of value, starting from character 1 up to but excluding character 3 | +| `"internationalization"[1,-2]` | Will return “nternationalizati†(negative indexes are counted from the end) | +| `row.columnNames[5]` | Will return the name of the fifth column | + +Any function that outputs an array can use square brackets to select only one part of the array to output as a string (remember that the index of the items in an array starts with 0). + +For example, [partition()](grelfunctions#partitions-s-or-p-fragment-b-omitfragment-optional) would normally output an array of three items: the part before your chosen fragment, the fragment you've identified, and the part after. Selecting only the third part with `"internationalization".partition("nation")[2]` will output “alization†(and so will [-1], indicating the final item in the array). + +## Controls {#controls} + +GREL offers controls to support branching and looping (that is, “if†and “for†functions), but unlike functions, their arguments don't all get evaluated before they get run. A control can decide which part of the code to execute and can affect the environment bindings. Functions, on the other hand, can't do either. Each control decides which of their arguments to evaluate to `value`, and how. + +Please note that the GREL control names are case-sensitive: for example, the isError() control can't be called with iserror(). + +#### if(e, eTrue, eFalse) {#ife-etrue-efalse} + +Expression e is evaluated to a value. If that value is true, then expression eTrue is evaluated and the result is the value of the whole if() expression. Otherwise, expression eFalse is evaluated and that result is the value. + +Examples: + +| Example expression | Result | +| ------------------------------------------------------------------------ | ------------ | +| `if("internationalization".length() > 10, "big string", "small string")` | “big string†| +| `if(mod(37, 2) == 0, "even", "odd")` | “odd†| + +Nested if (switch case) example: + + if(value == 'Place', 'http://www.example.com/Location', + + if(value == 'Person', 'http://www.example.com/Agent', + + if(value == 'Book', 'http://www.example.com/Publication', + + null))) + +#### with(e1, variable v, e2) {#withe1-variable-v-e2} + +Evaluates expression e1 and binds its value to variable v. Then evaluates expression e2 and returns that result. + +| Example expression | Result | +| ------------------------------------------------------------------------------------ | ---------- | +| `with("european union".split(" "), a, a.length())` | 2 | +| `with("european union".split(" "), a, forEach(a, v, v.length()))` | [ 8, 5 ] | +| `with("european union".split(" "), a, forEach(a, v, v.length()).sum() / a.length())` | 6.5 | + +#### filter(e1, v, e test) {#filtere1-v-e-test} + +Evaluates expression e1 to an array. Then for each array element, binds its value to variable v, evaluates expression test - which should return a boolean. If the boolean is true, pushes v onto the result array. + +| Expression | Result | +| ---------------------------------------------- | ------------- | +| `filter([ 3, 4, 8, 7, 9 ], v, mod(v, 2) == 1)` | [ 3, 7, 9 ] | + +#### forEach(e1, v, e2) {#foreache1-v-e2} + +Evaluates expression e1 to an array. Then for each array element, binds its value to variable v, evaluates expression e2, and pushes the result onto the result array. When e1 is a JSON object, `forEach` iterates over its keys. + +| Expression | Result | +| ------------------------------------------ | ------------------- | +| `forEach([ 3, 4, 8, 7, 9 ], v, mod(v, 2))` | [ 1, 0, 0, 1, 1 ] | + +#### forEachIndex(e1, i, v, e2) {#foreachindexe1-i-v-e2} + +Evaluates expression e1 to an array. Then for each array element, binds its index to variable i and its value to variable v, evaluates expression e2, and pushes the result onto the result array. + +| Expression | Result | +| ------------------------------------------------------------------------------- | --------------------------- | +| `forEachIndex([ "anne", "ben", "cindy" ], i, v, (i + 1) + ". " + v).join(", ")` | 1. anne, 2. ben, 3. cindy | + +#### forRange(n from, n to, n step, v, e) {#forrangen-from-n-to-n-step-v-e} + +Iterates over the variable v starting at from, incrementing by the value of step each time while less than to. At each iteration, evaluates expression e, and pushes the result onto the result array. + +#### forNonBlank(e, v, eNonBlank, eBlank) {#fornonblanke-v-enonblank-eblank} + +Evaluates expression e. If it is non-blank, forNonBlank() binds its value to variable v, evaluates expression eNonBlank and returns the result. Otherwise (if e evaluates to blank), forNonBlank() evaluates expression eBlank and returns that result instead. + +Unlike other GREL functions beginning with “for,†forNonBlank() is not iterative. forNonBlank() essentially offers a shorter syntax to achieving the same outcome by using the isNonBlank() function within an “if†statement. + +#### isBlank(e), isNonBlank(e), isNull(e), isNotNull(e), isNumeric(e), isError(e) {#isblanke-isnonblanke-isnulle-isnotnulle-isnumerice-iserrore} + +Evaluates the expression e, and returns a boolean based on the named evaluation. + +Examples: + +| Expression | Result | +| ------------------- | ------- | +| `isBlank("abc")` | false | +| `isNonBlank("abc")` | true | +| `isNull("abc")` | false | +| `isNotNull("abc")` | true | +| `isNumeric(2)` | true | +| `isError(1)` | false | +| `isError("abc")` | false | +| `isError(1 / 0)` | true | + +Remember that these are controls and not functions: you can’t use dot notation (for example, the format `e.isX()` will not work). + +## Constants {#constants} +|Name |Meaning | +|-|-| +| true | The boolean constant true | +| false | The boolean constant false | +| PI | From [Java's Math.PI](https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#PI), the value of pi (that is, 3.1415...) | diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/grelfunctions.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/grelfunctions.md new file mode 100644 index 000000000..5e4893851 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/grelfunctions.md @@ -0,0 +1,535 @@ +--- +id: grelfunctions +title: GREL functions +sidebar_label: GREL functions +--- + +## Reading this reference {#reading-this-reference} + +For the reference below, the function is given in full-length notation and the in-text examples are written in dot notation. Shorthands are used to indicate the kind of [data type](exploring#data-types) used in each function: s for string, b for boolean, n for number, d for date, a for array, p for a regex pattern, and o for object (meaning any data type), as well as “null†and “error†data types. + +If a function can take more than one kind of data as input or can output more than one kind of data, that is indicated with more than one letter (as with “s or aâ€) or with o for object, meaning it can take any type of data (string, boolean, date, number, etc.). + +We also use shorthands for substring (“subâ€) and separator string (“sepâ€). +Optional arguments will say “(optional)â€. + +In places where OpenRefine will accept a string (s) or a regex pattern (p), you can supply a string by putting it in quotes. If you wish to use any [regex](expressions#regular-expressions) notation, wrap the pattern in forward slashes. + +## Boolean functions {#boolean-functions} + +###### and(b1, b2, ...) {#andb1-b2-} + +Uses the logical operator AND on two or more booleans to output a boolean. Evaluates multiple statements into booleans, then returns true if all of the statements are true. For example, `(1 < 3).and(1 < 0)` returns false because one condition is true and one is false. + +###### or(b1, b2, ...) {#orb1-b2-} + +Uses the logical operator OR on two or more booleans to output a boolean. For example, `(1 < 3).or(1 > 7)` returns true because at least one of the conditions (the first one) is true. + +###### not(b) {#notb} + +Uses the logical operator NOT on a boolean to output a boolean. For example, `not(1 > 7)` returns true because 1 > 7 itself is false. + +###### xor(b1, b2, ...) {#xorb1-b2-} + +Uses the logical operator XOR (exclusive-or) on two or more booleans to output a boolean. Evaluates multiple statements, then returns true if only one of them is true. For example, `(1 < 3).xor(1 < 7)` returns false because more than one of the conditions is true. + +## String functions {#string-functions} + +###### length(s) {#lengths} + +Returns the length of string s as a number. + +###### toString(o, string format (optional)) {#tostringo-string-format-optional} + +Takes any value type (string, number, date, boolean, error, null) and gives a string version of that value. + +You can use toString() to convert numbers to strings with rounding, using an [optional string format](https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html). For example, if you applied the expression `value.toString("%.0f")` to a column: + +|Input|Output| +|-|-| +|3.2|3| +|0.8|1| +|0.15|0| +|100.0|100| + +You can also convert dates to strings, using date parsing syntax built into OpenRefine (see [the toDate() function for details](#todateo-b-monthfirst-s-format1-s-format2-)). For example, `value.toString("MMM-dd-yyyy")` would convert the date value [2024-10-15T00:00:00Z] to “Oct-15-2024â€. + +Note: In OpenRefine, using toString() on a null cell outputs the string “nullâ€. + +### Testing string characteristics {#testing-string-characteristics} + +###### startsWith(s, sub) {#startswiths-sub} + +Returns a boolean indicating whether s starts with sub. For example, `"food".startsWith("foo")` returns true, whereas `"food".startsWith("bar")` returns false. + +###### endsWith(s, sub) {#endswiths-sub} + +Returns a boolean indicating whether s ends with sub. For example, `"food".endsWith("ood")` returns true, whereas `"food".endsWith("odd")` returns false. + +###### contains(s, sub or p) {#containss-sub-or-p} + +Returns a boolean indicating whether s contains sub, which is either a substring or a regex pattern. For example, `"food".contains("oo")` returns true whereas `"food".contains("ee")` returns false. + +You can search for a regular expression by wrapping it in forward slashes rather than quotes: `"rose is a rose".contains(/\s+/)` returns true. startsWith() and endsWith() can only take strings, while contains() can take a regex pattern, so you can use contains() to look for beginning and ending string patterns. + +### Basic string modification {#basic-string-modification} + +#### Case conversion {#case-conversion} + +###### toLowercase(s) {#tolowercases} + +Returns string s converted to all lowercase characters. + +###### toUppercase(s) {#touppercases} + +Returns string s converted to all uppercase characters. + +###### toTitlecase(s) {#totitlecases} + +Returns string s converted into titlecase: a capital letter starting each word, and the rest of the letters lowercase. For example, `"Once upon a midnight DREARY".toTitlecase()` returns the string “Once Upon A Midnight Drearyâ€. + +#### Trimming {#trimming} + +###### trim(s) {#trims} + +Returns a copy of the string s with leading and trailing whitespace removed. For example, `" island ".trim()` returns the string “islandâ€. Identical to strip(). + +###### strip(s) {#strips} + +Returns a copy of the string s with leading and trailing whitespace removed. For example, `" island ".strip()` returns the string “islandâ€. Identical to trim(). + +###### chomp(s, sep) {#chomps-sep} + +Returns a copy of string s with the string sep removed from the end if s ends with sep; otherwise, just returns s. For example, `"barely".chomp("ly")` and `"bare".chomp("ly")` both return the string “bareâ€. + +#### Substring {#substring} + +###### substring(s, n from, n to (optional)) {#substrings-n-from-n-to-optional} + +Returns the substring of s starting from character index from, and up to (excluding) character index to. If the to argument is omitted, substring will output to the end of s. For example, `"profound".substring(3)` returns the string “foundâ€, and `"profound".substring(2, 4)` returns the string “ofâ€. + +Remember that character indices start from zero. A negative character index counts from the end of the string. For example, `"profound".substring(0, -1)` returns the string “profounâ€. + +###### slice(s, n from, n to (optional)) {#slices-n-from-n-to-optional} + +Identical to substring() in relation to strings. Also works with arrays; see [Array functions section](#slicea-n-from-n-to-optional). + +###### get(s, n from, n to (optional)) {#gets-n-from-n-to-optional} + +Identical to substring() in relation to strings. Also works with named fields. Also works with arrays; see [Array functions section](#geta-n-from-n-to-optional). + +#### Find and replace {#find-and-replace} + +###### indexOf(s, sub) {#indexofs-sub} + +Returns the first character index of sub as it first occurs in s; or, returns -1 if s does not contain sub. For example, `"internationalization".indexOf("nation")` returns 5, whereas `"internationalization".indexOf("world")` returns -1. + +###### lastIndexOf(s, sub) {#lastindexofs-sub} + +Returns the first character index of sub as it last occurs in s; or, returns -1 if s does not contain sub. For example, `"parallel".lastIndexOf("a")` returns 3 (pointing at the second “aâ€). + +###### replace(s, s or p find, s replace) {#replaces-s-or-p-find-s-replace} + +Returns the string obtained by replacing the find string with the replace string in the inputted string. For example, `"The cow jumps over the moon and moos".replace("oo", "ee")` returns the string “The cow jumps over the meen and meesâ€. Find can be a regex pattern. For example, `"The cow jumps over the moon and moos".replace(/\s+/, "_")` will return “The_cow_jumps_over_the_moon_and_moosâ€. + +You cannot find or replace nulls with this, as null is not a string. You can instead: + +1. Facet by null and then bulk-edit them to a string, or +2. Transform the column with an expression such as `if(value==null,"new",value)`. + +###### replaceChars(s, s find, s replace) {#replacecharss-s-find-s-replace} + +Returns the string obtained by replacing a character in s, identified by find, with the corresponding character identified in replace. For example, `"Téxt thát was optícálly recógnízéd".replaceChars("áéíóú", "aeiou")` returns the string “Text that was optically recognizedâ€. You cannot use this to replace a single character with more than one character. + +###### find(s, sub or p) {#finds-sub-or-p} + +Outputs an array of all consecutive substrings inside string s that match the substring or [regex](expressions#grel-supported-regex) pattern p. For example, `"abeadsabmoloei".find(/[aeio]+/)` would result in the array [ "a", "ea", "a", "o", "oei" ]. + +You can supply a substring instead of p, by putting it in quotes, and OpenRefine will compile it into a regex pattern. Anytime you supply quotes, OpenRefine interprets the contents as a string, not regex. If you wish to use any regex notation, wrap the pattern in forward slashes. + +###### match(s, p) {#matchs-p} + +Attempts to match the string s in its entirety against the [regex](expressions#grel-supported-regex) pattern p and, if the pattern is found, outputs an array of all [capturing groups](https://www.regular-expressions.info/brackets.html) (found in order). For example, `"230.22398, 12.3480".match(/.*(\d\d\d\d)/)` returns an array of 1 substring: [ "3480" ]. It does not find 2239 as the first sequence with four digits, because the regex indicates the four digits must come at the end of the string. + +You will need to convert the array to a string to store it in a cell, with a function such as toString(). An empty array [] is returned when there is no match to the desired substrings. A null is output when the entire regex does not match. + +Remember to enclose your regex in forward slashes, and to escape characters and use parentheses as needed. Parentheses denote a desired substring (capturing group); for example, “.*(\d\d\d\d)†would return an array containing a single value, while “(.*)(\d\d\d\d)†would return two. So, if you are looking for a desired substring anywhere within a string, use the syntax `value.match(/.*(desired-substring-regex).*/)`. + +For example, if `value` is “hello 123456 goodbyeâ€, the following would occur: + +|Expression|Result| +|-|-| +|`value.match(/\d{6}/)` |null (does not match the full string)| +|`value.match(/.*\d{6}.*/)` |[ ] (no indicated substring)| +|`value.match(/.*(\d{6}).*/)` |[ "123456" ] (array with one value)| +|`value.match(/(.*)(\d{6})(.*)/)` |[ "hello ", "123456", " goodbye" ] (array with three values)| + +### String parsing and splitting {#string-parsing-and-splitting} + +###### toNumber(s) {#tonumbers} + +Returns a string converted to a number. Will attempt to convert other formats into a string, then into a number. If the value is already a number, it will return the number. + +###### split(s, s or p sep, b preserveTokens (optional)) {#splits-s-or-p-sep-b-preservetokens-optional} + +Returns the array of strings obtained by splitting s by sep. The separator can be either a string or a regex pattern. For example, `"fire, water, earth, air".split(",")` returns an array of 4 strings: [ "fire", " water", " earth", " air" ]. Note that the space characters are retained but the separator is removed. If you include “true†for the preserveTokens boolean, empty segments are preserved. + +###### splitByLengths(s, n1, n2, ...) {#splitbylengthss-n1-n2-} + +Returns the array of strings obtained by splitting s into substrings with the given lengths. For example, `"internationalization".splitByLengths(5, 6, 3)` returns an array of 3 strings: [ "inter", "nation", "ali" ]. Excess characters are discarded. + +###### smartSplit(s, s or p sep (optional)) {#smartsplits-s-or-p-sep-optional} + +Returns the array of strings obtained by splitting s by sep, or by guessing either tab or comma separation if there is no sep given. Handles quotes properly and understands cancelled characters. The separator can be either a string or a regex pattern. For example, `value.smartSplit("\n")` will split at a carriage return or a new-line character. + +Note: [`value.escape('javascript')`](#escapes-s-mode) is useful for previewing unprintable characters prior to using smartSplit(). + +###### splitByCharType(s) {#splitbychartypes} + +Returns an array of strings obtained by splitting s into groups of consecutive characters each time the characters change [Unicode categories](https://en.wikipedia.org/wiki/Unicode_character_property#General_Category). For example, `"HenryCTaylor".splitByCharType()` will result in an array of [ "H", "enry", "CT", "aylor" ]. It is useful for separating letters and numbers: `"BE1A3E".splitByCharType()` will result in [ "BE", "1", "A", "3", "E" ]. + +###### partition(s, s or p fragment, b omitFragment (optional)) {#partitions-s-or-p-fragment-b-omitfragment-optional} + +Returns an array of strings [ a, fragment, z ] where a is the substring within s before the first occurrence of fragment, and z is the substring after fragment. Fragment can be a string or a regex. For example, `"internationalization".partition("nation")` returns 3 strings: [ "inter", "nation", "alization" ]. If s does not contain fragment, it returns an array of [ s, "", "" ] (the original unpartitioned string, and two empty strings). + +If the omitFragment boolean is true, for example with `"internationalization".partition("nation", true)`, the fragment is not returned. The output is [ "inter", "alization" ]. + +You can use regex for your fragment. The expresion `"abcdefgh".partition(/c.e/)` will output [“abcâ€, "cde", defgh†]. + +###### rpartition(s, s or p fragment, b omitFragment (optional)) {#rpartitions-s-or-p-fragment-b-omitfragment-optional} + +Returns an array of strings [ a, fragment, z ] where a is the substring within s before the last occurrence of fragment, and z is the substring after the last instance of fragment. (Rpartition means “reverse partition.â€) For example, `"parallel".rpartition("a")` returns 3 strings: [ "par", "a", "llel" ]. Otherwise works identically to partition() above. + +### Encoding and hashing {#encoding-and-hashing} + +###### diff(s1, s2, s timeUnit (optional)) {#diffs1-s2-s-timeunit-optional} + +Takes two strings and compares them, returning a string. Returns the remainder of s2 starting with the first character where they differ. For example, `"cacti".diff("cactus")` returns "us". Also works with dates; see [Date functions](#diffd1-d2-s-timeunit). + +###### escape(s, s mode) {#escapes-s-mode} + +Escapes s in the given escaping mode. The mode can be one of: "html", "xml", "csv", "url", "javascript". Note that quotes are required around your mode. See the [recipes](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#question-marks--showing-in-your-data) for examples of escaping and unescaping. + +###### unescape(s, s mode) {#unescapes-s-mode} + +Unescapes s in the given escaping mode. The mode can be one of: "html", "xml", "csv", "url", "javascript". Note that quotes are required around your mode. See the [recipes](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#atampampt----att) for examples of escaping and unescaping. + +###### md5(o) {#md5o} + +Returns the [MD5 hash](https://en.wikipedia.org/wiki/MD5) of an object. If fed something other than a string (array, number, date, etc.), md5() will convert it to a string and deliver the hash of the string. For example, `"internationalization".md5()` will return 2c55a1626e31b4e373ceedaa9adc12a3. + +###### sha1(o) {#sha1o} + +Returns the [SHA-1 hash](https://en.wikipedia.org/wiki/SHA-1) of an object. If fed something other than a string (array, number, date, etc.), sha1() will convert it to a string and deliver the hash of the string. For example, `"internationalization".sha1()` will return cd05286ee0ff8a830dbdc0c24f1cb68b83b0ef36. + +###### phonetic(s, s encoding) {#phonetics-s-encoding} + +Returns a phonetic encoding of a string, based on an available phonetic algorithm. See the [section on phonetic clustering](cellediting#clustering-methods) for more information. Can be one of the following supported phonetic methods: [metaphone, doublemetaphone, metaphone3](https://www.wikipedia.org/wiki/Metaphone), [soundex](https://en.wikipedia.org/wiki/Soundex), [cologne](https://en.wikipedia.org/wiki/Cologne_phonetics). Quotes are required around your encoding method. For example, `"Ruth Prawer Jhabvala".phonetic("metaphone")` outputs the string “R0PRWRJHBFLâ€. + +###### reinterpret(s, s encoderTarget, s encoderSource) {#reinterprets-s-encodertarget-s-encodersource} + +Returns s reinterpreted through the given character encoders. You must supply one of the [supported encodings](http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html) for each of the original source and the target output. Note that quotes are required around your character encoder. + +When an OpenRefine project is started, data is imported and interpreted. A specific character encoding is identified or manually selected at that time (such as UTF-8). You can reinterpret a column into another specificed encoding using this function. This function may not fix your data; it may be better to use this in conjunction with new projects to test the interpretation, and pre-format your data as needed. + +###### fingerprint(s) {#fingerprints} + +Returns the fingerprint of s, a string that is the first step in [fingerprint clustering methods](cellediting#clustering-methods): it will trim whitespaces, convert all characters to lowercase, remove punctuation, sort words alphabetically, etc. For example, `"Ruth Prawer Jhabvala".fingerprint()` outputs the string “jhabvala prawer ruthâ€. + +###### ngram(s, n) {#ngrams-n} + +Returns an array of the word n-grams of s. That is, it lists all the possible consecutive combinations of n words in the string. For example, `"Ruth Prawer Jhabvala".ngram(2)` would output the array [ "Ruth Prawer", "Prawer Jhabvala" ]. A word n-gram of 1 simply lists all the words in original order; an n-gram larger than the number of words in the string will only return the original string inside an array (e.g. `"Ruth Prawer Jhabvala".ngram(4)` would simply return ["Ruth Prawer Jhabvala"]). + +###### ngramFingerprint(s, n) {#ngramfingerprints-n} + +Returns the [n-gram fingerprint](cellediting#clustering-methods) of s. For example, `"banana".ngram(2)` would output “anbanaâ€, after first generating the 2-grams “ba an na an naâ€, removing duplicates, and sorting them alphabetically. + +###### unicode(s) {#unicodes} + +Returns an array of strings describing each character of s in their full unicode notation. For example, `"Bernice Rubens".unicode()` outputs [ 66, 101, 114, 110, 105, 99, 101, 32, 82, 117, 98, 101, 110, 115 ]. + +###### unicodeType(s) {#unicodetypes} + +Returns an array of strings describing each character of s by their unicode type. For example, `"Bernice Rubens".unicodeType()` outputs [ "uppercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "space separator", "uppercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter", "lowercase letter" ]. + +## Format-based functions (JSON, HTML, XML) {#format-based-functions-json-html-xml} + +###### jsonize(o) {#jsonizeo} + +Quotes a value as a JSON literal value. + +###### parseJson(s) {#parsejsons} + +Parses a string as JSON. get() can then be used with parseJson(): for example, `parseJson(" { 'a' : 1 } ").get("a")` returns 1. + +For example, from the following JSON array in `value`, we want to get all instances of “keywords†having the same object string name of “textâ€, and combine them, using the forEach() function to iterate over the array. + + { + "status":"OK", + "url":"", + "language":"english", + "keywords":[ + { + "text":"York en route", + "relevance":"0.974363" + }, + { + "text":"Anthony Eden", + "relevance":"0.814394" + }, + { + "text":"President Eisenhower", + "relevance":"0.700189" + } + ] + } + +The GREL expression `forEach(value.parseJson().keywords,v,v.text).join(":::")` will output “York en route:::Anthony Eden:::President Eisenhowerâ€. + +### Jsoup XML and HTML parsing {#jsoup-xml-and-html-parsing} + +###### parseHtml(s) {#parsehtmls} +Given a cell full of HTML-formatted text, parseHtml() simplifies HTML tags (such as by removing “ /†at the end of self-closing tags), closes any unclosed tags, and inserts linebreaks and indents for cleaner code. You cannot pass parseHtml() a URL, but you can pre-fetch HTML with the [Add column by fetching URLs](columnediting#add-column-by-fetching-urls) menu option. + +A cell cannot store the output of parseHtml() unless you convert it with toString(): for example, `value.parseHtml().toString()`. + +When parseHtml() simplifies HTML, it can sometimes introduce errors. When closing tags, it makes its best guesses based on line breaks, indentation, and the presence of other tags. You may need to manually check the results. + +You can then extract or [select()](#selects-element) which portions of the HTML document you need for further splitting, partitioning, etc. An example of extracting all table rows from a div using parseHtml().select() together is described more in depth at [StrippingHTML](https://github.com/OpenRefine/OpenRefine/wiki/StrippingHTML). + +###### parseXml(s) {#parsexmls} +Given a cell full of XML-formatted text, parseXml() returns a full XML document and adds any missing closing tags. You can then extract or [select()](#selects-element) which portions of the XML document you need for further splitting, partitioning, etc. Functions the same way as parseHtml() is described above. + +###### select(s, element) {#selects-element} +Returns an array of all the desired elements from an HTML or XML document, if the element exists. Elements are identified using the [Jsoup selector syntax](https://jsoup.org/apidocs/org/jsoup/select/Selector.html). For example, `value.parseHtml().select("img.portrait")[0]` would return the entirety of the first “img†tag with the “portrait†class found in the parsed HTML inside `value`. Returns an empty array if no matching element is found. Use with toString() to capture the results in a cell. A tutorial of select() is shown in [StrippingHTML](https://github.com/OpenRefine/OpenRefine/wiki/StrippingHTML). + +You can use select() more than once: + +``` +value.parseHtml().select("div#content")[0].select("tr").toString() +``` + +###### htmlAttr(s, element) {#htmlattrs-element} +Returns a string from an attribute on an HTML element. Use it in conjunction with parseHtml() as in the following example: `value.parseHtml().select("a.email")[0].htmlAttr("href")` would retrieve the email address attached to a link with the “email†class. + +###### xmlAttr(s, element) {#xmlattrs-element} +Returns a string from an attribute on an XML element. Functions the same way htmlAttr() is described above. Use it in conjunction with parseXml(). + +###### htmlText(element) {#htmltextelement} +Returns a string of the text from within an HTML element (including all child elements), removing HTML tags and line breaks inside the string. Use it in conjunction with parseHtml() and select() to provide an element, as in the following example: `value.parseHtml().select("div.footer")[0].htmlText()`. + +###### xmlText(element) {#xmltextelement} +Returns a string of the text from within an XML element (including all child elements). Functions the same way htmlText() is described above. Use it in conjunction with parseXml() and select() to provide an element. + +###### wholeText(element) {#wholetextelement} + +Selects the (unencoded) text of an element and its children, including any new lines and spaces, and returns a string of unencoded, un-normalized text. Use it in conjunction with parseHtml() and select() to provide an element as in the following example: `value.parseHtml().select("div.footer")[0].wholeText()`. + +###### innerHtml(element) {#innerhtmlelement} +Returns the [inner HTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) of an HTML element. This will include text and children elements within the element selected. Use it in conjunction with parseHtml() and select() to provide an element. + +###### innerXml(element) {#innerxmlelement} +Returns the inner XML elements of an XML element. Does not return the text directly inside your chosen XML element - only the contents of its children. To select the direct text, use ownText(). To select both, use xmlText(). Use it in conjunction with parseXml() and select() to provide an element. + +###### ownText(element) {#owntextelement} +Returns the text directly inside the selected XML or HTML element only, ignoring text inside children elements (for this, use innerXml()). Use it in conjunction with a parser and select() to provide an element. + +## Array functions {#array-functions} + +###### length(a) {#lengtha} +Returns the size of an array, meaning the number of objects inside it. Arrays can be empty, in which case length() will return 0. + +###### slice(a, n from, n to (optional)) {#slicea-n-from-n-to-optional} +Returns a sub-array of a given array, from the first index provided and up to and excluding the optional last index provided. Remember that array objects are indexed starting at 0. If the to value is omitted, it is understood to be the end of the array. For example, `[0, 1, 2, 3, 4].slice(1, 3)` returns [ 1, 2 ], and `[ 0, 1, 2, 3, 4].slice(2)` returns [ 2, 3, 4 ]. Also works with strings; see [String functions](#slices-n-from-n-to-optional). + +###### get(a, n from, n to (optional)) {#geta-n-from-n-to-optional} +Returns a sub-array of a given array, from the first index provided and up to and excluding the optional last index provided. Remember that array objects are indexed starting at 0. + +If the to value is omitted, only one array item is returned, as a string, instead of a sub-array. To return a sub-array from one index to the end, you can set the to argument to a very high number such as `value.get(2,999)` or you can use something like `with(value,a,a.get(1,a.length()))` to count the length of each array. + +Also works with strings; see [String functions](#gets-n-from-n-to-optional). + +###### inArray(a, s) {#inarraya-s} +Returns true if the array contains the desired string, and false otherwise. Will not convert data types; for example, `[ 1, 2, 3, 4 ].inArray("3")` will return false. + +###### reverse(a) {#reversea} +Reverses the array. For example, `[ 0, 1, 2, 3].reverse()` returns the array [ 3, 2, 1, 0 ]. + +###### sort(a) {#sorta} +Sorts the array in ascending order. Sorting is case-sensitive, uppercase first and lowercase second. For example, `[ "al", "Joe", "Bob", "jim" ].sort()` returns the array [ "Bob", "Joe", "al", "jim" ]. + +###### sum(a) {#suma} +Return the sum of the numbers in the array. For example, `[ 2, 1, 0, 3 ].sum()` returns 6. + +###### join(a, sep) {#joina-sep} +Joins the items in the array with sep, and returns it all as a string. For example, `[ "and", "or", "not" ].join("/")` returns the string “and/or/notâ€. + +###### uniques(a) {#uniquesa} +Returns the array with duplicates removed. Case-sensitive. For example, `[ "al", "Joe", "Bob", "Joe", "Al", "Bob" ].uniques()` returns the array [ "Joe", "al", "Al", "Bob" ]. + +As of OpenRefine 3.4.1, uniques() reorders the array items it returns; in 3.4 beta 644 and onwards, it preserves the original order (in this case, [ "al", "Joe", "Bob", "Al" ]). + +## Date functions {#date-functions} + +###### now() {#now} + +Returns the current time according to your system clock, in the [ISO 8601 extended format](exploring#data-types) (converted to UTC). For example, 10:53am (and 00 seconds) on November 26th 2020 in EST returns [date 2020-11-26T15:53:00Z]. + +###### toDate(o, b monthFirst, s format1, s format2, ...) {#todateo-b-monthfirst-s-format1-s-format2-} + +Returns the inputted object converted to a date object. Without arguments, it returns the ISO 8601 extended format. With arguments, you can control the output format: +* monthFirst: set false if the date is formatted with the day before the month. +* formatN: attempt to parse the date using an ordered list of possible formats. Supply formats based on the [SimpleDateFormat](https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html) syntax (and see the table below for a handy reference). + +For example, you can parse a column containing dates in different formats, such as cells with “Nov-09†and “11/09â€, using `value.toDate('MM/yy','MMM-yy').toString('yyyy-MM')` and both will output “2009-11â€. For another example, “1/4/2012 13:30:00†can be parsed into a date using `value.toDate('d/M/y H:m:s')`. + +| Letter | Date or Time Component | Presentation | Examples | +|-|-|-|-| +| G | Era designator | Text | AD | +| y | Year | Year | 1996; 96 | +| Y | [Week year](https://en.wikipedia.org/wiki/ISO_week_date#First_week) | Year | 2009; 09 | +| M | Month in year | Month | July; Jul; 07 | +| w | Week in year | Number | 27 | +| W | Week in month | Number | 2 | +| D | Day in year | Number | 189 | +| d | Day in month | Number | 10 | +| F | Day of week in month | Number | 2 | +| E | Day name in week | Text | Tuesday; Tue | +| u | Day number of week (1 = Monday, ..., 7 = Sunday) | Number | 1 | +| a | AM/PM marker | Text | PM | +| H | Hour in day (0-23) | Number | 0 | +| k | Hour in day (1-24) | Number | 24 | +| K | Hour in AM/PM (0-11) | Number | 0 | +| h | Hour in AM/PM (1-12) | Number | 12 | +| m | Minute in hour | Number | 30 | +| s | Second in minute | Number | 55 | +| S | Millisecond | Number | 978 | +| n | Nanosecond | Number | 789000 | +| z | Time zone | General time zone | Pacific Standard Time; PST; GMT-08:00 | +| Z | Time zone | RFC 822 time zone | \-0800 | +| X | Time zone | ISO 8601 time zone | \-08; -0800; -08:00 | + +###### diff(d1, d2, s timeUnit) {#diffd1-d2-s-timeunit} + +Given two dates, returns a number indicating the difference in a given time unit (see the table below). For example, `diff(("Nov-11".toDate('MMM-yy')), ("Nov-09".toDate('MMM-yy')), "weeks")` will return 104, for 104 weeks, or two years. The later date should go first. If the output is negative, invert d1 and d2. + +Also works with strings; see [diff() in string functions](#diffsd1-sd2-s-timeunit-optional). + +###### inc(d, n, s timeUnit) {#incd-n-s-timeunit} + +Returns a date changed by the given amount in the given unit of time (see the table below). The default unit is “hourâ€. A positive value increases the date, and a negative value moves it back in time. For example, if you want to move a date backwards by two months, use `value.inc(-2,"month")`. + +###### datePart(d, s timeUnit) {#datepartd-s-timeunit} + +Returns part of a date. The data type returned depends on the unit (see the table below). + +OpenRefine supports the following values for timeUnit: + +| Unit | Date part returned | Returned data type | Example using [date 2014-03-14T05:30:04.000789000Z] as value | +|-|-|-|-| +| years | Year | Number | value.datePart("years") → 2014 | +| year | Year | Number | value.datePart("year") → 2014 | +| months | Month | Number | value.datePart("months") → 2 | +| month | Month | Number | value.datePart("month") → 2 | +| weeks | Week of the month | Number | value.datePart("weeks") → 3 | +| week | Week of the month | Number | value.datePart("week") → 3 | +| w | Week of the month | Number | value.datePart("w") → 3 | +| weekday | Day of the week | String | value.datePart("weekday") → Friday | +| hours | Hour | Number | value.datePart("hours") → 5 | +| hour | Hour | Number | value.datePart("hour") → 5 | +| h | Hour | Number | value.datePart("h") → 5 | +| minutes | Minute | Number | value.datePart("minutes") → 30 | +| minute | Minute | Number | value.datePart("minute") → 30 | +| min | Minute | Number | value.datePart("min") → 30 | +| seconds | Seconds | Number | value.datePart("seconds") → 04 | +| sec | Seconds | Number | value.datePart("sec") → 04 | +| s | Seconds | Number | value.datePart("s") → 04 | +| milliseconds | Millseconds | Number | value.datePart("milliseconds") → 789 | +| ms | Millseconds | Number | value.datePart("ms") → 789 | +| S | Millseconds | Number | value.datePart("S") → 789 | +| n | Nanoseconds | Number | value.datePart("n") → 789000 | +| nano | Nanoseconds | Number | value.datePart("n") → 789000 | +| nanos | Nanoseconds | Number | value.datePart("n") → 789000 | +| time | Milliseconds between input and the [Unix Epoch](https://en.wikipedia.org/wiki/Unix_time) | Number | value.datePart("time") → 1394775004000 | + +## Math functions {#math-functions} + +For integer division and precision, you can use simple evaluations such as `1 / 2`, which is equivalent to `floor(1/2)` - that is, it returns only whole number results. If either operand is a floating point number, they both get promoted to floating point and a floating point result is returned. You can use `1 / 2.0` or `1.0 / 2` or `1.0 * x / y` (if you're working with variables of unknown contents). + +:::caution +Some of these math functions don't recognize integers when supplied as the first argument in dot notation (e.g., `5.cos()` simply returns 5 instead of the expected result). To ensure operations are successful, always wrap the first argument in brackets, such as `(value).cos()`. +::: + +|Function|Use|Example| +|-|-|-| +|`abs(n)`|Returns the absolute value of a number.|`abs(-6)` returns 6.| +|`acos(n)`|Returns the arc cosine of an angle, in the range 0 through [PI](https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#PI).|`acos(0.345)` returns 1.218557541697832.| +|`asin(n)`|Returns the arc sine of an angle in the range of -PI/2 through PI/2.|`asin(0.345)` returns 0.35223878509706474.| +|`atan(n)`|Returns the arc tangent of an angle in the range of -PI/2 through PI/2.|`atan(0.345)` returns 0.3322135507465967.| +|`atan2(n1, n2)`|Converts rectangular coordinates (n1, n2) to polar (r, theta). Returns number theta.|`atan2(0.345,0.6)` returns 0.5218342798144103.| +|`ceil(n)`|Returns the ceiling of a number.|`3.7.ceil()` returns 4 and `-3.7.ceil()` returns -3.| +|`combin(n1, n2)`|Returns the number of combinations for n2 elements as divided into n1.|`combin(20,2)` returns 190.| +|`cos(n)`|Returns the trigonometric cosine of a value.|`cos(5)` returns 0.28366218546322625.| +|`cosh(n)`|Returns the hyperbolic cosine of a value.|`cosh(5)` returns 74.20994852478785.| +|`degrees(n)`|Converts an angle from radians to degrees.|`degrees(5)` returns 286.4788975654116.| +|`even(n)`|Rounds the number up to the nearest even integer.|`even(5)` returns 6.| +|`exp(n)`|Returns [e](https://en.wikipedia.org/wiki/E_(mathematical_constant)) raised to the power of n.|`exp(5)` returns 148.4131591025766.| +|`fact(n)`|Returns the factorial of a number, starting from 1.|`fact(5)` returns 120.| +|`factn(n1, n2)`|Returns the factorial of n1, starting from n2.|`factn(10,3)` returns 280.| +|`floor(n)`|Returns the floor of a number.|`3.7.floor()` returns 3 and `-3.7.floor()` returns -4.| +|`gcd(n1, n2)`|Returns the greatest common denominator of two numbers.|`gcd(95,135)` returns 5.| +|`lcm(n1, n2)`|Returns the least common multiple of two numbers.|`lcm(95,135)` returns 2565.| +|`ln(n)`|Returns the natural logarithm of n.|`ln(5)` returns 1.6094379124341003.| +|`log(n)`|Returns the base 10 logarithm of n.|`log(5)` returns 0.6989700043360189.| +|`max(n1, n2)`|Returns the larger of two numbers.|`max(3,10)` returns 10.| +|`min(n1, n2)`|Returns the smaller of two numbers.|`min(3,10)` returns 3.| +|`mod(n1, n2)`|Returns n1 modulus n2. Note: `value.mod(9)` will work, whereas `74.mod(9)` will not work.|`mod(74, 9)` returns 2. | +|`multinomial(n1, n2 …(optional))`|Calculates the multinomial of one number or a series of numbers.|`multinomial(2,3)` returns 10.| +|`odd(n)`|Rounds the number up to the nearest odd integer.|`odd(10)` returns 11.| +|`pow(n1, n2)`|Returns n1 raised to the power of n2. Note: value.pow(3)` will work, whereas `2.pow(3)` will not work.|`pow(2, 3)` returns 8 (2 cubed) and `pow(3, 2)` returns 9 (3 squared). The square root of any numeric value can be called with `value.pow(0.5)`.| +|`quotient(n1, n2)`|Returns the integer portion of a division (truncated, not rounded), when supplied with a numerator and denominator.|`quotient(9,2)` returns 4.| +|`radians(n)`|Converts an angle in degrees to radians.|`radians(10)` returns 0.17453292519943295.| +|`randomNumber(n lowerBound, n upperBound)`|Returns a random integer in the interval between the lower and upper bounds (inclusively). Will output a different random number in each cell in a column.| +|`round(n)`|Rounds a number to the nearest integer.|`3.7.round()` returns 4 and `-3.7.round()` returns -4.| +|`sin(n)`|Returns the trigonometric sine of an angle.|`sin(10)` returns -0.5440211108893698.| +|`sinh(n)`|Returns the hyperbolic sine of an angle.|`sinh(10)` returns 11013.232874703393.| +|`sum(a)`|Sums the numbers in an array. Ignores non-number items. Returns 0 if the array does not contain numbers.|`sum([ 10, 2, three ])` returns 12.| +|`tan(n)`|Returns the trigonometric tangent of an angle.|`tan(10)` returns 0.6483608274590866.| +|`tanh(n)`|Returns the hyperbolic tangent of a value.|`tanh(10)` returns 0.9999999958776927.| + +## Other functions {#other-functions} + +###### type(o) {#typeo} +Returns a string with the data type of o, such as undefined, string, number, boolean, etc. For example, a [Transform](cellediting#transform) operation using `value.type()` will convert all cells in a column to strings of their data types. + +###### facetCount(choiceValue, s facetExpression, s columnName) {#facetcountchoicevalue-s-facetexpression-s-columnname} +Returns the facet count corresponding to the given choice value, by looking for the facetExpression in the choiceValue in columnName. For example, to create facet counts for the following table, we could generate a new column based on “Gift†and enter in `value.facetCount("value", "Gift")`. This would add the column we've named “Countâ€: + +| Gift | Recipient | Price | Count | +|-|-|-|-| +| lamp | Mary | 20 | 1 | +| clock | John | 57 | 2 | +| watch | Amit | 80 | 1 | +| clock | Claire | 62 | 2 | + +The facet expression, wrapped in quotes, can be useful to manipulate the inputted values before counting. For example, you could do a textual cleanup using fingerprint(): `(value.fingerprint()).facetCount(value.fingerprint(),"Gift")`. + +###### hasField(o, s name) {#hasfieldo-s-name} +Returns a boolean indicating whether o has a member field called [name](expressions#variables). For example, `cell.recon.hasField("match")` will return false if a reconciliation match hasn’t been selected yet, or true if it has. You cannot chain your desired fields: for example, `cell.hasField("recon.match")` will return false even if the above expression returns true). + +###### coalesce(o1, o2, o3, ...) {#coalesceo1-o2-o3-} +Returns the first non-null from a series of objects. For example, `coalesce(value, "")` would return an empty string Ҡif `value` was null, but otherwise return `value`. + +###### cross(cell, s projectName (optional), s columnName (optional)) {#crosscell-s-projectname-optional-s-columnname-optional} +Returns an array of zero or more rows in the project projectName for which the cells in their column columnName have the same content as the cell in your chosen column. For example, if two projects contained matching names, and you wanted to pull addresses for people by their names from a project called “People†you would apply the following expression to your column of names: +``` +cell.cross("People","Name").cells["Address"].value[0] +``` + +This would match your current column to the “Name†column in “People†and, using those matches, pull the respective “Address†value into your current project. + +You may need to do some data preparation with cross(), such as using trim() on your key columns or deduplicating values. + +The first argument will be interpreted as `cell.value` if set to `cell`. If you omit projectName and columnName, they will default to the current project and index column (number 0). + +Recipes and more examples for using cross() can be found [on our wiki](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#combining-datasets). diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/installing.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/installing.md new file mode 100644 index 000000000..bf280a3e3 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/installing.md @@ -0,0 +1,425 @@ +--- +id: installing +title: Installing OpenRefine +sidebar_label: Installing +--- + +## System requirements {#system-requirements} + +OpenRefine does not require internet access to run its basic functions. Once you download and install it, it runs as a small web server on your own computer, and you access that local web server by using your browser. It only requires an internet connection to import data from the web, reconcile data using a web service, or export data to the web. + +OpenRefine requires three things on your computer in order to function: + +#### Compatible operating system {#compatible-operating-system} + +OpenRefine is designed to work with **Windows**, **Mac**, and **Linux** operating systems. [Our team releases packages for each](https://openrefine.org/download.html). + +#### Java {#java} + +[Java](https://java.com/en/download/) must be installed and configured on your computer to run OpenRefine. The Mac version of OpenRefine includes Java; new in OpenRefine 3.4, there is also a Windows package with Java included. + +If you install and start OpenRefine on a Windows computer without Java, it will automatically open up a browser window to the [Java downloads page](https://java.com/en/download/), and you can simply follow the instructions there. + +We recommend you [download](https://java.com/en/download/) and install Java before proceeding with the OpenRefine installation. Please note that OpenRefine works with Java 8 to Java 17 for OpenRefine 3.5. + +#### Compatible browser {#compatible-browser} + +OpenRefine works best on browsers based on Webkit, such as: + +* Google Chrome +* Chromium +* Opera +* Microsoft Edge + +We are aware of some minor rendering and performance issues on other browsers such as Firefox. We don't support Internet Explorer. If you are having issues running OpenRefine, see the [section on Running](running.md#troubleshooting). + +### Release versions {#release-versions} + +OpenRefine always has a [latest stable release](https://github.com/OpenRefine/OpenRefine/releases/latest), as well as some more recent developments available in beta, release candidate, or [snapshot releases](https://github.com/OpenRefine/OpenRefine-snapshot-releases/releases). If you are installing for the first time, we recommend [the latest stable release](https://github.com/OpenRefine/OpenRefine/releases/latest). + +If you wish to use an extension that is only compatible with an earlier version of OpenRefine, and do not require the latest features, you may find that [an older stable version is best for you](https://github.com/OpenRefine/OpenRefine/releases) in our list of releases. Look at later releases to see which security vulnerabilities are being fixed, in order to assess your own risk tolerance for using earlier versions. Look for “final release†versions instead of “beta†or “release candidate†versions. + +#### Unstable versions {#unstable-versions} + +If you need a recently developed function, and are willing to risk some untested code, you can look at [the most recent items in the list](https://github.com/OpenRefine/OpenRefine/releases) and see what changes appeal to you. + +“Beta†and “release candidate†versions may both have unreported bugs and are most suitable for people who are willing to help us troubleshoot these versions by [creating bug reports](https://github.com/OpenRefine/OpenRefine/issues). + +For the absolute latest development updates, see the [snapshot releases](https://github.com/OpenRefine/OpenRefine-snapshot-releases/releases). These are created with every commit. + +#### What’s changed {#whats-changed} + +Our [latest version is OpenRefine 3.5.0](https://github.com/OpenRefine/OpenRefine/releases/tag/3.5.0), released November 7th 2021. The major changes in this version are listed on the [3.5.0 release page](https://github.com/OpenRefine/OpenRefine/releases/tag/3.5.0) with the downloadable packages. + +You can find information about all OpenRefine versions on the [Releases page on Github](https://github.com/OpenRefine/OpenRefine/releases). + +:::info Other distributions +OpenRefine may also work in other environments, such as [Chromebooks](https://gist.github.com/organisciak/3e12e5138e44a2fed75240f4a4985b4f) where Linux terminals are available. Look at our list of [Other Distributions on the Downloads page](https://openrefine.org/download.html) for other ways of running OpenRefine, and refer to our contributor community to see new environments in development. +::: + +## Installing or upgrading {#installing-or-upgrading} +### Back up your data {#back-up-your-data} + +If you are upgrading from an older version of OpenRefine and have projects already on your computer, you should create backups of those projects before you install a new version. + +First, [locate your workspace directory](#where-is-data-stored). Then copy everything you find there and paste it into a folder elsewhere on your computer. + +For extra security you can [export your existing OpenRefine projects](exporting#export-a-project). + +:::caution +Take note of the [extensions](#installing-extensions) you have currently installed. They may not be compatible with the upgraded version of OpenRefine. Installations can be installed in two places, so be sure to check both your workspace directory and the existing installation directory. +::: + +### Install or upgrade OpenRefine {#install-or-upgrade-openrefine} + +If you are upgrading an existing OpenRefine installation, you can delete the old program files and install the new files into the same space. Do not overwrite the files as some obsolete files may be left over unnecessarily. + +:::caution +If you have extensions installed, do not delete the `webapp\extensions` folder where you installed them. You may wish to install extensions into the workspace directory instead of the program directory. There is no guarantee that extensions will be forward-compatible with new versions of OpenRefine, and we do not maintain extensions. +::: + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + + +Once you have downloaded the `.zip` file, extract it into a folder where you wish to store program files (such as `D:\Program Files\OpenRefine`). + +You can right-click on `openrefine.exe` or `refine.bat` and pin one of those programs to your Start Menu or create shortcuts for easier access. + + + + + +Once you have downloaded the `.dmg` file, open it and drag the OpenRefine icon onto the Applications folder icon (just like you would normally install Mac applications). + + + + + +The quick version: + +1. Install [Homebrew](http://brew.sh) +2. In Terminal enter ` brew cask install openrefine` +1. Then find OpenRefine in your Applications folder. + +The long version: + +[Homebrew](http://brew.sh) is a popular command-line package manager for Mac. Installing Homebrew is accomplished by pasting the installation command on the Homebrew website into a Terminal window. Once Homebrew is installed, applications like OpenRefine can be installed via a simple command. You can [install Homebrew from their website](http://brew.sh). + +###### Install {#install} + +Install OpenRefine with this command: + +``` +brew cask install openrefine +``` + +You should see output like this: + +``` +==> Downloading https://github.com/OpenRefine/OpenRefine/releases/download/2.7/openrefine-mac-2.7.dmg +########################### 100.0% + ==> Verifying checksum for Cask openrefine + ==> Installing Cask openrefine + ==> Moving App 'OpenRefine.app' to '/Applications/OpenRefine.app'. + 🺠openrefine was successfully installed! +``` + +Behind the scenes, this command causes Homebrew to download the OpenRefine installer, verify the file’s authenticity (using a SHA-256 checksum), mount the disk image, copy the `OpenRefine.app` application bundle into the Applications folder, unmount the disk image, and save a copy of the installer and metadata about the installation for future use. + +If an existing `OpenRefine.app` is found in the Applications folder, Homebrew will not overwrite it, so installing via Homebrew requires either deleting or renaming previously installed copies. + +###### Uninstall {#uninstall} + +To uninstall OpenRefine, paste this command into the Terminal: + +``` + brew cask uninstall openrefine +``` + +You should see output like this: + +``` + ==> Removing App '/Applications/OpenRefine.app'. +``` + +###### Update {#update} + +To update to the latest version of OpenRefine, paste this command into the Terminal: + +``` + brew cask reinstall openrefine +``` + +You should see output like this: + +``` + ==> Downloading https://github.com/OpenRefine/OpenRefine/releases/download/2.7/openrefine-mac-2.7.dmg +########################### 100.0% + ==> Verifying checksum for Cask openrefine + ==> Removing App '/Applications/OpenRefine.app'. + ==> Moving App 'OpenRefine.app' to '/Applications/OpenRefine.app'. + 🺠openrefine was successfully installed! +``` + +If you had previously installed the `openrefine-dev` cask (containing a release candidate) and you want to move to the stable release, you need to first uninstall the old cask and then install the new one: + +``` + brew cask uninstall openrefine-dev + brew cask install openrefine +``` + + + + +Once you have downloaded the `.tar.gz` file, open a shell, navigate to the folder containing the download, and type: + +``` +tar xzf openrefine-linux-3.5.0.tar.gz +``` + + + + + +--- + + +### Set where data is stored {#set-where-data-is-stored} + +OpenRefine stores data in two places: program files in the program directory, wherever it is you’ve installed it; and project files in what we call the “workspace directory.†You can access this folder easily from OpenRefine by going to the [home screen](running#the-home-screen) (at [http://127.0.0.1:3333/](http://127.0.0.1:3333/)) and clicking Browse workspace directory. + +By default this is: + + + + + +Depending on your version of Windows, the data is in one of these directories: +* `%appdata%\OpenRefine` +* `%localappdata%\OpenRefine` +* `C:\Documents and Settings\(user id)\Local Settings\Application Data\OpenRefine` +* `C:\Users\(user id)\AppData\Roaming\OpenRefine` +* `C:\Users\(user id)\AppData\Local\OpenRefine` +* `C:\Users\(user id)\OpenRefine` + +For older Google Refine releases, replace `OpenRefine` with `Google\Refine`. + +You can change this by adding this line to the file `openrefine.l4j.ini` and specifying your desired drive and folder path: + +``` +-Drefine.data_dir=D:\MyDesiredFolder +``` + +If your folder path has spaces, use neutral quotation marks around it: + +``` +-Drefine.data_dir="D:\My Desired Folder" +``` + +If the folder does not exist, OpenRefine will create it. + + + + + +``` +~/Library/Application Support/OpenRefine/ +``` + +For older versions, as Google Refine: + +``` +~/Library/Application Support/Google/Refine/ +``` + +Logging is to `/var/log/daemon.log` - grep for `com.google.refine.Refine`. + + + + + +``` +~/.local/share/openrefine/ +``` + +You can change this when you run OpenRefine from the terminal, by pointing to the workspace directory through the `-d` parameter: + +``` + ./refine -p 3333 -i 0.0.0.0 -m 6000M -d /My/Desired/Folder +``` + + + + + +--- + + +### Logs {#logs} + +OpenRefine does not currently output an error log, but because the OpenRefine console window is always open (on Linux and Windows) while OpenRefine runs in your browser, you can copy information from the console if an error occurs. + +Using a Mac, you can [run OpenRefine using the terminal](running#starting-and-exiting) in order to capture errors. + +--- + +## Increasing memory allocation {#increasing-memory-allocation} + +OpenRefine relies on having computer memory available to it to work effectively. If you are planning to work with large datasets, you may wish to set up OpenRefine to handle it at the outset. By “large†we generally mean one of the following indicators: +* more than one million total cells +* an input file size of more than 50 megabytes (MB) +* more than 50 [rows per record in records mode](running#records-mode) + +By default OpenRefine is set to operate with 1 gigabyte (GB) of memory (1024MB). If you feel that OpenRefine is running slowly, or you are getting “out of memory†errors (for example, `java.lang.OutOfMemoryError`), you can try allocating more memory. + +A good practice is to start with no more than 50% of whatever memory is left over after the estimated usage of your operating system, to leave memory for your browser to run. + +All of the settings below use a four-digit number to specify the megabytes (MB) used (actually [mebibytes](https://en.wikipedia.org/wiki/Mebibyte)). The default is usually 1024MB, but the new value doesn't need to be a multiple of 1024. + +:::info Dealing with large datasets +If your project is big enough to need more than the default amount of memory, consider turning off Parse cell text into numbers, dates, ... on import. It's convenient, but less efficient than explicitly converting any columns that you need as a data type other than the default “string†type. +::: + + + + + +#### Using openrefine.exe {#using-openrefineexe} + +If you run `openrefine.exe`, you will need to edit the `openrefine.l4j.ini` file found in the program directory and edit the line + +``` +# max memory memory heap size +-Xmx1024M +``` + +The line “-Xmx1024M†defines the amount of memory available in megabytes. Change the number “1024†- for example, edit the line to “-Xmx2048M†to make 2048MB [2GB] of memory available. + +:::caution openrefine.exe not running? +Once you increase the memory allocation, you may find that you cannot run `openrefine.exe`. In this case, your computer needs a 64-bit version of [Java](https://www.java.com/en/download/help/index_installing.xml) (this is different from [Java JDK](#install-or-upgrade-java). Look for the “Windows Offline (64-bit)†download on the Downloads page and install that. Your system must also be set to use the 64-bit version of Java by [changing the Java configuration](https://www.java.com/en/download/help/update_runtime_settings.xml). +::: + +#### Using refine.bat {#using-refinebat} + +On Windows, OpenRefine can also be run by using the file `refine.bat` in the program directory. If you start OpenRefine using `refine.bat`, the memory available to OpenRefine can be specified either through command line options, or through the `refine.ini` file. + +To set the maximum amount of memory on the command line when using `refine.bat`, `cd` to the program directory, then type + +```refine.bat /m 2048m``` + +where “2048†is the maximum amount of MB that you want OpenRefine to use. + +To change the default that `refine.bat` uses, edit the `refine.ini` line that reads + +```REFINE_MEMORY=1024M``` + +Note that this file is only read if you use `refine.bat`, not `openrefine.exe`. + + + + +If you have downloaded the `.dmg` package and you start OpenRefine by double-clicking on it: + +* close OpenRefine +* control-click on the OpenRefine icon (opens the contextual menu) +* click on "show package content†(a finder window opens) +* open the “Contents†folder +* open the `Info.plist` file with any text editor (like Mac's default TextEdit) +* Change “-Xmx1024M†into, for example, “-Xmx2048M†or “-Xmx8G†+* save the file +* restart OpenRefine. + + + + +If you have downloaded the `.tar.gz` package and you start OpenRefine from the command line, add the “-m xxxxM†parameter like this: +`./refine -m 2048m` + +#### Setting a default {#setting-a-default} + +If you don't want to set this option on the command line each time, you can also set it in the `refine.ini` file. Edit the line + +``` +REFINE_MEMORY=1024M +``` + +Make sure it is not commented out (that is, that the line doesn't start with a “#†character), and change “1024†to a higher value. Save the file, and when you next start OpenRefine it will use this value. + + + + + +--- + + +## Installing extensions {#installing-extensions} + +Extensions have been created by our contributor community to add functionality or provide convenient shortcuts for common uses of OpenRefine. [We list extensions we know about on our downloads page](https://openrefine.org/download.html). + +:::info Contributing extensions +If you’d like to create or modify an extension, [see our developer documentation here](https://github.com/OpenRefine/OpenRefine/wiki/Documentation-For-Developers). If you’re having a problem, [use our downloads page](https://openrefine.org/download.html) to go to the extension’s page and report the issue there. +::: + +### Two ways to install extensions {#two-ways-to-install-extensions} + +You can [install extensions in one of two places](#set-where-data-is-stored): + +* Into your OpenRefine program folder, so they will only be available to that version/installation of OpenRefine (meaning the extension will not run if you upgrade OpenRefine), or +* Into your workspace, where your projects are stored, so they will be available no matter which version of OpenRefine you’re using. + +We provide these options because you may wish to reinstall a given extension manually each time you upgrade OpenRefine, in order to be sure it works properly. + +### Find the right place to install {#find-the-right-place-to-install} + +If you want to install the extension into the program folder, go to your program directory and then go to `webapp\extensions` (or create it if not does not exist). + +If you want to install the extension into your workspace, you can: +* launch OpenRefine and click Open Project in the sidebar +* At the bottom of the screen, click Browse workspace directory +* A file-explorer or finder window will open in your workspace +* Create a new folder called “extensions†inside the workspace if it does not exist. + +You can also [find your workspace on each operating system using these instructions](#set-where-data-is-stored). + +### Install the extension {#install-the-extension} + +Some extensions have their own instructions: make sure you read the documentation before you begin installing. + +Some extensions may have multiple versions, to match OpenRefine versions, so be sure to choose the right release for your installation. If you have questions about compatibility or want to request or voice your support for an update, [use our downloads page](https://openrefine.org/download.html) to go to the extension’s page and report the issue there. + +Generally, the installation process will be: + +* Download the extension (usually as a zip file from GitHub) +* Extract the zip contents into the “extensions†directory, making sure all the contents go into one folder with the name of the extension +* Start (or restart) OpenRefine. + +To confirm that installation was a success, follow the instructions provided by the extension. Each extension will appear in its own way inside the OpenRefine interface. Make sure you read its documentation to know where the functionality will appear, such as under specific dropdown menus. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/jythonclojure.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/jythonclojure.md new file mode 100644 index 000000000..a93d18155 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/jythonclojure.md @@ -0,0 +1,76 @@ +--- +id: jythonclojure +title: Jython & Clojure +sidebar_label: Jython & Clojure +--- + +## Jython {#jython} + +Jython 2.7.2 comes bundled with the default installation of OpenRefine 3.4.1. You can add libraries and code by following [this tutorial](https://github.com/OpenRefine/OpenRefine/wiki/Extending-Jython-with-pypi-modules). A large number of Python files (`.py` or `.pyc`) are compatible. + +Python code that depends on C bindings will not work in OpenRefine, which uses Java / Jython only. Since Jython is essentially Java, you can also import Java libraries and utilize those. + +You will need to restart OpenRefine, so that new Jython or Python libraries are initialized during startup. + +OpenRefine now has [most of the Jsoup.org library built into GREL functions](grelfunctions#jsoup-xml-and-html-parsing-functions) for parsing and working with HTML and XML elements. + +### Syntax {#syntax} + +Expressions in Jython must have a `return` statement: + +``` + return value[1:-1] +``` + +``` + return rowIndex%2 +``` + +Fields have to be accessed using the bracket operator rather than dot notation: + +``` + return cells["col1"]["value"] +``` + +For example, to access the [edit distance](reconciling#reconciliation-facets) between a reconciled value and an original cell value using [recon variables](#reconciliation): + +``` + return cell["recon"]["features"]["nameLevenshtein"] +``` + +To return the lower case of `value` (if the value is not null): + +``` + if value is not None: + return value.lower() + else: + return None +``` + +### Tutorials {#tutorials} +- [Extending Jython with pypi modules](https://github.com/OpenRefine/OpenRefine/wiki/Extending-Jython-with-pypi-modules) +- [Working with phone numbers using Java libraries inside Python](https://github.com/OpenRefine/OpenRefine/wiki/Jython#tutorial---working-with-phone-numbers-using-java-libraries-inside-python) + +Full documentation on the Jython language can be found on its official site: [http://www.jython.org](http://www.jython.org). + +## Clojure {#clojure} + +Clojure 1.10.1 comes bundled with the default installation of OpenRefine 3.4.1. At this time, not all [variables](expressions#variables) can be used with Clojure expressions: only `value`, `row`, `rowIndex`, `cell`, and `cells` are available. + +For example, functions can take the form +``` +(.. value (toUpperCase) ) +``` + +Or can look like +``` +(-> value (str/split #" ") last ) +``` + +which functions like `value.split(" ")` in GREL. + +For help with syntax, see the [Clojure website's guide to syntax](https://clojure.org/guides/learn/syntax). + +User-contributed Clojure recipes can be found on our wiki at [https://github.com/OpenRefine/OpenRefine/wiki/Recipes#11-clojure](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#11-clojure). + +Full documentation on the Clojure language can be found on its official site: [https://clojure.org/](https://clojure.org/). \ No newline at end of file diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/reconciling.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/reconciling.md new file mode 100644 index 000000000..0d14e80ad --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/reconciling.md @@ -0,0 +1,242 @@ +--- +id: reconciling +title: Reconciling +sidebar_label: Reconciling +--- + +## Overview {#overview} + +Reconciliation is the process of matching your dataset with that of an external source. Datasets for comparison might be produced by libraries, archives, museums, academic organizations, scientific institutions, non-profits, or interest groups. You can also reconcile against user-edited data on [Wikidata or other Wikibase instances](wikibase/reconciling), or reconcile against [a local dataset that you yourself supply](https://github.com/OpenRefine/OpenRefine/wiki/Reconcilable-Data-Sources#local-services). + +To reconcile your OpenRefine project against an external dataset, that dataset must offer a web service that conforms to the [Reconciliation Service API standards](https://reconciliation-api.github.io/specs/0.1/). + +You may wish to reconcile in order to: +* fix spelling or variations in proper names +* clean up manually-entered subject headings against authorities such as the [Library of Congress Subject Headings](https://id.loc.gov/authorities/subjects.html) (LCSH) +* link your data to an existing dataset +* add to an editable platform such as [Wikidata](https://www.wikidata.org) +* or see whether entities in your project appear in some specific list, such as the [Panama Papers](https://aleph.occrp.org/datasets/734). + +Reconciliation is semi-automated: OpenRefine matches your cell values to the reconciliation information as best it can, but human judgment is required to review and approve the results. Reconciling happens by default through string searching, so typos, whitespace, and extraneous characters will have an effect on the results. You may wish to [clean and cluster](cellediting) your data before reconciliaton. + +:::info Working iteratively +We recommend planning your reconciliation operations as iterative: reconcile multiple times with different settings, and with different subgroups of your data. +::: + +## Sources {#sources} + +Start with [this current list of reconcilable authorities](https://reconciliation-api.github.io/testbench/), which includes instructions for adding new services via Wikidata editing if you have one to add. + +OpenRefine maintains a [further list of sources on the wiki](https://github.com/OpenRefine/OpenRefine/wiki/Reconcilable-Data-Sources), which can be edited by anyone. This list includes ways that you can reconcile against a [local dataset](https://github.com/OpenRefine/OpenRefine/wiki/Reconcilable-Data-Sources#local-services). + +Other services may exist that are not yet listed in these two places: for example, the [310 datasets hosted by the Organized Crime and Corruption Reporting Project (OCCRP)](https://aleph.occrp.org/datasets/) each have their own reconciliation URL, or you can reconcile against their entire database with the URL [shared on the reconciliation API list](https://reconciliation-api.github.io/testbench/). For another example, you can reconcile against the entire Virtual International Authority File (VIAF) dataset, or [only the contributions from certain institutions](http://refine.codefork.com/). Search online to see if the authority you wish to reconcile against has an available service, or whether you can download a copy to reconcile against locally. + +OpenRefine includes Wikidata reconciliation in the installation package - see the [Wikibase](wikibase/reconciling) page for more information particular to that service. Extensions can add reconciliation services, and can also add enhanced reconciliation capacities. Check the list of extensions on the [Downloads page](https://openrefine.org/download.html) for more information. + +Each source will have its own documentation on how it provides reconciliation. The table on [the reconciliation API list](https://reconciliation-api.github.io/testbench/) indicates whether your chosen service supports the features described below. Refer to the service's documentation if you have questions about its behaviors and which OpenRefine features it supports. + +In addition to the reconciliation services mentioned above, you may also choose to build your own service. You can either start from scratch using the [API specification](https://reconciliation-api.github.io/specs/latest/) or use one of the frameworks mentioned in the [Reconciliation census](https://reconciliation-api.github.io/census/services/). + +Of particular note is [reconcile-csv](http://okfnlabs.org/reconcile-csv/) which allows you to build a reconciliation service from a simple CSV file. Thus if you wanted to reconcile one OpenRefine project against another, you'd simply need to export the target project as a CSV, point `reconcile-csv` at it and you're good to go. A somewhat newer port of this project written in Python can be found at [csv-reconcile](https://github.com/gitonthescene/csv-reconcile) which is more configurable and defaults to parsing tab separated files for convenience. + +Similiarly, you may choose to export some SPARQL output to a TSV to limit the scope of values you're reconciling against and/or for better peformance. + +## Getting started {#getting-started} + +Choose a column to reconcile and use its dropdown menu to select Reconcile → Start reconciling. If you want to reconcile only some cells in that column, first use filters and facets to isolate them. + +In the reconciliation window, you will see Wikidata offered as a default service. To add another service, click Add Standard Service... and paste in the URL of a [service](#sources). You should see the name of the service appear in the list of Services if the URL is correct. + +![The reconciliation window.](/img/reconcilewindow.png) + +Once you select a service, your selected column may be sampled in order to suggest [“types†(categories)](#reconciling-by-type) to reconcile against. Other services will suggest their available types without sampling, and some services have no types. + +For example, if you had a list of artists represented in a gallery collection, you could reconcile their names against the Getty Research Institute’s [Union List of Artist Names (ULAN)](https://www.getty.edu/research/tools/vocabularies/ulan/). The same [Getty reconciliation URL](https://services.getty.edu/vocab/reconcile/) will offer you ULAN, AAT (Art and Architecture Thesaurus), and TGN (Thesaurus of Geographic Names). + +![The reconciliation window with types.](/img/reconcilewindow2.png) + +Refer to the [documentation specific to the reconciliation service](https://reconciliation-api.github.io/testbench/) to learn whether types are offered, which types are offered, and which one is most appropriate for your column. You may wish to facet your data and reconcile batches against different types if available. + +Reconciliation can be a time-consuming process, especially with large datasets. We suggest starting with a small test batch. There is no throttle (delay between requests) to set for the reconciliation process. The amount of time will vary for each service, and vary based on the options you select during the process. + +When the process is done, you will see the reconciliation data in the cells. +If the cell was successfully matched, it displays text as a single dark blue link. In this case, the reconciliation is confident that the match is correct, and you should not have to check it manually. +If there is no clear match, one or more candidates are displayed, together with their reconciliation score, with the text in light blue links. You will need to select the correct one. + +For each matching decision you make, you have two options: match this cell only (one checkmark), or also use the same identifier for all other cells containing the same original string (two checkmarks). + +For services that offer the [“preview entities†feature](https://reconciliation-api.github.io/testbench/), you can hover your mouse over the suggestions to see more information about the candidates or matches. Each participating service (and each type) will deliver different structured data that may help you compare the candidates. + +For example, the Getty ULAN shows an artist’s discipline, nationality, and birth and death years: + +![Hovering over matches.](/img/reconcilehover.png) + +Hovering over the suggestion will also offer the two matching options as buttons. + +For matched values (those appearing as dark blue links), the underlying cell value has not been altered - the cell is storing both the original string and the matched entity link at the same time. If you were to copy your column to a new column at this point using `value`, for example, the reconcilation data would not transfer - only the original strings. You can learn more about how OpenRefine stores different pieces of information in each cell in [the Variables section specific to reconciliation data](expressions#reconciliation). + +For each cell, you can manually “Create new item,†which will take the cell’s original value and apply it, as though it is a match. This will not become a dark blue link, because at this time there is nothing to link to: it is a draft entity stored only in your project. You can use this feature to prepare these entries for eventual upload to an editable service such as [Wikibase](wikibase/overview), but most services do not yet support this feature. + +### Reconciliation facets {#reconciliation-facets} + +Under Reconcile → Facets there are a number of reconciliation-specific faceting options. OpenRefine automatically creates two facets when you reconcile some cells. + +One is a numeric facet for “best candidate's score,†the range of reconciliation scores of only the best candidate of each cell. Higher scores mean better matches, although each service calculates scores differently and has a different range. You can facet for higher scores using the numeric facet, and then approve them all in bulk, by using Reconcile → [Actions](#reconciliation-actions) → Match each cell to its best candidate. + +There is also a “judgment†facet created, which lets you filter for the cells that haven't been matched (pick “none†in the facet). As you process each cell, its judgment changes from “none†to “matched†and it disappears from the view. + +You can add other facets by selecting Reconcile → Facets on your reconciled column. You can facet by: + +* your judgments (“matched,†or “none†for unreconciled cells, or “new†for entities you've created) +* the action you’ve performed on that cell (chosen a “single†match, or set a “mass†match, or no action, which appears as “unknownâ€) +* the timestamps on the edits you’ve made so far (these appear as millisecond counts since an arbitrary point: they can be sorted alphabetically to move forward and back in time). + +You can facet only the best candidates for each cell, based on: +* the score (calculated based on each service's own methods) +* the edit distance (using the [Levenshtein distance](cellediting#nearest-neighbor), a number based on how many single-character edits would be required to get your original value to the candidate value, with a larger value being a greater difference) +* the word similarity. + +Word similarity is calculated as a percentage based on how many words (excluding [stop words](https://en.wikipedia.org/wiki/Stop_word)) in the original value match words in the candidate. For example, the value “Maria Luisa Zuloaga de Tovar†matched to the candidate “Palacios, Luisa Zuloaga de†results in a word similarity value of 0.6, or 60%, or 3 out of 5 words. Cells that are not yet matched to one candidate will show as 0.0). + +You can also look at each best candidate’s: +* type (the ones you have selected in successive reconciliation attempts, or other types returned by the service based on the cell values) +* type match (“true†if you selected a type and it succeeded, “false†if you reconciled against no particular type, and “(no type)†if it didn’t reconcile) +* name match (“true†if you’ve matched, “false†if you haven’t yet chosen from the candidates, or “(unreconciled)†if it didn’t reconcile). + +These facets are useful for doing successive reconciliation attempts, against different types, and with different supplementary information. The information represented by these facets are held in the cells themselves and can be called using the [reconciliation variables](expressions#reconciliation) available in expressions. + +### Reconciliation actions {#reconciliation-actions} + +You can use the Reconcile → Actions menu options to perform bulk changes (which will apply only to your currently viewed set of rows or records): +* Match each cell to its best candidate (by highest score) +* Create a new item for each cell (discard any suggested matches) +* Create one new item for similar cells (a new entity will be created for each unique string) +* Match all filtered cells to... (a specific item from the chosen service, via a search box; only works with services that support the “suggest entities†property) +* Discard all reconciliation judgments (reverts back to multiple candidates per cell, including cells that may have been auto-matched in the original reconciliation process) +* Clear reconciliation data, reverting all cells back to their original values. + +The other options available under Reconcile are: +* Copy reconciliation data... (to an existing column: if the original values in your reconciliation column are identical to those in your chosen column, the matched and new cells will copy over; unmatched values will not change) +* [Use values as identifiers](#reconciling-with-unique-identifiers) (if you are reconciling with unique identifiers instead of by doing string searches) +* [Add entity identifiers column](#add-entity-identifiers-column). + +## Reconciling with unique identifiers {#reconciling-with-unique-identifiers} + +Reconciliation services use unique identifiers for their entities. For example, the 14th Dalai Lama has the VIAF ID [38242123](https://viaf.org/viaf/38242123/) and the Wikidata ID [Q17293](https://www.wikidata.org/wiki/Q37349). You can supply these identifiers directly to your chosen reconciliation service in order to pull more data, but these strings will not be “reconciled†against the external dataset. + +Select the column with unique identifiers and apply the operation Reconcile → Use values as identifiers. This will bring up the list of reconciliation services you have already added (to add a new service, open the Start reconciling... window first). If you use this operation on a column of IDs, you will not have access to the usual reconciliation settings. + +Matching identifiers does not validate them. All cells will appear as dark blue “confirmed†matches. You should check before this operation that the identifiers in the column exist on the target service. + +You may get false positives, which you will need to hover over or click on to identify: + +![Hovering over an error.](/img/reconcileIDerror.png) + +## Reconciling by type {#reconciling-by-type} + +Reconciliation services, once added to OpenRefine, may suggest types from their databases. These types will usually be whatever the service specializes in: people, events, places, buildings, tools, plants, animals, organizations, etc. + +Reconciling against a type may be faster and more accurate, but may result in fewer matches. Some services have hierarchical types (such as “mammal†as a subtype of “animalâ€). When you reconcile against a more specific type, unmatched values may fall back to the broader type; other services will not do this, so you may need to perform successive reconciliation attempts against different types. Refer to the documentation specific to the reconciliation service to learn more. + +When you select a service from the list, OpenRefine will load some or all available types. Some services will sample the first ten rows of your column to suggest types (check the [“Suggest types†column](https://reconciliation-api.github.io/testbench/)). You will see a service’s types in the reconciliation window: + +![Reconciling using a type.](/img/reconcile-by-type.png) + +In this example, “Person†and “Corporate Name†are potential types offered by the reconciliation API for VIAF. You can also use the Reconcile against type: field to enter in another type that the service offers. When you start typing, this field may search and suggest existing types. For VIAF, you could enter “/book/book†if your column contained publications. You may need to enter the service's own strings precisely instead of attempting to search for a match. + +Types are structured to fit their content: the Wikidata “human†type, for example, can include fields for birth and death dates, nationality, etc. The VIAF “person†type can include nationality and gender. You can use this to [include more properties](#reconciling-with-additional-columns) and find better matches. + +If your column doesn’t fit one specific type offered, you can Reconcile against no particular type. This may take longer. + +We recommend working in batches and reconciling against different types, moving from specific to broad. You can create a facet for Best candidate’s types facet to see which types are being represented. Some candidates may return more than one type, depending on the service. Types may appear in facets by their unique IDs, rather than by their semantic labels (for example, Q5 for “human†in Wikidata). + +## Reconciling with additional columns {#reconciling-with-additional-columns} + +Some of your cells may be ambiguous, in the sense that a string can point to more than one entity: there are dozens of places called “Paris†and many characters, people, and pieces of culture, too. Selecting non-geographic or more localized types can help narrow that down, but if your chosen service doesn't provide a useful type, you can include more properties that make it clear whether you're looking for Paris, France. + +![Reconciling sometimes turns up ambiguous matches.](/img/reconcileParis.gif) + +Including supplementary information can be useful, depending on the service (such as including birthdate information about each person you are trying to reconcile). You can re-reconcile unmatched cells with additional properties, in the right side of the Start reconciling window, under “Also use relevant details from other columns.†The column names in your project will appear in the reconciliation window, with an Include? checkbox next to each one. + +Fill in the As Property field with the type of information you are including. When you start typing, potential fields may pop up (depending on the [“suggest properties†feature](https://reconciliation-api.github.io/testbench/)), such as “birthDate†in the case of ULAN or “Geburtsdatum†in the case of Integrated Authority File (GND). Use the documentation for your chosen service to identify the fields in their terms. + +Some services will not be able to search for the exact name of your desired As Property entry, but you can still manually supply the field name. Refer to the service to choose the most appropriate field, and make sure you enter it correctly. + +![Including a birth-date type.](/img/reconcile-with-property.png) + +## Fetching more data {#fetching-more-data} + +One reason to reconcile to some external service is that it allows you to pull data from that service into your OpenRefine project. There are three ways to do this: + +* Add identifiers for your values +* Add columns from reconciled values +* Add column by fetching URLs. + +### Add entity identifiers column {#add-entity-identifiers-column} + +Once you have selected matches for your cells, you can retrieve the unique identifiers for those cells and create a new column for these, with Reconcile → Add entity identifiers column. You will be asked to supply a column name. New items and other unmatched cells will generate null values in this column. + +### Add columns from reconciled values {#add-columns-from-reconciled-values} + +If the reconciliation service supports [data extension](https://reconciliation-api.github.io/testbench/), then you can augment your reconciled data with new columns using Edit column → Add columns from reconciled values.... + +For example, if you have a column of chemical elements identified by name, you can fetch categorical information about them such as their atomic number and their element symbol: + +![A screenshare of elements fetching related information.](/img/reconcileelements.gif) + +Once you have chosen reconciliation matches for your cells, selecting Add column from reconciled values... will bring up a window to choose which related information you’d like to import into new columns. You can manually enter desired properties, or select from a list of suggestions. + +The quality of the suggested properties will depend on how you have reconciled your data beforehand: reconciling against a specific type will provide you with the associated properties of that type. For example, GND suggests elements about the “people†type after you've reconciled with it, such as their parents, native languages, children, etc. + +![A screenshot of available properties from GND.](/img/reconcileGND.png) + +If you have left any values unreconciled in your column, you will see “<not reconciled>†in the preview. These will generate blank cells if you continue with the column addition process. + +This process may pull more than one property per row in your data (such as multiple occupations), so you may need to switch into records mode after you've added columns. + +### Add columns by fetching URLs {#add-columns-by-fetching-urls} + +If the reconciliation service cannot extend data, look for a generic web API for that data source, or a structured URL that points to their dataset entities via unique IDs (such as “https://viaf.org/viaf/000000â€). You can use the Edit column → [Add column by fetching URLs](columnediting#add-column-by-fetching-urls) operation to call this API or URL with the IDs obtained from the reconciliation process. This will require using [expressions](expressions). + +You may not want to pull the entire HTML content of the pages at the ends of these URLs, so look to see whether the service offers a metadata endpoint, such as JSON-formatted data. You can either use a column of IDs, or you can pull the ID from each matched cell during the fetching process. + +For example, if you have reconciled artists to the Getty's ULAN, and [have their unique ULAN IDs as a column](#add-entity-identifiers-column), you can generate a new column of JSON-formatted data by using Add column by fetching URLs and entering the GREL expression `"http://vocab.getty.edu/" + value + ".json"`. For this service, the unique IDs are formatted “ulan/000000†and so the generated URLs look like “http://vocab.getty.edu/ulan/000000.jsonâ€. + +Alternatively, you can insert the ID directly from the matched column's reconciliation variables, using a GREL expression like `“http://vocab.getty.edu/†+ cell.recon.match.id + “.jsonâ€` instead. + +Remember to set an appropriate throttle and to refer to the service documentation to ensure your compliance with their terms. See [the section about this operation](columnediting#add-column-by-fetching-urls) to learn more about the fetching process. + +## Keep all the suggestions made {#keep-all-the-suggestions-made} + +To generate a list of each suggestion made, rather than only the best candidate, you can use a [GREL expression](expressions#GREL). Go to Edit column → Add column based on this column. To create a list of all the possible matches, use something like + +``` +forEach(cell.recon.candidates,c,c.name).join(", ") +``` + +To get the unique identifiers of these matches instead, use + +``` +forEach(cell.recon.candidates,c,c.id).join(", ") +``` + +This information is stored as a string, without any attached reconciliation information. + +## Writing reconciliation expressions {#writing-reconciliation-expressions} + +OpenRefine supplies a number of variables related specifically to reconciled values. These can be used in GREL and Jython expressions. For example, some of the reconciliation variables are: + +* `cell.recon.match.id` or `cell.recon.match.name` for matched values +* `cell.recon.best.name` or `cell.recon.best.id` for best-candidate values +* `cell.recon.candidates` for all listed candidates of each cell +* `cell.recon.judgment` (the values used in the “judgment†facet) +* `cell.recon.judgmentHistory` (the values used in the “judgment action timestamp†facet) +* `cell.recon.matched` (a “true†or “false†value) + +You can find out more in the [reconciliaton variables](expressions#reconciliaton-variables) section. + +## Exporting reconciled data {#exporting-reconciled-data} + +Once you have data that is reconciled to existing entities online, you may wish to export that data to a user-editable service such as Wikidata. See the section on [uploading your edits to Wikidata or other Wikibase instances](wikibase/uploading) for more information, or the section on [exporting](exporting) to see other formats OpenRefine can produce. + +You can share reconciled data in progress through a [project export or import](exporting#export-a-project), with some preparation. The importing user needs to have the appropriate reconciliation services installed on their OpenRefine instance (by going to Start reconciling and clicking on Add Standard Service...) in advance of opening the project, in order to use candidate and match links. Otherwise, the links will be broken and the user will need to add the reconciliation service and re-reconcile the columns in question. [Wikidata](wikibase/reconciling) reconciliation data can be shared more easily as the service comes bundled with OpenRefine. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/running.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/running.md new file mode 100644 index 000000000..e23317562 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/running.md @@ -0,0 +1,509 @@ +--- +id: running +title: Running OpenRefine +sidebar_label: Running +--- + +## Starting and exiting {#starting-and-exiting} + +OpenRefine does not require internet access to run its basic functions. Once you download and install it, it runs as a small web server on your own computer, and you access that local web server by using your browser. + +You will see a command line window open when you run OpenRefine. Ignore that window while you work on datasets in your browser. + +No matter how you start OpenRefine, it will load its interface in your computer’s default browser. If you would like to use another browser instead, start OpenRefine and then point your chosen browser at the home screen: [http://127.0.0.1:3333/](http://127.0.0.1:3333/). + +OpenRefine works best on browsers based on Webkit, such as: +* Google Chrome +* Chromium +* Opera +* Microsoft Edge + +We are aware of some minor rendering and performance issues on other browsers such as Firefox. We don't support Internet Explorer. + +You can view and work on multiple projects at the same time by simply having multiple tabs or browser windows open. From the Open Project screen, you can right-click on project names and open them in new tabs or windows. + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + + +#### With openrefine.exe {#with-openrefineexe} +You can run OpenRefine by double-clicking `openrefine.exe` or calling it from the command line. + +If you want to [modify the way `openrefine.exe` opens](#starting-with-modifications), you can edit the `openrefine.l4j.ini` file. + +#### With refine.bat {#with-refinebat} +On Windows, OpenRefine can also be run by using the file `refine.bat` in the program directory. If you start OpenRefine using `refine.bat`, you can do so by opening the file itself, or by calling it from the command line. + +If you call `refine.bat` from the command line, you can [start OpenRefine with modifications](#starting-with-modifications). +If you want to modify the way `refine.bat` opens through double-clicking or using a shortcut, you can edit the `refine.ini` file. + +#### Exiting {#exiting} + +To exit OpenRefine, close all the browser tabs or windows, then navigate to the command line window. To close this window and ensure OpenRefine exits properly, hold down `Control` and press `C` on your keyboard. This will save any last changes to your projects. + + + + + +You can find OpenRefine in your Applications folder, or you can open it using Terminal. + +To run OpenRefine using Terminal: +* Find the OpenRefine application / icon in Finder +* Control-click on the icon and select “Show Package Contents†from the context menu +* This should open a new Finder menu: navigate into the “MacOS†folder +* Control-click on “JavaAppLauncher†+* Choose “Open With†from the menu, and select “Terminal.†+ +To exit, close all your OpenRefine browser tabs, go back to the terminal window and press `Command` and `Q` to close it down. + +:::caution Problems starting? +If you are using an older version of OpenRefine or are on an older version of MacOS, [check our Wiki for solutions to problems with MacOS](https://github.com/OpenRefine/OpenRefine/wiki/Installation-Instructions#macos). +::: + + + + + +Use a terminal to launch OpenRefine. First, navigate to the installation folder. Then call the program: + +``` +cd openrefine-3.4.1 + ./refine +``` + +This will start OpenRefine and open your browser to the home screen. + +To exit, close all the browser tabs, and then press `control` and `C` in the terminal window. + +:::caution Did you get a JAVA_HOME error? +“Error: Could not find the ‘java’ executable at ‘’, are you sure your JAVA_HOME environment variable is pointing to a proper java installation?†+ +If you see this error, you need to [install and configure a JDK package](installing#linux), including setting up `JAVA_HOME`. +::: + + + + + +--- + +### Troubleshooting {#troubleshooting} + +If you are having problems connecting to OpenRefine with your browser, [check our Wiki for information about browser settings and operating-system issues](https://github.com/OpenRefine/OpenRefine/wiki/FAQ#i-am-having-trouble-connecting-to-openrefine-with-my-browser). + +### Starting with modifications {#starting-with-modifications} + +When you run OpenRefine from a command line, you can change a number of default settings. + + + + + +On Windows, use a slash: + +``` +C:>refine /i 127.0.0.2 /p 3334 +``` + +Get a list of all the commands with `refine /?`. + +|Command|Use|Syntax example| +|---|---|---| +|/w|Path to the webapp|refine /w /path/to/openrefine| +|/m|Memory maximum heap|refine /m 6000M| +|/p|Port|refine /p 3334| +|/i|Interface (IP address, or IP and port)|refine /i 127.0.0.2:3334| +|/H|HTTP host to expect on incoming requests|refine /H openrefine.internal| +|/d|Enable debugging (on port 8000)|refine /d| +|/x|Enable JMX monitoring for Jconsole and JvisualVM|refine /x| + + + + + +You cannot start the Mac version with modifications using Terminal, but you can modify the way the application starts with [settings within files](#modifications-set-within-files). + + + + + +To see the full list of command-line options, run `./refine -h`. + +|Command|Use|Syntax example| +|---|---|---| +|-w|Path to the webapp|./refine -w /path/to/openrefine| +|-d|Path to the workspace|./refine -d /where/you/want/the/workspace| +|-m|Memory maximum heap|./refine -m 6000M| +|-p|Port|./refine -p 3334| +|-i|Interface (IP address, or IP and port)|./refine -i 127.0.0.2:3334| +|-H|HTTP host to expect on incoming requests|./refine -H openrefine.internal| +|-k|Add a Google API key|./refine -k YOUR_API_KEY| +|-v|Verbosity (from low to high: error,warn,info,debug,trace)|./refine -v info| +|-x|Additional Java configuration parameters (see Java documentation)|| +|--debug|Enable debugging (on port 8000)|./refine --debug| +|--jmx|Enable JMX monitoring for Jconsole and JvisualVM|./refine --jmx| + + + + + +--- + +#### Modifications set within files {#modifications-set-within-files} + +On Windows, you can modify the way `openrefine.exe` runs by editing `openrefine.l4j.ini`; you can modify the way `refine.bat` runs by editing `refine.ini`. + +You can modify the Mac application by editing `info.plist`. + +On Linux, you can edit `refine.ini`. + +Some settings, such as changing memory allocations, are already set inside these files, and all you have to do is change the values. Some lines need to be un-commented to work. + +For example, inside `refine.ini`, you should see: +``` +no_proxy="localhost,127.0.0.1" +#REFINE_PORT=3334 +#REFINE_HOST=127.0.0.1 +#REFINE_WEBAPP=main\webapp + +# Memory and max form size allocations +#REFINE_MAX_FORM_CONTENT_SIZE=1048576 +REFINE_MEMORY=1400M + +# Set initial java heap space (default: 256M) for better performance with large datasets +REFINE_MIN_MEMORY=1400M +... +``` + +##### JVM preferences {#jvm-preferences} + +Further modifications can be performed by using JVM preferences. These JVM preferences are different options and have different syntax than the key/value descriptions used on the command line. + +Some of the most common keys (with their defaults) are: +* The project [autosave](starting#autosaving) frequency: `-Drefine.autosave` (5 [minutes]) +* The workspace director: `-Drefine.data_dir` (/) +* Development mode: `-Drefine.development` (false) +* Headless mode: `-Drefine.headless` (false) +* IP: `-Drefine.host` (127.0.0.1) +* Port: `-Drefine.port` (3333) +* The application folder: `-Drefine.webapp` (main/webapp) + +The syntax is as follows: + + + + + +Locate the `refine.l4j.ini` file, and insert lines in this way: + +``` +-Drefine.port=3334 +-Drefine.host=127.0.0.2 +-Drefine.webapp=broker/core +``` + +In `refine.ini`, use a similar syntax, but set multiple parameters within a single line starting with `JAVA_OPTIONS=`: + +``` +JAVA_OPTIONS=-Drefine.data_dir=C:\Users\user\Documents\OpenRefine\ -Drefine.port=3334 + +``` + + + + +Locate the `info.plist`, and find the `array` element that follows the line + +``` +JVMOptions +``` + +Typically this looks something like: + +``` +JVMOptions + +-Xms256M +-Xmx1024M +-Drefine.version=2.6-beta.1 +-Drefine.webapp=$APP_ROOT/Contents/Resource/webapp + +``` + +Add in values such as: + +``` +JVMOptions + +-Xms256M +-Xmx1024M +-Drefine.version=2.6-beta.1 +-Drefine.webapp=$APP_ROOT/Contents/Resource/webapp +-Drefine.autosave=2 +-Drefine.port=3334 + + +``` + + + + + +Locate the `refine.ini` file, and add `JAVA_OPTIONS=` before the `-Drefine.preference` declaration. You can un-comment and edit the existing suggested lines, or add lines: + +``` +JAVA_OPTIONS=-Drefine.autosave=2 +JAVA_OPTIONS=-Drefine.port=3334 +JAVA_OPTIONS=-Drefine.data_dir=usr/lib/OpenRefineWorkspace +``` + + + + + + +--- + +Refer to the [official Java documentation](https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html) for more preferences that can be set. + +## The home screen {#the-home-screen} + +When you first launch OpenRefine, you will see a screen with a menu on the left hand side that includes Create Project, Open Project, Import Project, and Language Settings. This is called the “home screen,†where you can manage your projects and general settings. + +In the lower left-hand corner of the screen, you'll see Preferences, Help, and About. + +### Language settings {#language-settings} + +From the home screen, look in the options to the left for Language Settings. You can set your preferred interface language here. This language setting will persist until you change it again in the future. Languages are translated as a community effort; some languages are partially complete and default back to English where unfinished. Currently OpenRefine supports the following languages for 75% or more of the interface: + +* Cebuano +* German +* English (UK) +* English (US) +* Spanish +* Filipino +* French +* Hebrew +* Magyar +* Italian +* Japanese (日本語) +* Portuguese (Brazil) +* Tagalog +* Chinese (简体中文) + +To leave the Language Settings screen, click on the diamond “OpenRefine†logo. + +:::info Help us Translate OpenRefine +We use Weblate to provide translations for the interface. You can check [our profile on Weblate](https://hosted.weblate.org/projects/openrefine/translations/) to see which languages are in the process of being supported. See [our technical reference if you are interested in contributing translation work](../technical-reference/translating-ui) to make OpenRefine accessible to people in other languages. +::: + +### Preferences {#preferences} + +In the bottom left corner of the screen, look for Preferences. At this time you can set preferences using a key/value pair: that is, selecting one of the keys below and setting a value for it. + +|Setting|Key|Value syntax|Default|Example|Version| +|---|---|---|---|---|---| +|Interface language|userLang|[ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) two-digit code|en|fr|—| +|Maximum facets|ui.browsing.listFacet.limit|Number|2000|5000|—| +|Timeout for Google Drive import|googleReadTimeOut|Number (microseconds)|180000|500000|—| +|Timeout for Google Drive authorization|googleConnectTimeOut|Number (microseconds)|180000|500000|—| +|Maximum lag for Wikibase edit retries|wikibase.upload.maxLag|Number (seconds)|5|10|—| +|Display of the reconciliation preview on hover|cell-ui.previewMatchedCells|Boolean|true|false|v3.2| +|Values for the choice of the number of rows to display|ui.browsing.pageSize|Array of number (JSON)|[ 5, 10, 25, 50 ]|[ 100,500,1000 ]|v3.4| +|Width of the panel for facets/history|ui.browsing.facetsHistoryPanelWidth|Number (pixel)|300|500|v3.5| + +To leave the Preferences screen, click on the diamond “OpenRefine†logo. + +If the preference you’re looking for isn’t here, look at the options you can set from the [command line or in an `.ini` file](#starting-with-modifications). + +## The project screen {#the-project-screen} + +The project screen (or work screen) is where you will spend most of your time once you have [begun to work on a project](starting). This is a quick walkthrough of the parts of the interface you should familiarize yourself with. + +![A screenshot of the project screen.](/img/projectscreen.png) + +### The project bar {#the-project-bar} + +The project bar runs across the very top of the project screen. It contains the the OpenRefine logo, the project title, and the project control buttons on the right side. + +At any time you can close your current project and go back to the home screen by clicking on the OpenRefine logo. If you’d like to open another project in a new browser tab or window, you can right-click on the logo and use “Open in a new tab.†You will lose [your current facets and view settings](#facetfilter) if you close your project (but data transformations will be saved in the [History](#history-undoredo) of the project). + +:::caution +Don’t click the “back†button on your browser - it will likely close your current project and you will lose your facets and view settings. +::: + +You can rename a project at any time by clicking inside the project title, which will turn into a text field. Project names don’t have to be unique, as OpenRefine organizes them based on a unique identifier behind the scenes. + +The Permalink allows you to return to a project at a specific view state - that is, with [facets and filters](facets) applied. The Permalink can help you pick up where you left off if you have to close your project while working with facets and filters. It puts view-specific information directly into the URL: clicking on it will load this current-view URL in the existing tab. You can right-click and copy the Permalink URL to copy the current view state to your clipboard, without refreshing the tab you’re using. + +The Open… button will open up a new browser tab showing the Create Project screen. From here you can change settings, start a new project, or open an existing project. + +Export is a dropdown menu that allows you to pick a format for exporting a dataset. Many of the export options will only export rows and records that are currently visible - the currently selected facets and filters, not the total data in the project. + +Help will open up a new browser tab and bring you to this user manual on the web. + +### The grid header {#the-grid-header} + +The grid header sits below the project bar and above the project grid (where the data of your project is displayed). The grid header will tell you the total number of rows or records in your project, and indicate whether you are in [rows or records mode](exploring#rows-vs-records). + +It will also tell you if you’re currently looking at a select number of rows via facets or filtering, rather than the entire dataset, by displaying either, for example, “180 rows†or “67 matching rows (180 total).†+ +Directly below the row number, you have the ability to switch between [row mode and records mode](exploring#rows-vs-records). OpenRefine stores projects persistently in one of the two modes, and displays your data as records by default if you are. + +To the right of the rows/records selection is the array of options for how many rows/records to view on screen at one time. At the far right of the screen you can navigate through your entire dataset one page at a time. + +### Extensions {#extensions} + +The Extensions dropdown offers you options for extending your data - most commonly by uploading your edited statements to Wikidata, or by importing or exporting schema. You can learn more about these functions on the [Wikibase section](wikibase/overview). Other extensions may also add functions to this dropdown menu. + +### The grid {#the-grid} + +The area of the project screen that displays your dataset is called the “grid†(or the “data grid,†or the “project gridâ€). The grid presents data in a tabular format, which may look like a normal spreadsheet program to you. + +Columns widths are automatically set based on their contents; some column headers may be cut off, but can be viewed by mousing over the headers. + +In each column header you will see a small arrow. Clicking on this arrow brings up a dropdown menu containing column-specific data exploration and transformation options. You will learn about each of these options in the [Exploring data](exploring) and [Transforming data](transforming) sections. + +The first column in every project will always be All, which contains options to flag, star, and do non-column-specific operations. The All column is also where rows/records are numbered. Numbering shows the permanent order of rows and records; a temporary sorting or facet may reorder the rows or show a limited set, but numbering will show you the original identifiers unless you make a permanent change. + +The project grid may display with both vertical and horizontal scrolling, depending on the number and width of columns, and the number of rows/records displayed. You can control the display of the project grid by using [Sort and View options](exploring#sort-and-view). + +Mousing over individual cells will allow you to [edit cells individually](cellediting#edit-one-cell-at-a-time). + +### Facet/Filter {#facetfilter} + +The Facet/Filter tab is one of the main ways of exploring your data: displaying the patterns and trends in your data, and helping you narrow your focus and modify that data. [Facets](facets) and [filters](facets#text-filter) are explained more in [Exploring data](exploring). + +![A screenshot of facets and filters in action.](/img/facetfilter.png) + +In the tab, you will see three buttons: Refresh, Reset all, and Remove all. + +Refreshing your facets will ensure you are looking at the latest information about each facet, for example if you have changed the counts or eliminated some options. + +Resetting your facets will remove any inclusion or exclusion you may have set - the facet options will stay in the sidebar, but your view settings will be undone. + +Removing your facets will clear out the sidebar entirely. If you have written custom facets using [expressions](expressions), these will be lost. + +You can preserve your facets and filters for future use by copying a [Permalink](#the-project-bar). + +### History (Undo/Redo) {#history-undoredo} + +In OpenRefine, any activity that changes the data can be undone. Changes are tracked from the very beginning, when a project is first created. The change history of each project is saved with the project's data, so quitting OpenRefine does not erase the steps you've taken. When you restart OpenRefine, you can view and undo changes that you made before you quit OpenRefine. OpenRefine [autosaves](starting#autosaving) your actions every five minutes by default, and when you close OpenRefine properly (using Ctrl + C). You can [change this interval](running#jvm-preferences). + +Project history gets saved when you export a project archive, and restored when you import that archive to a new installation of OpenRefine. + +![A screenshot of the History (Undo/Redo) tab with 13 steps.](/img/history.png "A screenshot of the History (Undo/Redo) tab with 13 steps.") + +When you click on the Undo / Redo tab in the sidebar of any project, that project’s history is shown as a list of changes in order, with the first “change†being the action of creating the project itself. (That first change, indexed as step zero, cannot be undone.) Here is a sample history with 3 changes: + +``` +0. Create project +1. Remove 7 rows +2. Create new column Last Name based on column Name with grel:value.split(" ") +3. Split 230 cell(s) in column Address into several columns by separator +``` + +The current state of the project is highlighted with a dark blue background. If you move back and forth on the timeline you will see the current state become highlighted, while the actions that came after that state will be grayed out. + +To revert your data back to an earlier state, simply click on the last action in the timeline you want to keep. In the example above, if we keep the removal of 7 rows but revert everything we did after that, then click on “Remove 7 rows.†The last 2 changes will be undone, in order to bring the project back to state #1. + +In this example, changes #2 and #3 will now be grayed out. You can redo a change by clicking on it in the history - everything up to and including it will be redone. + +If you have moved back one or more states, and then you perform a new operation on your data, the later actions (everything that’s greyed out) will be erased and cannot be re-applied. + +The Undo/Redo tab will indicate which step you’re on, and if you’re about to risk erasing work - by saying something like “4/5" or “1/7†at the end. + +#### Reusing operations {#reusing-operations} + +Operations that you perform in OpenRefine can be reused. For example, a formula you wrote inside one project can be copied and applied to another project later. + +To reuse one or more operations, first extract it from the project where it was first applied. Click to the Undo/Redo tab and click Extract…. This brings up a box that lists all operations up to the current state (it does not show undone operations). Select the operation or operations you want to extract using the checkboxes on the left, and they will be encoded as JSON on the right. Copy that JSON to the clipboard. + +Move to the second project, go to the Undo/Redo tab, click Apply… and paste in that JSON. + +Not all operations can be extracted. Edits to a single cell, for example, can’t be replicated. + +## Advanced OpenRefine uses {#advanced-openrefine-uses} + +### Running OpenRefine's Linux version on a Mac {#running-openrefines-linux-version-on-a-mac} + +You can run OpenRefine from the command line in Mac by using the Linux installation package. We do not promise support for this method. Follow the instructions in the Linux section. + +### Running as a server {#running-as-a-server} + +:::caution +Please note that if your machine has an external IP (is exposed to the Internet), you should not do this, or should protect it behind a proxy or firewall, such as nginx. Proceed at your own risk. +::: + +By default (and for security reasons), OpenRefine only listens to TCP requests coming from localhost (127.0.0.1) on port 3333. If you want to share your OpenRefine instance with colleagues and respond to TCP requests to any IP address of the machine, start it from the command line like this: +``` +./refine -i 0.0.0.0 +``` + +or set this option in `refine.ini`: +``` +REFINE_HOST=0.0.0.0 +``` + +or set this JVM option: +``` +-Drefine.host=0.0.0.0 +``` + +On Mac, you can add a specific entry to the `Info.plist` file located within the app bundle (`/Applications/OpenRefine.app/Contents/Info.plist`): +``` +JVMOptions + + + -Drefine.host=0.0.0.0 + … + +``` + +:::caution +OpenRefine has no built-in security or version control for multi-user scenarios. OpenRefine has a single data model that is not shared, so there is a risk of data operations being overwritten by other users. Care must be taken by users. +::: + +### Automating OpenRefine {#automating-openrefine} + +Some users may wish to employ OpenRefine for batch processing as part of a larger automated pipeline. Not all OpenRefine features can work without human supervision and advancement (such as clustering), but many data transformation tasks can be automated. + +:::caution +The following are all third-party extensions and code; the OpenRefine team does not maintain them and cannot guarantee that any of them work. +::: + +Some examples: + +* This project allows OpenRefine to be run from the command line using [operations saved in a JSON file](#reusing-operations): [OpenRefine batch processing](https://github.com/opencultureconsulting/openrefine-batch) +* A Python project for applying a JSON file of operations to a data file, outputting the new file, and deleting the temporary project, written by David Huynh and Max Ogden: [Python client library for Google Refine](https://github.com/maxogden/refine-python) +* And the same in Ruby: [Refine-Ruby](https://github.com/maxogden/refine-ruby) +* Another Python client library, by Paul Makepeace: [OpenRefine Python Client Library](https://github.com/PaulMakepeace/refine-client-py) + +To look for other instances, search our Google Groups [for users](https://groups.google.com/g/openrefine) and [for developers](https://groups.google.com/g/openrefine-dev), where [these projects were originally posted](https://groups.google.com/g/openrefine/c/GfS1bfCBJow/m/qWYOZo3PKe4J). diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/sortview.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/sortview.md new file mode 100644 index 000000000..4e6bcb715 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/sortview.md @@ -0,0 +1,41 @@ +--- +id: sortview +title: Sort and view +sidebar_label: Sort and view +--- + +## Sort {#sort} + +You can temporarily sort your rows by one column. You can sort based on [data type](exploring#data-types): +* text alphabetically or reverse +* numbers by largest or smallest +* dates by earliest or latest +* boolean values by false first or true first. + +You can also choose where to place errors and blank cells in the sorting. Text can be case-sensitive or not: if so, cells that start with lowercase characters will appear ahead of those that start with uppercase characters. + +![A screenshot of the Sort window.](/img/sort.png) + +After you apply a sorting method, you can make it permanent, remove it, reverse it, or apply a subsequent sorting. When it is applied, you’ll find Sort in the project grid header to the right of the rows-display setting, which will show all current sorting settings. + +If you have multiple sorting methods applied, they will work in the order you applied them (represented in order in the Sort menu). For example, you can sort an “authors†column alphabetically, and then sort their books by publication date, for those authors that have more than one book. If you apply those in a different order - sort all the publication dates in the dataset first, and then alphabetically by author - your dataset will look different. + +![Temporarily sorted rows.](/img/sort2.png) + +When the sorting method you've applied is temporary, you will see that the rows retain their original numbering. When you make that sorting method permanent, by selecting Reorder rows permanently, the row numbers will change and the Sort menu in the project grid header will disappear. This will apply all current sorting methods. + +## View {#view} + +You can control what data you view in the grid. On each column, you will see a View menu option. From there, you can “collapse†(hide) that specific column, all other columns, all columns to the left, and all columns to the right. Using the View option that appears in the All column’s dropdown menu, you can collapse all columns, and expand all the columns that you previously collapsed. + +### Show/hide “null†{#showhide-null} + +You can find, under All → View, the option to show and hide [“null†values](exploring#data-types). A small grey “null†will appear in each applicable cell. Remember that a null cell is not the same thing as an empty cell. + +![A screenshot of what a null value looks like.](/img/null.png) + +## Page navigation {#page-navigation} + +You can go directly to any page by changing the page number on the right-hand side. Using the up and down arrow keys in this input lets you go to the next and previous pages. You can also change the number of rows or records per page on the left-hand side of this view header bar. + +![A screenshot of the Page Navigation Feature.](/img/goto.png) diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/starting.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/starting.md new file mode 100644 index 000000000..f40ec237c --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/starting.md @@ -0,0 +1,194 @@ +--- +id: starting +title: Starting a project +sidebar_label: Starting a project +--- + +## Overview {#overview} + +An OpenRefine project is started by importing in some existing data - OpenRefine doesn’t allow you to create a dataset from nothing. + +No matter where your data comes from, OpenRefine won’t modify your original data source. It copies all the information from your input, creates its own project file, and stores it in your [workspace directory](installing#set-where-data-is-stored). + +The data and all of your edits are [automatically saved](#autosaving) inside the project file. When you’re finished modifying the data, you can [export it back out](exporting) into the file format of your choice. + +You can also receive and open other people’s projects, or send them yours, by [exporting a project archive](exporting#export-a-project) and [importing it](#import-a-project). + +## Create a project by importing data {#create-a-project-by-importing-data} + +When you start OpenRefine, you’ll be taken to the Create Project screen. You’ll see on the left side of the screen that your options are to: + +* import data from one or more files on your computer +* import data from one or more links on the web +* import data by pasting in text from your clipboard +* import data from a database (using SQL), and +* import one or more Sheets from Google Drive. + +From these sources, you can load any of the following file formats: + +* comma-separated values (CSV) or text-separated values (TSV) +* Text files +* Fixed-width columns +* JSON +* XML +* OpenDocument spreadsheet (ODS) +* Excel spreadsheet (XLS or XLSX) +* PC-Axis (PX) +* MARC +* RDF data (JSON-LD, N3, N-Triples, Turtle, RDF/XML) +* Wikitext + +More formats can be imported by [adding extensions to provide that functionality](https://openrefine.org/download.html). + +If you supply two or more files for one project, the files’ rows will be loaded in the order that you specify, and OpenRefine will create a column at the beginning of the dataset with the source URL or file name in it to help you identify where each row came from. If the files have columns with identical names, the data will load in those columns; if not, the successive files will append all of their new columns to the end of the dataset: + +|File|Fruit|Quantity|Berry|Berry source| +|---|---|---|---|---| +|fruits.csv|Orange|4| +|fruits.csv|Apple|6| +|berries.csv||9|Mulberry|Greece| +|berries.csv||2|Blueberry|Canada| + +You cannot combine two datasets into one project by appending data within rows. You can, however, combine two projects later using functions such as [cross()](grelfunctions/#crosscell-s-projectname-s-columnname), or [fetch further data](columnediting) using other methods. + +For whichever method you choose to start your project, when you click Next >> you will be given a preview and a chance to configure the way OpenRefine interprets the data you input. + +### Get data from this computer {#get-data-from-this-computer} + +Click on Browse… and select a file (or several) on your hard drive. All files will be shown, not just compatible ones. + +If you import an archive file (something with the extension `.zip`, `.tar.gz`, `.tgz`, `.tar.bz2`, `.gz`, or `.bz2`), OpenRefine detects the files inside it, shows you a preview screen, and allows you to select which ones to load. This does not work with `.rar` files. When importing multiple archives you can store the name of the archive each file was extracted from by ticking the `Store archive file` option upon import. + +### Web addresses (URLs) {#web-addresses-urls} + +Type or paste the URL to a data file into the field provided. You can add as many fields as you want. OpenRefine will download the file and preview the project for you. + +If you supply two or more file URLs, OpenRefine will identify each one and ask you to choose which (or all) to load. + +Do not use this form to load a Google Sheet by its link; use [the Google Data form instead](#google-data). + +### Clipboard {#clipboard} + +You can copy and paste in data from anywhere. OpenRefine will recognize comma-separated, tab-separated, or table-formatted information copied from sources such as word-processing documents, spreadsheets, and tables in PDFs. You can also just paste in a list of items that you want to turn into rows. OpenRefine recognizes each new text line as a row. + +This can be useful if you want to pre-select a specific number of rows from your source data, or paste together rows from different places, rather than delete unwanted rows later in the project interace. + +This can also be useful if you would like to paste in a list of URLs, which you can use later to [fetch more data](columnediting). + +### Database (SQL) {#database-sql} + +If you are an administrator or have SQL access to a database of information, you may want to pull the latest dataset directly from there. This could include an online catalogue, a content management system, or a digital repository or collection management system. You can also load a database (`.db`) file saved locally. You will need to use an [SQL query](https://www.w3schools.com/sql/) to import your intended data. + +There are some publicly-accessible databases you can query, such as [one provided by Rfam](https://docs.rfam.org/en/latest/database.html). The instructions provided by Rfam can help you understand how to connect to and query from other databases. + +OpenRefine can connect to PostgreSQL, MySQL, MariaDB, and SQLite database systems. It will automatically populate the Port field based on which of these you choose, but you can manually edit this if needed. + +If you have a `.db` file, you can supply the path to the file on your computer in the Database field at the bottom of the form. You can leave the rest of the fields blank. + +To import data directly from a database, you will need the database type (such as MySQL), database name, the hostname (either an IP address or the domain that hosts the database), and the port on the host. You will need an account authorized for access, and you may need to add OpenRefine's IP address or host to the "allowable hosts" for that account. You can find that information by pressing Test and getting the IP address from the error message that results. + +You can either connect just once to gather data, or save the connection to use it again later. If you press Connect without saving, OpenRefine will forget all the information you just entered. If you’d like to save the connection, name your connection in a way you will recognize later. Click Save and it will appear in the Saved Connections list on the left. From now on, you can click on the ... ellipsis to the right of the connection you’ve saved, and click Connect. + +If your connection is successful, you will see a Query Editor where you can run your SQL query. OpenRefine will give you an error if you write a statement that tries to modify the source database in any way. + +### Google data {#google-data} + +You have two ways to load in data from Google Sheets: +* providing a link to an accessible Google Sheet (that is, one with link-sharing turned on), and +* selecting a Google Sheet in your Google Drive. + +#### Google Sheet by URL {#google-sheet-by-url} + +You can import data from any Google Sheet that has link-sharing turned on. Paste in a URL that looks something like + +``` +https://docs.google.com/spreadsheets/………/edit?usp=sharing +``` + +This will only work with Sheets, not with any other Google Drive file that might have an available link, including `.xls` and other valid files that are hosted in Google Drive. These links will not work when attempting to start a project [by URL](#web-addresses-urls) either, so you need to download those files to your computer. + +#### Google Sheet from Drive {#google-sheet-from-drive} + +You can authorize OpenRefine to access your Google Drive data and import data from any Google Sheet it finds there. This will include Sheets that belong to you and Sheets that are shared with you, as well as Sheets that are in your trash. + +When you select a Google option (either here, or [when exporting project data to Google Drive or Google Sheets](exporting), you will see a pop-up window that asks you to select a Google account to authorize with. You may see an error message when you authorize: if so, try your import or export operation again and it should succeed. + +OpenRefine will not show spreadsheets that are in your email inbox or stored in any other Google property - only in Drive. It also won’t show all compatible file formats, only Sheets files. + +OpenRefine will generate a list of all Sheets it finds, with the most recently modified Sheets at the top. If a file you’ve just added isn’t showing in this list, you can close and restart OpenRefine, or simply navigate to an existing project, open it, then head back to the Create Project window and check again. + +When you click Preview the Sheet will open in a new browser tab. When you click the Sheet title, OpenRefine will begin to process the data. + + +## Project preview {#project-preview} + +Once OpenRefine is ready to import the data, you will see a screen with Configure Parsing Options at the top. You’ll see a preview of the first 100 rows and all identified columns. + +At the bottom of the screen you will find options for telling OpenRefine how to process what it has found. You can tell it which row(s) to parse as column headers, as well as to ignore any number of rows at the top. You can also select a specific range of rows to work with, by discarding some rows at the top (excluding the header) and limiting the total number of rows it loads. + +OpenRefine tries to guess how to parse your data based on the file extension. For example, `.xml` files are going to be parsed as though they are formatted in XML. An unknown file extension (or your clipboard copy-paste) is assumed to be either tab-separated or comma-separated. OpenRefine looks for a tab character, and if one is found, it assumes you have imported tab-separated data. + +If OpenRefine isn’t certain what format you imported, it will provide a list of possibilities under Parse data as and some settings. You can specify a custom separator now, or split columns later while [transforming your data](transforming). + +If you imported a spreadsheet with multiple worksheets, they will be listed along with the number of rows they contain. You can only select data from one worksheet. + +Note that OpenRefine does not preserve any formatting, such as cell or text colour, that my have been in the original data file. Hyperlinked text will be input as plain text, but OpenRefine will recognize links and make them clickable inside the project interface. + +:::info Encoding issues? +Look for character encoding issues at this stage. You may want to manually select an encoding, such as UTF-8, UTF-16, or ASCII, if OpenRefine does not display some characters correctly in the preview. Once your project is created, you can specify another encoding for specific columns using the [reinterpret() function](grelfunctions#reinterprets-s-encoder). +::: + +You should create a project name at this stage. You can also supply tags to keep your projects organized. When you’re happy with the preview, click Create Project. + + +## Import a project {#import-a-project} + +Because OpenRefine only runs locally on your computer, you can’t have a project accessible to more than one person at the same time. + +The best way to collaborate with another person is to export and import projects that save all your changes, so that you can pick up where someone else left off. You can also [export projects](exporting#export-a-project) and import them to other computers, such as for working on the same project from the office and from home. + +An exported project will include all of the [history](running#history-undoredo), so you can see (and undo) all the changes from the previous user. It is essentially a point-in-time snapshot of their work. OpenRefine only exports projects as `.tar.gz` files at this time. +:::caution +If you wish to hide the original state of your data and your history of edits (for example, if you are using OpenRefine to anonymize information), export your cleaned dataset only and do not share your project archive. +::: + +Once someone has sent you a project archive file from their computer, you can save it anywhere. OpenRefine will import it like a new project and save its information to your workspace directory. + +In the left-hand menu of the home screen, click Import Project. Click Browse… and navigate to wherever you saved the file you were sent (for example, your Downloads folder). + +You can rename the project if you’d like - we recommend adding your name, a date, or a version number, if you’re planning to continue collaborating with another person (or working from multiple computers). + +Then, click Import Project. Your project should appear with a step count beside Undo/Redo if steps were saved by the exporter. + +OpenRefine will store the project in its own workspace directory, so you can now delete the original file that was sent to you. + + +## Project management {#project-management} + +You can access all of your created projects by clicking on Open Project. Your project list can be organized by modification date, title, row count, and other metadata you can supply (such as subject, descripton, tags, or creator). To edit the fields you see here, click About to the left of each project. There you can edit a number of available fields. You can also see the project ID that corresponds to the name of the folder in your work directory. + +### Naming projects {#naming-projects} + +You may have multiple projects from the same dataset, or multiple versions from sharing a project with another person. OpenRefine automatically generates a project name from the imported file, or “clipboard†when you use Clipboard importing. Project names don’t have to be unique, and OpenRefine will create many projects with the same name unless you intervene. + +You can edit a project's name when you create it or import it, and you can rename a project later by opening it and clicking on the project name at the top of the screen. + +### Autosaving {#autosaving} + +OpenRefine [saves all of your actions](running#history-undoredo) (everything you can see in the Undo/Redo panel). That includes flagging and starring rows. + +It doesn’t, however, save your facets, filters, or any kind of view you may have in place while you work. This includes the number of rows showing, and any sorting or column collapsing you may have done. A good rule of thumb is: if it’s not showing in Undo/Redo, you will lose it when you leave the project workspace. + +Autosaving happens by default every five minutes. You can [change this preference by following these directions](running#jvm-preferences). + +You can only save and share facets and filters, not any other type of view. To save current facets and filters, click Permalink. The project will reload with a different URL, which you can then copy and save elsewhere. This permalink will save both the facets and filters you’ve set, and the settings for each one (such as sorting by count rather than by name). + +### Deleting projects {#deleting-projects} + +You can delete projects, which will erase the project files from the workspace directory on your computer. This is immediate and cannot be undone. + +Go to Open Project and find the project you want to delete. Click on the X to the left of the project name. There will be a confirmation dialog. + +### Project files {#project-files} + +You can find all of your raw project files in your work directory. They will be named according to the unique “Project ID†that OpenRefine has assigned them, which you can find on the Open Project screen, under the “About†link for each project. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/transforming.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/transforming.md new file mode 100644 index 000000000..53a436370 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/transforming.md @@ -0,0 +1,34 @@ +--- +id: transforming +title: Transforming data +sidebar_label: Overview +--- + +## Overview {#overview} + +OpenRefine gives you powerful ways to clean, correct, codify, and extend your data. Without ever needing to type inside a single cell, you can automatically fix typos, convert things to the right format, and add structured categories from trusted sources. + +This section of ways to improve data are organized by their appearance in the menu options in OpenRefine. You can: + +* change the order of [rows](#edit-rows) or [columns](columnediting#rename-remove-and-move) +* edit [cell contents](cellediting) within a particular column +* [transform](transposing) rows into columns, and columns into rows +* [split or join columns](columnediting#split-or-join) +* [add new columns](columnediting) based on existing data, with fetching new information, or through [reconciliation](reconciling) +* convert your rows of data into [multi-row records](exploring#rows-vs-records). + +## Edit rows {#edit-rows} + +Moving rows around is a permanent change to your data. + +You can [sort your data](sortview#sort) based on the values in one column, but that change is a temporary view setting. With that setting applied, you can make that new order permanent. + +![A screenshot of where to find the Sort menu with a sorting applied.](/img/sortPermanent.png) + +In the project grid header, the word “Sort†will appear when a sort operation is applied. Click on it to show the dropdown menu, and select Reorder rows permanently. You will see the numbering of the rows change under the All column. + +:::info Reordering all rows +Reordering rows permanently will affect all rows in the dataset, not just those currently viewed through [facets and filters](facets). +::: + +You can undo this action using the [History tab](running#history-undoredo). \ No newline at end of file diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/transposing.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/transposing.md new file mode 100644 index 000000000..6b5ec0dc8 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/transposing.md @@ -0,0 +1,234 @@ +--- +id: transposing +title: Transposing +sidebar_label: Transposing +--- + +## Overview {#overview} + +These functions were created to solve common problems with reshaping your data: pivoting cells from a row into a column, or pivoting cells from a column into a row. You can also transpose from a repeated set of values into multiple columns. + +## Transpose cells across columns into rows {#transpose-cells-across-columns-into-rows} + +Imagine personal data with addresses in this format: + +|Name|Street|City|State/Province|Country|Postal code| +|---|---|---|---|---|---| +|Jacques Cousteau|23, quai de Conti|Paris||France|75270| +|Emmy Noether|010 N Merion Avenue|Bryn Mawr|Pennsylvania|USA|19010| + +You can transpose the address information from this format into multiple rows. Go to the “Street†column and select Transpose → Transpose cells across columns into rows. From there you can select all of the five columns, starting with “Street†and ending with “Postal code,†that correspond to address information. Once you begin, you should put your project into [records mode](exploring#rows-vs-records) to associate the subsequent rows with “Name†as the key column. + +![A screenshot of the transpose across columns window.](/img/transpose1.png) + +### One column {#one-column} + +You can transpose the multiple address columns into a series of rows: + +|Name|Address| +|---|---| +|Jacques Cousteau|23, quai de Conti| +| |Paris| +| |France| +| |75270| +|Emmy Noether|010 N Merion Avenue| +||Bryn Mawr| +||Pennsylvania| +||USA| +||19010| + +You can choose one column and include the column-name information in each cell by prepending it to the value, with or without a separator: + +|Name|Address| +|---|---| +|Jacques Cousteau|Street: 23, quai de Conti| +| |City: Paris| +| |Country: France| +| |Postal code: 75270| +|Emmy Noether|Street: 010 N Merion Avenue| +||City: Bryn Mawr| +||State/Province: Pennsylvania| +||Country: USA| +||Postal code: 19010| + +### Two columns {#two-columns} + +You can retain the column names as separate cell values, by selecting Two new columns and naming the key and value columns. + +|Name|Address part|Address| +|---|---|---| +|Jacques Cousteau|Street|23, quai de Conti| +| |City|Paris| +| |Country|France| +| |Postal code|75270| +|Emmy Noether|Street|010 N Merion Avenue| +||City|Bryn Mawr| +||State/Province|Pennsylvania| +||Country|USA| +||Postal code|19010| + +## Transpose cells in rows into columns {#transpose-cells-in-rows-into-columns} + +Imagine employee data in this format: + +|Column| +|---| +|Employee: Karen Chiu| +|Job title: Senior analyst| +|Office: New York| +|Employee: Joe Khoury| +|Job title: Junior analyst| +|Office: Beirut| +|Employee: Samantha Martinez| +|Job title: CTO| +|Office: Tokyo| + +The goal is to sort out all of the information contained in one column into separate columns, but keep it organized by the person it represents: + +|Name |Job title |Office| +|---|---|---| +|Karen Chiu |Senior analyst |New York| +|Joe Khoury |Junior analyst |Beirut| +|Samantha Martinez |CTO |Tokyo| + +By selecting Transpose → Transpose cells in rows into columns... a window will appear that simply asks how many rows to transpose. In this case, each employee record has three rows, so input “3†(do not subtract one for the original column). The original column will disappear and be replaced with three columns, with the name of the original column plus a number appended. + +|Column 1 |Column 2 |Column 3| +|---|---|---| +|Employee: Karen Chiu |Job title: Senior analyst |Office: New York| +|Employee: Joe Khoury |Job title: Junior analyst |Office: Beirut| +|Employee: Samantha Martinez |Job title: CTO |Office: Tokyo| + +From here you can use Cell editing → Replace to remove “Employee: â€, “Job title: â€, and “Office: †if you wish, or use [expressions](expressions) with Edit cells → Transform... to clean out the extraneous characters: + +``` +value.replace("Employee: ", "") +``` + +If your dataset doesn't have a predictable number of cells per intended row, such that you cannot specify easily how many columns to create, try Columnize by key/value columns. + +## Columnize by key/value columns {#columnize-by-keyvalue-columns} + +This operation can be used to reshape a dataset that contains key and value columns: the repeating strings in the key column become new column names, and the contents of the value column are moved to new columns. This operation can be found at Transpose → Columnize by key/value columns. + +![A screenshot of the Columnize window.](/img/transpose2.png) + +Consider the following example, with flowers, their colours, and their International Union for Conservation of Nature (IUCN) identifiers: + +|Field |Data | +|--------|----------------------| +|Name |Galanthus nivalis | +|Color |White | +|IUCN ID |162168 | +|Name |Narcissus cyclamineus | +|Color |Yellow | +|IUCN ID |161899 | + +In this format, each flower species is described by multiple attributes on consecutive rows. The “Field†column contains the keys and the “Data†column contains the values. In the Columnize by key/value columns window you can select each of these from the available columns. It transforms the table as follows: + +| Name | Color | IUCN ID | +|-----------------------|----------|---------| +| Galanthus nivalis | White | 162168 | +| Narcissus cyclamineus | Yellow | 161899 | + +### Entries with multiple values in the same column {#entries-with-multiple-values-in-the-same-column} + +If a new row would have multiple values for a given key, then these values will be grouped on consecutive rows, to form a [record structure](exploring#rows-vs-records). + +For instance, flowers can have multiple colors: + +| Field | Data | +|-------------|-----------------------| +| Name | Galanthus nivalis | +| _Color_ | _White_ | +| _Color_ | _Green_ | +| IUCN ID | 162168 | +| Name | Narcissus cyclamineus | +| Color | Yellow | +| IUCN ID | 161899 | + +This table is transformed by the Columnize operation to: + +| Name | Color | IUCN ID | +|-----------------------|----------|---------| +| Galanthus nivalis | White | 162168 | +| | Green | | +| Narcissus cyclamineus | Yellow | 161899 | + +The first key encountered by the operation serves as the record key, so the “Green†value is attached to the “Galanthus nivalis†name. See the [Row order](#row-order) section for more details about the influence of row order on the results of the operation. + +### Notes column {#notes-column} + +In addition to the key and value columns, you can optionally add a column for notes. This can be used to store extra metadata associated to a key/value pair. + +Consider the following example: + +| Field | Data | Source | +|---------|---------------------|-----------------------| +| Name | Galanthus nivalis | IUCN | +| Color | White | Contributed by Martha | +| IUCN ID | 162168 | | +| Name | Narcissus cyclamineus | Legacy | +| Color | Yellow | 2009 survey | +| IUCN ID | 161899 | | + +If the “Source†column is selected as the notes column, this table is transformed to: + +| Name | Color | IUCN ID | Source: Name | Source: Color | +|-----------------------|----------|---------|---------------|-----------------------| +| Galanthus nivalis | White | 162168 | IUCN | Contributed by Martha | +| Narcissus cyclamineus | Yellow | 161899 | Legacy | 2009 survey | + +Notes columns can therefore be used to preserve provenance or other context about a particular key/value pair. + +### Row order {#row-order} + +The order in which the key/value pairs appear matters. The Columnize operation will use the first key it encounters as the delimiter for entries: every time it encounters this key again, it will produce a new row, and add the following key/value pairs to that row. + +Consider for instance the following table: + +| Field | Data | +|----------|-----------------------| +| _Name_ | Galanthus nivalis | +| Color | White | +| IUCN ID | 162168 | +| _Name_ | Crinum variabile | +| _Name_ | Narcissus cyclamineus | +| Color | Yellow | +| IUCN ID | 161899 | + +The occurrences of the “Name†value in the “Field†column define the boundaries of the entries. Because there is no other row between the “Crinum variabile†and the “Narcissus cyclamineus†rows, the “Color†and “IUCN ID†columns for the “Crinum variabile†entry will be empty: + +| Name | Color | IUCN ID | +|-----------------------|----------|---------| +| Galanthus nivalis | White | 162168 | +| Crinum variabile | | | +| Narcissus cyclamineus | Yellow | 161899 | + +This sensitivity to order is removed if there are extra columns: in that case, the first extra column will serve as the key for the new rows. + +### Extra columns {#extra-columns} + +If your dataset contains extra columns, that are not being used as the key, value, or notes columns, they can be preserved by the operation. For this to work, they must have the same value in all old rows corresponding to a new row. + +In the following example, the “Field†and “Data†columns are used as key and value columns respectively, and the “Wikidata ID†column is not selected: + +| Field | Data | Wikidata ID | +|---------|-----------------------|-------------| +| Name | Galanthus nivalis | Q109995 | +| Color | White | Q109995 | +| IUCN ID | 162168 | Q109995 | +| Name | Narcissus cyclamineus | Q1727024 | +| Color | Yellow | Q1727024 | +| IUCN ID | 161899 | Q1727024 | + +This will be transformed to: + +| Wikidata ID | Name | Color | IUCN ID | +|-------------|-----------------------|----------|---------| +| Q109995 | Galanthus nivalis | White | 162168 | +| Q1727024 | Narcissus cyclamineus | Yellow | 161899 | + +This actually changes the operation: OpenRefine no longer looks for the first key (“Nameâ€) but simply pivots all information based on the first extra column's values. Every old row with the same value gets transposed into one new row. If you have more than one extra column, they are pivoted as well but not used as the new key. + +You can use [Fill down](cellediting#fill-down-and-blank-down) to put identical values in the extra columns if you need to. \ No newline at end of file diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/troubleshooting.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/troubleshooting.md new file mode 100644 index 000000000..5388fc351 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/troubleshooting.md @@ -0,0 +1,31 @@ +--- +id: troubleshooting +title: Troubleshooting +sidebar_label: Troubleshooting +--- + +## Frequently asked questions {#frequently-asked-questions} + +We collect and share FAQs and responses on Github at [https://github.com/OpenRefine/OpenRefine/wiki/FAQ](https://github.com/OpenRefine/OpenRefine/wiki/FAQ). + +If you don’t find your problem and solution there, continue on to the resources in the Community section below to see more conversations and look for solutions. + +## Community {#community} + +### If you’re having a problem: {#if-youre-having-a-problem} +* Search the [User forum](https://groups.google.com/g/openrefine) to see if the problem is already reported +* Search [Github issues](https://github.com/OpenRefine/OpenRefine/issues) to see if the problem is already reported +* Read [Stack Overflow](https://stackoverflow.com/questions/tagged/openrefine) to see if others had a similar problem +* Check [Twitter](https://twitter.com/search?f=tweets&vertical=default&q=OpenRefine%20OR%20%22Open%20Refine%22%20OR%20%23OpenRefine&src=typd) to see if others are discussing the problem +* Report an issue: + * First as a new thread (conversation) in the [User forum](https://groups.google.com/g/openrefine). + * Then, if you wish, you can create a Github issue. + +### If you want to contribute: {#if-you-want-to-contribute} +* [Help us translate the tool into more languages](../technical-reference/translating-ui), using Weblate +* [We have a guide to contributing](../technical-reference/contributing) in the [Technical Reference](../technical-reference/technical-reference-index) section +* Contribute your feature requests in the [User forum](https://groups.google.com/g/openrefine) or as [Github issues](https://github.com/OpenRefine/OpenRefine/issues/new/choose) +* Join the User Forum and/or the [Developer Forum](https://groups.google.com/g/openrefine-dev) +* Share your successes and use cases with us, in the User forum +* Add your [blog posts, guides, tips, tricks, tutorials to our list](https://github.com/OpenRefine/OpenRefine/wiki/External-Resources) +* Keep an eye out for and respond to our biennial user survey. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/advanced-schemas.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/advanced-schemas.md new file mode 100644 index 000000000..45f91800c --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/advanced-schemas.md @@ -0,0 +1,72 @@ +Sometimes your data is not as simple as a normal table, or the sort of +statements that you want to do varies on each row. This document +explains how to work around these cases. + +## Hierarchical data {#hierarchical-data} + +Sometimes your source provides data in a structured format, such as XML, +JSON or RDF. OpenRefine can import these files and will convert them to +tables. These tables will reflect some of the hierarchy in the file by +means of null cells, using the [records mode](/manual/exploring#rows-vs-records). + +The Wikibase extension always works in rows mode, so if we want to add +statements which reference both the artist and the song, we need to fill +the null cells with the corresponding artist. You can do this with the +**Fill down** operation (in the **Edit cells** menu for this column). +This function will copy not just cell values but also reconciliation +results. + +## Conditional additions {#conditional-additions} + +Sometimes you want to add a statement only in some conditions. + +The workflow to achieve this looks like this: +- Use facets to select the rows where you do not want to add any + information; +- Blank out the cells in the column that contain the information you + want to add. If you do not want to lose this information, you can + create a copy of the column beforehand; +- Remove your facets to see all rows again; +- Create a schema using the column you partially blanked out as + statement value. + +## Varying properties {#varying-properties} + +Sometimes you wish you could use column variables for properties in your +schema. It is currently not possible, first because we do not have a +reconciliation service for properties yet, but also because allowing +varying properties in a statement would mean that these properties could +potentially have different datatypes, which would break the structure of +the schema. + +If you only want to use a few properties, there is a way to go around +this problem. For instance, say you have a first column of altitudes and a +second column that indicates whether you should add it as +[operating altitude (P2254)](https://www.wikidata.org/wiki/Property:P2254) or as +[elevation above sea level (P2044)](https://www.wikidata.org/wiki/Property:P2044). + +Create a text facet on the first column. Filter to keep only the +*altitude* values. Add a new column based on the second column, by +keeping the default expression (`value`) which just copies the existing +values. Then, select the *maximum operating altitude* value in the facet +and do the same. Reset the facet, you should have obtained two new columns +which partition the original column. You can now create a schema which adds +two statements, with values taken from those columns. Since blank values are +ignored, exactly one statement will be added for each item, with the desired property. + +## Adapting to existing data on Wikibase {#adapting-to-existing-data-on-wikibase} + +Sometimes you want to create statements only if there are no such +statements on the item yet. Here is one way to achieve this: + +- first, retrieve the existing values from Wikidata first, using the + **Edit columns** → **Add columns from reconciled values** action; +- second, create a *facet by null* on the newly created column that + contains the information you want to control against; +- select the non-null rows (value **false**); +- clear the contents of the column where your source values are + (**Edit cells** → **Common transformations** → **To null**). + +You can now construct your schema as usual - null values will be ignored +when generating the statements. + diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/configuration.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/configuration.md new file mode 100644 index 000000000..aa7fd1d98 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/configuration.md @@ -0,0 +1,149 @@ +--- +id: configuration +title: Connecting OpenRefine to a Wikibase instance +sidebar_label: Connecting to Wikibase +--- + +This page explains how to connect OpenRefine to any Wikibase instance. If you just want to work with [Wikidata](https://www.wikidata.org/), you can ignore this page as Wikidata is configured out of the box in OpenRefine. + +## For Wikibase end users {#for-wikibase-end-users} + +All you need to configure OpenRefine to work with a Wikibase instance is a *manifest* for that instance, which provides some metadata and links required for the integration to work. + +We offer some off-the-shelf manifests for some public Wikibase instances in the [wikibase-manifests](https://github.com/OpenRefine/wikibase-manifests) repository. But the administrators of your Wikibase instance should provide one that is potentially more +up to date, so it makes sense to request it to them first. + +## For Wikibase administrators {#for-wikibase-administrators} + +To let your users contribute to your Wikibase instance with OpenRefine, you will need to write a manifest as described above. There is currently no canonical location where this manifest should be hosted - just make sure can be found easily by your users. This section explains the format of the manifest. + +### Requirements {#requirements} + +To work with OpenRefine, your Wikibase instance needs an associated reconciliation service. For instance you can use [a Python wrapper](https://github.com/wetneb/openrefine-wikibase) for this. Also, in addition to Wikibase, the [UniversalLanguageSelector extension](https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:UniversalLanguageSelector) should be installed. + + +### The format of the manifest {#the-format-of-the-manifest} + +Here is the manifest of Wikidata: + +```json +{ + "version": "1.0", + "mediawiki": { + "name": "Wikidata", + "root": "https://www.wikidata.org/wiki/", + "main_page": "https://www.wikidata.org/wiki/Wikidata:Main_Page", + "api": "https://www.wikidata.org/w/api.php" + }, + "wikibase": { + "site_iri": "http://www.wikidata.org/entity/", + "maxlag": 5, + "properties": { + "instance_of": "P31", + "subclass_of": "P279" + }, + "constraints": { + "property_constraint_pid": "P2302", + "exception_to_constraint_pid": "P2303", + "constraint_status_pid": "P2316", + "mandatory_constraint_qid": "Q21502408", + "suggestion_constraint_qid": "Q62026391", + "distinct_values_constraint_qid": "Q21502410", + // ... + } + }, + "oauth": { + "registration_page": "https://meta.wikimedia.org/wiki/Special:OAuthConsumerRegistration/propose" + }, + "reconciliation": { + "endpoint": "https://wikidata.reconci.link/${lang}/api" + }, + "editgroups": { + "url_schema": "([[:toollabs:editgroups/b/OR/${batch_id}|details]])" + } +} +``` + +In general, there are several parts of the manifest: version, mediawiki, wikibase, oauth, reconciliation and editgroups. + +#### version {#version} + +The version should in the format "1.x". The minor version should be increased when you update the manifest in a backward-compatible manner. The major version should be "1" if the manifest is in the format specified by [wikibase-manifest-schema-v1.json](https://github.com/afkbrb/wikibase-manifest/blob/master/wikibase-manifest-schema-v1.json). + +#### mediawiki {#mediawiki} + +This part contains some basic information of the Wikibase. + +##### name {#name} + +The name of the Wikibase, should be unique for different Wikibase instances. + +##### root {#root} + +The root of the Wikibase. Typically in the form "https://foo.bar/wiki/". The trailing slash cannot be omitted. + +##### main_page {#main_page} + +The main page of the Wikibase. Typically in the form "https://foo.bar/wiki/Main_Page". + +##### api {#api} + +The MediaWiki API endpoint of the Wikibase. Typically in the form "https://foo.bar/w/api.php". + +#### wikibase {#wikibase} + +This part contains configurations of the Wikibase extension. + +##### site_iri {#site_iri} + +The IRI of the Wikibase, in the form 'http://foo.bar/entity/'. This should match the IRI prefixes used in RDF serialization. Be careful about using "http" or "https", because any variation will break comparisons at various places. The trailing slash cannot be omitted. + +##### maxlag {#maxlag} + +Maxlag is a parameter that controls how aggressive a mass-editing tool should be when uploading edits to a Wikibase instance. See https://www.mediawiki.org/wiki/Manual:Maxlag_parameter for more details. The value should be adapted according to the actual traffic of the Wikibase. + +##### properties {#properties} + +Some special properties of the Wikibase. + +###### instance_of {#instance_of} + +The ID of the property "instance of". + +###### subclass_of {#subclass_of} + +The ID of the property "subclass of". + +##### constraints {#constraints} + +Not required. Should be configured if the Wikibase has the [WikibaseQualityConstraints extension](https://www.mediawiki.org/wiki/Extension:WikibaseQualityConstraints) installed. Configurations of constraints consists of IDs of constraints related properties and items. For Wikidata, these IDs are retrieved from [extension.json](https://github.com/wikimedia/mediawiki-extensions-WikibaseQualityConstraints/blob/master/extension.json). To configure this for another Wikibase instance, you should contact an admin of the Wikibase instance to get the content of `extension.json`. + +#### oauth {#oauth} + +Not required. Should be configured if the Wikibase has the [OAuth extension](https://www.mediawiki.org/wiki/Extension:OAuth) installed. + +##### registration_page {#registration_page} + +The page to register an OAuth consumer of the Wikibase. Typically in the form "https://foo.bar/wiki/Special:OAuthConsumerRegistration/propose". + +#### reconciliation {#reconciliation} + +The Wikibase instance must have at least a reconciliation service endpoint linked to it. If there is no reconciliation service for the Wikibase, you can run one with [openrefine-wikibase](https://github.com/wetneb/openrefine-wikibase). + +##### endpoint {#endpoint} + +The default reconciliation service endpoint of the Wikibase instance. The endpoint must contain the "${lang}" variable such as "https://wikidata.reconci.link/${lang}/api", since the reconciliation service is expected to work for different languages. + +#### editgroups {#editgroups} + +Not required. Should be configured if the Wikibase instance has [EditGroups](https://github.com/Wikidata/editgroups) service(s). + +##### url_schema {#url_schema} + +The URL schema used in edits summary. This is used for EditGroups to extract the batch id from a batch of edits and for linking to the EditGroups page of the batch. The URL schema must contains the variable '${batch_id}', such as '([[:toollabs:editgroups/b/OR/${batch_id}|details]])' for Wikidata. + +#### Check the format of the manifest {#check-the-format-of-the-manifest} + +As mentioned above, the manifest should be in the format specified by [wikibase-manifest-schema-v1.json](https://github.com/afkbrb/wikibase-manifest/blob/master/wikibase-manifest-schema-v1.json). You can check the format by adding the manifest directly to OpenRefine, and OpenRefine will complain if there is anything wrong with the format. + +![test-validate-manifest-format](https://user-images.githubusercontent.com/29347603/90506110-52d85d00-e186-11ea-8077-683d2f234c46.gif) diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/new-entities.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/new-entities.md new file mode 100644 index 000000000..8dbc4f362 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/new-entities.md @@ -0,0 +1,104 @@ +--- +id: new-entities +title: Creating new items +sidebar_label: New items +--- + +OpenRefine can create new items. This page explains how they are +generated. + +## Words of caution {#words-of-caution} + +- The fact that OpenRefine does not propose any item when reconciling + a cell does not mean that the item is not present in the Wikibase instance: + it can be missed for all sorts of reasons. Please make + sure that you are not creating any duplicates! + +- Make sure that the items that you want to create are admissible in + the Wikibase instance. For Wikidata, see the [notability guidelines](https://www.wikidata.org/wiki/Wikidata:Notability); + +- Deleting items generally requires special rights: if you want to revert an + edit group that includes new items in Wikidata, you will need to ask an + administrator to do it. + +## Workflow overview {#workflow-overview} + +Here is how you would typically create new items with OpenRefine: + +- Reconcile a column; +- Mark some of its cells as new items. This will not create items yet. + If you need to mark many rows as new items, use the **Reconcile** → + **Actions** → **Create a new item for each cell** operation. +- Create a Wikibase schema as usual, using the column where your new + items are marked; +- Perform the edits: the new items will be created on Wikidata at this + point; +- The cells that you had marked as new items will now be reconciled to + the newly-created items. + +It is often useful (but not mandatory) to treat new items in isolation +and use a dedicated schema for them. This helps you add many statements +on the new items (including labels and descriptions) without risking to +clutter existing items with redundant edits. Use a facet on the judgment +status of the reconciled column to isolate new items and perform their +edits separately. As always in OpenRefine, only the rows covered by your +facets will be considered when uploading the edits to Wikidata: if a +cell is reconciled to a new item but is excluded by the facet, no new +item will be created for it.[^1] + +Note that even if you know that all items in your column are new, you +will still need to make a first reconciliation pass by selecting the +Wikidata reconciliation service, and then setting all reconciliation +statuses to \"new\". If you skip the first part, OpenRefine will not +know that this column is reconciled against your Wikibase instance (it could be +reconciled to other services) so it will not let you use it in place of +an item in a Wikibase schema. + +You can also perform the edits with QuickStatements - in this case, your +OpenRefine project will not be updated with the newly created Qids. + +## Adding labels to new items {#adding-labels-to-new-items} + +The text that is in a cell reconciled to \"new\" is not automatically +used as label for the newly-created item. This is because OpenRefine has +no way to guess in which language this label should be. When adding new +items, you need to explicitly add a label in the schema. This label can +use the reconciled column as source, but if you have other cells matched +to existing items, be careful not to override the labels of these items +(if it is not your intention). + +OpenRefine will refuse to perform edits where new items are created +without any labels (as this is considered a critical issue). Other +issues will be raised if insufficient basic information is added on the +items (but these other warnings will not prevent you from performing the +edits). + +## Marking multiple cells as identical items {#marking-multiple-cells-as-identical-items} + +If you mark individual cells as new items, one new item per cell will be +created. Sometimes multiple rows refer to the same item. OpenRefine +makes it possible to mark all the corresponding cells as the *same* new +item. Two conditions have to be met: +- the reconciled cells must be in the same column (it is not possible + to mark two cells in different colums as the same new item); +- the cells must contain the same initial text value. + +If these two conditions are met, then isolate these cells with facets +and go to **Reconcile** → **Actions** → **Create one item for similar +cells**. This will mark the cells as new and referring to the same item. + +## Retrieving the Qids of the newly-created items {#retrieving-the-qids-of-the-newly-created-items} + +Once you have performed your edits with OpenRefine, any new cells +covered by the facet will be updated with their new Qids. You can +retrieve these Qids with the **Edit column** → **Add column based on +this column** action and using the `cell.recon.match.id` expression. +Note that you will no longer be able to isolate new items with a +judgment facet at this stage (because the judgment will be updated to +**matched**) so it can be worth marking these rows (for instance with a +star or flag) before performing the edits. + +[^1]: The only exception to this rule is when marking multiple cells as + identical items: in this case, if one of such cells are included in + the facet, then all the others will be updated with the newly + created Qid once the edits are made. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/overview.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/overview.md new file mode 100644 index 000000000..a202101fd --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/overview.md @@ -0,0 +1,134 @@ +--- +id: overview +title: Overview of Wikibase support +sidebar_label: Overview +--- + +[Wikibase](https://wikiba.se/) is a platform for collaborative knowledge base editing. Its flagship instance [Wikidata](https://www.wikidata.org/) offers structured data about the world and can be edited by anyone. OpenRefine provides powerful ways to both pull data from Wikibase and add data to it. + +OpenRefine's Wikibase integration is provided by an extension which is available by default in OpenRefine. In this page, we present the functionalities for Wikidata, but [any Wikibase instance can be connected to OpenRefine](./configuration) to obtain a similar integration. + +## Editing Wikidata with OpenRefine {#editing-wikidata-with-openrefine} + +As a user-maintained data source, Wikidata can be edited by anyone. OpenRefine makes it simple to upload information in bulk. You simply need to get your information into the correct format, and ensure that it is new (not redundant to information already on Wikidata) and does not conflict with existing Wikidata information. + +You do not need a Wikidata account to reconcile your local OpenRefine project to Wikidata, but to upload your cleaned dataset to Wikidata, you will need an [autoconfirmed](https://www.wikidata.org/wiki/Wikidata:Autoconfirmed_users) account, and you must [authorize OpenRefine with that account](#manage-wikidata-account). + +Wikidata is built by creating entities (such as people, organizations, or places, identified with unique numbers starting with Q), defining properties (unique numbers starting with P), and using properties to define relationships between entities (a Q has a property P, with a value of another Q). + +For example, you may wish to create entities for local authors and the books they've set in your community. Each writer will be an entity with the occupation [author (Q482980)](https://www.wikidata.org/wiki/Q482980), each book will be an entity with the property “instance of†([P31](https://www.wikidata.org/wiki/Property:P31)) linking it to a class such as [literary work (Q7725634)](https://www.wikidata.org/wiki/Q7725634), and books will be related to authors through a property [author (P50)](https://www.wikidata.org/wiki/Property:P50). Books can have places where they are set, with the property [narrative location (P840)](https://www.wikidata.org/wiki/Property:P840). + +To do this with OpenRefine, you'll need a column of publication titles that you have reconciled (and create new items where needed); each publication will have one or more locations in a “setting†column, which is also reconciled to municipalities or regions where they exist (and create new items where needed). Then you can add those new relationships, and create new entities for authors, books, and places where needed. You do not need columns for properties; those are defined later, in the creation of your [schema](#edit-wikidata-schema). + +There is a list of [tutorials and walkthroughs on Wikidata](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing) that will allow you to see the full process. You can save your schemas and drafts in OpenRefine, and your progress stays in draft until you are ready to upload it to Wikidata. + +Batches of edits to Wikidata that are created with OpenRefine can be undone. You can test out the uploading process by reconciling to several “sandbox†entities created specifically for drafting edits and learning about Wikidata: +* https://www.wikidata.org/wiki/Q4115189 +* https://www.wikidata.org/wiki/Q13406268 +* https://www.wikidata.org/wiki/Q15397819 +* https://www.wikidata.org/wiki/Q64768399 + +If you upload edits that are redundant (that is, all the statements you want to make have already been made), nothing will happen. If you upload edits that conflict with existing information (such as a different birthdate than one already in Wikidata), it will be added as a second statement. OpenRefine produces no warnings as to whether your data replicates or conflicts with existing Wikidata elements. + +You can use OpenRefine's reconciliation preview to look at the target Wikidata elements and see what information they already have, and whether the elements' histories have had similar edits reverted in the past. + +### Wikidata schema {#wikidata-schema} + +A [schema](https://en.wikipedia.org/wiki/Database_schema) is a plan for how to structure information in a database. In OpenRefine, the schema operates as a template for how Wikidata edits should be applied: how to translate your tabular data into statements. With a schema, you can: +* preview the Wikidata edits and inspect them manually; +* analyze and fix any issues highlighted by OpenRefine; +* upload your changes to Wikidata by logging in with your own account; +* export the changes to the QuickStatements v1 format. + +For example, if your dataset has columns for authors, publication titles, and publication years, your schema can be conceptualized as: [publication title] has the author [author], and was published in [publication year]. To establish these facts, you need to establish one or more columns as “items,†for which you will make “statements†that relate them to other columns. + +You can export any schema you create, and import an existing schema for use with a new dataset. This can help you work in batches on a large amount of data while minimizing redundant labor. + +Once you select Edit Wikidata schema under the Extensions dropdown menu, your project interface will change. You’ll see new tabs added to the right of “X rows/records" in the grid header: “Schema,†“Issues,†and “Preview.†You can now switch between the tabular grid format of your dataset and the screens that allow you to prepare data for uploading. + +OpenRefine presents you with an easy visual way to map out the relationships in your dataset. Each of the columns of your project will appear at the top of the sceren, and you can simply drag and drop them into the appropriate slots. To get start, select one column as an item. + +![A screenshot of the schema construction window in OpenRefine.](/img/wikidata-schema.png) + +You may wish to refer to [this Wikidata tutorial on how OpenRefine handles Wikidata schema](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing/Tutorials/Basic_editing). For details about how each data type is handled in the Wikibase schema, see [Schema alignment](./schema-alignment). + +#### Editing terms with your schema {#editing-terms-with-your-schema} + +With OpenRefine, you can edit the terms (labels, aliases, descriptions, or sitelinks) of Wikidata entities as well as establish relationships between entities. For example, you may wish to upload pseudonyms, pen names, maiden names, or married names for authors. + +![An author with a number of aliases indicating pseudonyms.](/img/wikidata-terms.png) + +You can do so by putting the preferred names in one column of your dataset and alternative names in another column. In the schema interface, add an item for the preferred values, then click “Add term†on the right-hand side of the screen. Select “Alias†from the dropdown, enter in “English†in the language field, and drop your alternative names column into the space. For this example, you should also consider adding those alternative names to the authors' entries using the property [pseudonym (P742)](https://www.wikidata.org/wiki/Property:P742). The "description" and "label" terms can only contain one value, so there is an option to override existing values if needed. Aliases can be potentially infinite. + +![The schema window showing a term being edited.](/img/wikidata-terms2.png) + +Terms must always have an associated language. You can select the term's language by typing in the “lang†field, which will auto-complete for you. You cannot edit multiple languages at once, unless you supply a suitable column instead. For example, suppose you had translated publication titles, with data in the following format: + +|English title|Translated title|Translation language| +|---|---|---| +|Possession|Besessen|German| +||Обладать|Russian| +|Disgrace|Disgrâce|French| +||Vergogna|Italian| +|Wolf Hall|En la corte del lobo|Spanish| +||ウルフ・ホール|Japanese| + +You could upload the “Translated titles†to “Label†with the language specified by “Translation language.†You may wish to fetch the two-letter language code and use that instead for better language matches. + +![Constructing a schema with aliases and languages.](/img/wikidata-translated.png) + +### Manage Wikidata account {#manage-wikidata-account} + +To edit Wikidata directly from OpenRefine, you must log in with a Wikidata account. OpenRefine can only upload edits with Wikidata user accounts that are “[autoconfirmed](https://www.wikidata.org/wiki/Wikidata:Autoconfirmed_users)†- at this time, that means accounts that have more than 50 edits and have existed for longer than four days. + +Use the Extensions menu to select Manage Wikidata account and you will be presented with the following window: + +![The Wikidata authorization window in OpenRefine.](/img/wikidata-login.png) + +For security reasons, you should not use your main account authorization with OpenRefine. Wikidata allows you to set special passwords to access your account through software. You can find [this setting for your account here](https://www.wikidata.org/wiki/Special:BotPasswords) once logged in. Creating bot access will prompt you for a unique name. You should then enable the following required settings: +* High-volume editing +* Edit existing pages +* Create, edit, and move pages + +It will then generate a username (in the form of “yourwikidatausername@yourbotnameâ€) and password for you to use with OpenRefine. + +If your account or your bot is not properly authorized, OpenRefine will not display a warning or error when you try to upload your edits. + +You can store your unencrypted username and password in OpenRefine, saved locally to your computer and available for future use. For security reasons, you may wish to leave this box unchecked. You can also save your OpenRefine-specific bot password in your browser or with a password management tool. + +### Import and export schema {#import-and-export-schema} + +You can save time on repetitive processes by defining a schema on one project, then exporting it and importing for use on new datasets in the future. Or you and your colleagues can share a schema with each other to coordinate your work. + +You can export a schema from a project using Export → Wikidata schema, or by using Extensions → Export schema. OpenRefine will generate a JSON file for you to save and share. You may experience issues with pop-up windows in your browser: consider allowing pop-ups from the OpenRefine URL (`127.0.0.1`) from now on. + +You can import a schema using Extensions → Import schema. You can upload a JSON file, or paste JSON statements directly into a field in the window. An imported schema will look for columns with the same names, and you will see an error message if your project doesn't contain matching columns. + +### Upload edits to Wikidata {#upload-edits-to-wikidata} + +There are two menu options in OpenRefine for applying your edits to Wikidata, and the details of the differences between the two can be found in the [Uploading page](./uploading). Under Export you will see Wikidata edits... and under Extensions you will see Upload edits to Wikidata. Both will bring up the same window for you to [log in with a Wikidata account](#manage-wikidata-account). + +Once you are authorized, you will see a window with any outstanding issues. You can ignore these issues, but we recommend you resolve them. + +If you are ready to upload your edits, you can provide an “Edit summary†- a short message describing the batch of edits you are making. It can be helpful to leave notes for yourself, such as “batch 1: authors A-G†or other indicators of your workflow progress. OpenRefine will show the progress of the upload as it is happening, but does not show a confirmaton window. + +If your edits have been successful, you will see them listed on [your Wikidata user contributions page](https://www.wikidata.org/wiki/Special:Contributions/), and on the [Edit groups page](https://editgroups.toolforge.org/). All edits can be undone from this second interface. + +### QuickStatements export {#quickstatements-export} + +Your OpenRefine data can be exported in a format recognized by [QuickStatements](https://www.wikidata.org/wiki/Help:QuickStatements), a tool that creates Wikidata edits using text commands. OpenRefine generates “version 1†QuickStatements commands. + +There are advantages to using QuickStatements rather than uploading your edits directly to Wikidata, including the way QuickStatements resolves duplicates and redundancies. You can learn more on QuickStatements' [Help page](https://www.wikidata.org/wiki/Help:QuickStatements), and on OpenRefine's [Uploading page](https://www.wikidata.org/wiki/Wikidata:Tools/OpenRefine/Editing/Uploading). + +In order to use QuickStatements, you must authorize it with a Wikidata account that is [autoconfirmed](https://www.wikidata.org/wiki/Wikidata:Autoconfirmed_users) (it may appear as “MediaWiki†when you authorize). + +Follow the [steps listed on this page](https://www.wikidata.org/wiki/Help:QuickStatements#Running_QuickStatements). +To prepare your OpenRefine data into QuickStatements, select Export → QuickStatements file, or Extensions → Export to QuickStatements. Exporting your schema from OpenRefine will generate a text file called `statements.txt` by default. Paste the contents of the text file into a new QuickStatements batch using version 1. You can find [version 1 of the tool (no longer maintained) here](https://wikidata-todo.toolforge.org/quick_statements.php). The text commands will be processed into Wikidata edits and previewed for you to review before submitting. + +### Issue detection {#issue-detection} + +This section is an overview of the [Quality assurance page](./quality-assurance). + +OpenRefine will analyze your schema and make suggestions. It does not check for conflicts in your proposed edits, or tell you about redundancies. + +One of the most common suggestions is to attach [a reference to your edits](https://www.wikidata.org/wiki/Help:Sources) - a citation for where the information can be found. This can be a book or newspaper citation, a URL to an online page, a reference to a physical source in an archival or special collection, or another source. If the source is itself an item on Wikidata, use the relationship [stated in (P248)](https://www.wikidata.org/wiki/Property:P248); otherwise, use [reference URL (P854)](https://www.wikidata.org/wiki/Property:P854) to identify an external source. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/quality-assurance.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/quality-assurance.md new file mode 100644 index 000000000..a8ead43e3 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/quality-assurance.md @@ -0,0 +1,48 @@ +--- +id: quality-assurance +title: Quality assurance for Wikibase uploads +sidebar_label: Quality assurance +--- + +This page explains how the Wikidata extension of OpenRefine analyzes edits before they are uploaded to the Wikibase +instance. Most of these checks rely on the use of the [Wikibase Quality Constraints](https://gerrit.wikimedia.org/g/mediawiki/extensions/WikibaseQualityConstraints) extension and the configuration of the property and item identifiers in the [Wikibase manifest](./configuration). + +## Overview {#overview} + +Changes are scrutinized before they are uploaded, but also before the current content of the corresponding items is retrieved and merged with the updates. This means that some constraint violations cannot be predicted by the software (for instance, adding a new statement that conflicts with an existing statement on the item). However, this makes it possible to run the checks quickly, even for relatively large batches of edits. Issues are therefore refreshed in real time while the user builds the schema. + +As a consequence, not all constraint violations can be detected: the ones that are supported are listed in the [Constraint violations](#constraint-violations) section. Conversely, not all issues reported will be flagged as constraint violations on the Wikibase site: see [Generic issues](#generic-issues) for these. + +## Reconciliation {#reconciliation} + +You should always assess the quality of your reconciliation results first. OpenRefine has various tools for quality assurance of reconciliation results. For instance: + +* you can analyze the string similarity between your original names and those of the reconciled items (for instance with Reconcile → Facets → Best candidate's name edit distance); +* you can compare the values in your table with those on the items (via a text facet defined by a custom expression); +* you can facet by type on the reconciled items (add a new column with the types and use a text facet ordered by counts to get a sense of the distribution of types in your reconciled items). + +## Constraint violations {#constraint-violations} + +Constraints are retrieved as defined on the properties, using [ (P2302)](https://www.wikidata.org/wiki/Property:P2302). + +The following constraints are supported: +* [format constraint (Q21502404)](https://www.wikidata.org/wiki/Q21502404), checked on all values +* [inverse constraint (Q21510855)](https://www.wikidata.org/wiki/Q21510855): OpenRefine assumes that the inverses of the candidate statements are not in Wikidata yet. If you know that the inverse statements are already in Wikidata, you can safely ignore this issue. +* [used for values only constraint (Q21528958)](https://www.wikidata.org/wiki/Q21528958), [used as qualifier constraint (Q21510863)](https://www.wikidata.org/wiki/Q21510863) and [used as reference constraint (Q21528959)](https://www.wikidata.org/wiki/Q21528959) +* [allowed qualifiers constraint (Q21510851)](https://www.wikidata.org/wiki/Q21510851) +* [required qualifier constraint (Q21510856)](https://www.wikidata.org/wiki/Q21510856) +* [single-value constraint (Q19474404)](https://www.wikidata.org/wiki/Q19474404): this will only trigger if you are adding more than one statement with the property on the same item, but will not detect any existing statement with this property. +* [distinct values constraint (Q21502410)](https://www.wikidata.org/wiki/Q21502410): similarly, this only checks for conflicts inside your edit batch. + +A comparison of the supported constraints with respect to other implementations is available [here](https://www.wikidata.org/wiki/Wikidata:WikiProject_property_constraints/reports/implementations). + +## Generic issues {#generic-issues} + +OpenRefine also detects issues that are not flagged (yet) by constraint violations on Wikidata: +* Statements without references. This does not rely on [citation needed constraint (Q54554025)](https://www.wikidata.org/wiki/Q54554025): all statements are expected to have references. (The idea is that when importing a dataset, every statement you add +* should link to this dataset - it does not hurt to do it even for generic properties such as [instance of (P31)](https://www.wikidata.org/wiki/Property:P31).) +* Spurious whitespace and non-printable characters in strings (including labels, descriptions and aliases); +* Self-referential statements (statements which mention the item they belong to); +* New items created without any label; +* New items created without any description; +* New items created without any [instance of (P31)](https://www.wikidata.org/wiki/Property:P31) or [subclass of (P279)](https://www.wikidata.org/wiki/Property:P279) statement. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/reconciling.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/reconciling.md new file mode 100644 index 000000000..0e5625c9f --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/reconciling.md @@ -0,0 +1,45 @@ +--- +id: reconciling +title: Reconciling with Wikibase +sidebar_label: Reconciling with Wikibase +--- + +The Wikidata [reconciliation service](reconciling) for OpenRefine [supports](https://reconciliation-api.github.io/testbench/): +* A large number of potential types to reconcile against +* Previewing and viewing entities +* Suggesting entities, types, and properties +* Augmenting your project with more information pulled from Wikidata. + +You can find documentation and further resources on the reconciliation API [here](https://wikidata.reconci.link/). + +For the most part, Wikidata reconciliation behaves the same way other reconciliation services do, but there are a few processes and features specific to Wikidata. + +## Language settings {#language-settings} + +You can install a version of the Wikidata reconciliation service that uses your language. First, you need the language code: this is the [two-letter code found on this list](https://en.wikipedia.org/wiki/List_of_Wikipedias), or in the domain name of the desired Wikipedia/Wikidata (for instance, “fr†if your Wikipedia is https://fr.wikipedia.org/wiki/). + +Then, open the reconciliation window (under Reconcile → Start reconciling...) and click Add Standard Service. The URL to enter is `https://wikidata.reconci.link/fr/api`, where “fr†is your desired language code. + +When reconciling using this interface, items and properties will be displayed in your chosen language if the label is available. The matching score of the reconciliation is not influenced by your choice of language for the service: items are matched by considering all labels and returning the best possible match. The language of your dataset is also irrelevant to your choice of language for the reconciliation service; it simply determines which language labels to return based on the entity chosen. + +## Restricting matches by type {#restricting-matches-by-type} + +In Wikidata, types are items themselves. For instance, the [university of Ljubljana (Q1377)](https://www.wikidata.org/wiki/Q1377) has the type [public university (Q875538)](https://www.wikidata.org/wiki/Q875538), using the [instance of (P31)](https://www.wikidata.org/wiki/Property:P31) property. Types can be subclasses of other types, using the [subclass of (P279)](https://www.wikidata.org/wiki/Property:P279) property. For instance, [public university (Q875538)](https://www.wikidata.org/wiki/Q875538) is a subclass of [university (Q3918)](https://www.wikidata.org/wiki/Q3918). You can visualize these structures with the [Wikidata Graph Builder](https://angryloki.github.io/wikidata-graph-builder/). + +When you select or enter a type for reconciliation, OpenRefine will include that type and all of its subtypes. For instance, if you select [university (Q3918)](https://www.wikidata.org/wiki/Q3918), then [university of Ljubljana (Q1377)](https://www.wikidata.org/wiki/Q1377) will be a possible match, though that item isn't directly linked to Q3918 - because it is directly linked to Q875538, the subclass of Q3918. + +Some items and types may not yet be set as an instance or subclass of anything (because Wikidata is crowdsourced). If you restrict reconciliation to a type, items without the chosen type will not appear in the results, except as a fallback, and will have a lower score. + +## Reconciling via unique identifiers {#reconciling-via-unique-identifiers} + +You can supply a column of unique identifiers (in the form "Q###" for entities) directly to Wikidata in order to pull more data, but [these strings will not be “reconciled†against the external dataset](reconciling#reconciling-with-unique-identifiers). Apply the operation Reconcile → Use values as identifiers on your column of QIDs. All cells will appear as dark blue “confirmed†matches. Some of the “matches†may be errors, which you will need to hover over or click on to identify. You cannot use this to reconcile properties (in the form "P###"). + +If the identifier you submit is assigned to multiple Wikidata items (because Wikidata is crowdsourced), all of the items are returned as candidates, with none automatically matched. + +## Property paths, special properties, and subfields {#property-paths-special-properties-and-subfields} + +Wikidata's hierarchical property structure can be called by using property paths (using |, /, and . symbols). Labels, aliases, descriptions, and sitelinks can also be accessed. You can also match values against subfields, such as latitude and longitude subfields of a geographical coordinate. + +For information on how to do this, read the [documentation and further resources here](https://wikidata.reconci.link/#documentation). + + diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/schema-alignment.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/schema-alignment.md new file mode 100644 index 000000000..112c1a45c --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/schema-alignment.md @@ -0,0 +1,253 @@ +--- +id: schema-alignment +title: Schema alignment +sidebar_label: Schema alignment +--- + +A Wikibase schema is a template of Wikidata edits that is applied +to each row in the project. This page describes how each part of this +template works, and how it generates edits depending on the contents of +the table cells. + +## Items {#items} + +An item in the schema represents a set of changes on a particular +Wikidata item, generated by a single row. This item can contain changes +in [terms](#terms) (labels, descriptions and aliases) or +[statements](#statements). + +It is possible to make edits on different items for each row of your +table: just add multiple items in your schema. Each item has a subject, +which can be either entered manually (when the item on which the edits +should be made is the same for all rows), or any reconciled column can +be dropped in this field. In this case, the edits will depend on the +reconciliation status of each cell: + +- If the cell is matched to an item, edits will be made on that item; +- If the cell is marked as corresponding to a new item, a new item + will be created for it. See [New items](./new-entities) for more + details about how this works; +- If the cell has reconciliation candidates but has not been matched + to any of them, the edit will be skipped (even if there is only one + candidate with a high reconciliation score); +- If the cell is not reconciled or blank, the edit will be skipped. + +Do not worry about the ordering of items in the schema or the order of +your rows, as OpenRefine will rearrange your edits to optimize their +upload. If your project makes edits on the same item across multiple +rows, these edits will be merged together and performed in one edit. See +[Uploading your changes](./uploading) about that. + +## Terms {#terms} + +**Terms** are the language-specific strings that you find at the top of +Wikidata items: labels, descriptions and aliases. OpenRefine lets you +edit these terms via the Wikidata schema. + +### Languages {#languages} + +Each term belongs to a particular language. Wikidata supports [hundreds +of languages](https://www.wikidata.org/wiki/Help:Wikimedia_language_codes/lists/all), which +are designated by language codes. For each term that you want to add to +an item, you will need to specify the language for this term. There are +two cases: + +- Either the language is constant across your dataset: you know that + all the names in a given column are spelled in the same language. In + this case, type the name of the language in the input and select the + language in the drop-down suggestion dialog. This will place the + appropriate language code in the input. +- Or the language varies across your dataset. In this case, you need + to provide a column of Wikimedia language codes that indicates the + language for each term that you want to add. Just drag and drop this + column to the language field. If there are any invalid language + codes in this column, the corresponding terms will be ignored. + OpenRefine will translate any deprecated language codes to their + preferred values silently. + +### Labels {#labels} + +This is because Wikidata items can have at most one label per language, +so you need to choose whether to override any existing label (default +behaviour before 3.2) or only insert your label if there is no such +label in the given language (default behaviour starting from 3.2). When +the content of the cell providing the label is blank, nothing will be +changed (so, it is not possible to remove labels). + +### Descriptions {#descriptions} + +Descriptions work like labels: there is at most one description per +language, and OpenRefine can override existing descriptions or leave +them unchanged. It is not possible to remove descriptions either. + +### Aliases {#aliases} + +Aliases are added to the list of existing aliases in the given language. +When adding an alias in a language where no label has been added yet, +the alias is automatically promoted to a label for this language. It is +not possible to remove aliases or to override any existing aliases. + +## Statements {#statements} + +You can add statements in the schema: this will generate new statements +on the corresponding items. These statements will be merged with any +existing statements on the actual Wikidata items and [this merging process depends on the upload medium](./uploading#Merging-strategies-for-statements). +It is forecast to give more control over the merging strategy in the +near future. + +### Main values {#main-values} + +Statements must have main values: \"novalue\" or \"somevalue\" +statements are not supported yet. The main value of a statement is a +data value whose type depends on the property used for the statement. If +the main value cannot be evaluated (for instance because one of the +cells it depends on is empty), then the entire statement will be +skipped. + +See the [data values](#data-values) section for more details +about how to specify each type of data value and when they are skipped. + +### Qualifiers {#qualifiers} + +Qualifiers can be added on each statement. When their values are +skipped, only the qualifier will be discarded: the rest of the statement +will still be added. + +### References {#references} + +References can (and should) be added to back each statement. If values +inside the reference are skipped, the corresponding part of the +reference will be discarded but the reference will still be added +(unless the reference becomes empty). + +### Ranks {#ranks} + +All statements ranks are set to **Normal**. It is currently not possible +to set a different rank. + +## Data values {#data-values} + +Data values are the data that you can find as target of a statement (or +qualifier, or part of a reference). Each property dictates a particular +type of data value. In each case, OpenRefine uses a particular process +to translate cell contents to a data value of the appropriate type. This +section explains the process for all data types. + +### Items {#items-1} + +Items are evaluated in the same way as the subjects of items in the +schema. They can be input directly using the auto-suggest service +provided, or any column reconciled against Wikidata can be used. Refer to +[the first Items section](#items) to see how they are +evaluated. + +### Strings and external identifiers {#strings-and-external-identifiers} + +Bare strings and external identifiers can be input directly as constants +(if they do not change across rows) or using any column. If a reconciled +column is used for a string value, it is the value of the cell that is +going to be used, not the name of the reconciled item (which is what +OpenRefine displays). Values are skipped when the column is blank or +null. + +### Monolingual texts {#monolingual-texts} + +Monolingual texts consist of two parts: + +- the language: see [Languages](#languages) for their + structure; +- the value of the text: see [the section above](#strings-and-external-identifiers). + +A monolingual text is skipped when any of its parts is skipped (that is, +if the language or the text are invalid). + +### Dates {#dates} + +Dates are parsed from cell contents (or from any constant provided in +the schema) and the precision of the date is inferred from its format. +Here are the valid formats: + +- `YYYYM`, such as `2001M` (millenium precision) +- `YYYYC`, such as `1901C` (century precision) +- `YYYYD`, such as `1981D` (decade precision) +- `YYYY`, such as `1984` (year precision) +- `YYYY-MM`, such as `2019-03` (month precision) +- `YYYY-MM-DD`, such as `1897-08-14` (day precision) + +Any value that does not match any of these formats will be ignored. All +dates are represented in UTC, Gregorian calendar. + +In OpenRefine 3.3, the following new formats have been introduced: + +- `TODAY` returns today's date with day precision. This will be + evaluated when performing the edits (or exporting to + QuickStatements); +- `YYYY-MM-DD_QID` can be used to specify a date in a particular + calendar (such as the [proleptic Julian calendar (Q1985786)](https://www.wikidata.org/wiki/Q1985786). + +In OpenRefine 3.5, the following new format has been introduced: + +- `-234` represents the year 234 [BCE](https://en.wikipedia.org/wiki/Common_Era) + +### Quantities {#quantities} + +Quantities consist of two parts: the amount and the unit. + +- the amount is mandatory and must be a string, such as `18,229.1020`. + The precision that is displayed will be respected (the same number + of trailing zeros will be shown in Wikidata). By default, no upper + and lower bounds will be set. To define these, one needs to use the + engineering notation, such as `3.45E+3`, which will be interpreted + as `3,450±5`. As usual, the amount can be provided as a constant or + as a column variable. In the latter case, the values in the column + must be strings. +- the unit is optional. It is an item, so it can be provided either + with the auto-suggest dialog or as a reconciled column. It is + important to note that if a reconciled column is used, any + unreconciled cells will discard the entire quantity value. So a + template for a quantity value is either always unit-less, or always + has a unit. + +### Globe coordinates {#globe-coordinates} + +Geographic coordinates are specified as strings with the following +formats, where all components are floating point numbers in degrees: + +- `latitude,longitude` for a default precision of ten micro degrees + (for instance: + [`49.265278,4.028611`](https://tools.wmflabs.org/geohack/geohack.php?params=49.265277777778_N_4.0286111111111_E_globe:earth&language=en) + can be used indicate the position of Reims, France. + + +- `latitude,longitude,precision` when specifying an explicit precision + (for instance: `49.265278,4.028611,0.1` can be used indicate the + position of Reims within a tenth of a degree). + +All globe coordinates are on Earth ([Q2](https://www.wikidata.org/wiki/Q2)). + +If your coordinates are in a different format, such as +`49° 15′ 55″ N, 4° 1′ 43″ E`, you will need to convert them to decimal +format first. + +### Media on Commons {#media-on-commons} + +Media on Wikimedia Commons is treated like strings, whose values must +exactly match filenames on Commons. These values are not checked during +schema evaluations: if they are wrong, uploading the statements will +fail. + +Tabular data and Geoshapes must be prefixed with the `Data:` namespace. +This is indicated by the placeholder in the field that appears when +constructing the schema. + +### Properties {#properties} + +Properties are always constants: there is currently no way to reconcile +a column against properties. They have to be selected with the +auto-suggest dialog. + +### Other data types {#other-data-types} + +URLs, mathematical expressions and other textual datatypes are supported +and treated as strings. At the time of writing, all datatypes supported +by Wikidata are supported by OpenRefine. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/uploading.md b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/uploading.md new file mode 100644 index 000000000..99da1259d --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/manual/wikibase/uploading.md @@ -0,0 +1,48 @@ +--- +id: uploading +title: Uploading edits to Wikibase +sidebar_label: Uploading edits +--- + +This page explains how to upload your edits to the target Wikibase. It assumes you already have a created a Wikibase schema in your OpenRefine project. + +## Uploading with OpenRefine {#uploading-with-openrefine} + +* Click Wikidata → Upload edits to Wikidata. +* Log in with your personal account or your bot account depending on which account you want to use to make the edits. It is a good practice to use a [bot password](https://www.mediawiki.org/wiki/Manual:Bot_passwords). +* Supply a meaningful edit summary. This is especially important because OpenRefine condenses all your changes on the same item as one edit: if you are making multiple changes, the edit summary generated by Wikibase will not indicate clearly what sort of change you made. If you are making atomic changes, such as adding a single alias or statement, the automatic edit summaries will be more meaningful. If supported by your Wikibase instance, OpenRefine will append a link to the [EditGroups](https://editgroups.toolforge.org/) tool, which lets you track and analyze your edit batch after upload. +* Click Perform edits and wait for the operation to complete. You can watch your edits being made by checking your wiki contributions or the EditGroups tool. + +Because performing edits in OpenRefine counts as an operation, you can extract this operation and reapply it to other projects. If you do so, you should also include the operation that saves the schema (only the last one is required), and make sure that the column names in the schema match those of the OpenRefine project where you are applying the operation. + +## Uploading with QuickStatements {#uploading-with-quickstatements} + +This requires that the Wikibase site has an associated [QuickStatements](https://meta.wikimedia.org/wiki/QuickStatements) tool. + +* Click Wikibase → Export to QuickStatements and copy the contents of the file; +* Go to QuickStatements (for Wikidata it can be found at https://quickstatements.toolforge.org/) and login to authorize the tool to use your account; +* Click Version 1 format; +* Paste the generated changes in the text area; +* Perform the edits with Run or Run in background. + +## Notable differences between the two methods {#notable-differences-between-the-two-methods} + +### Merging strategy for statements {#merging-strategy-for-statements} + +OpenRefine checks for existing statements which match not only the property and the target value, but also the qualifiers. On the other hand, QuickStatements ignores qualifiers when matching statements. +Both merging strategies can be useful depending on the properties. It is forecast to let the user configure the matching method in OpenRefine. + +If references are provided, both tools merge references in matching statements. + +### New item creation {#new-item-creation} + +OpenRefine supports creating new items with arbitrary relations between them. + +QuickStatements supports creating new items with the CREATE instruction, and subsequent instructions can use the LAST placeholder to use the Qid of the last created item. When generating QuickStatements instructions, OpenRefine reorders your edits so that this syntax can be used. In rare cases, such as when a statement links two newly-created items, it is impossible to use QuickStatements to perform the edit. In this case, no QuickStatements script will be generated. + +### Speed and number of edits {#speed-and-number-of-edits} + +OpenRefine generally performs one edit per item touched by an edit batch and at most two in general (in the case where new items contain links between them). This was chosen to minimize server load, speed up the upload and keep item histories compact. The downside is that the edit summaries can be less meaningful - it is therefore important that users supply informative summaries when uploading their batches. OpenRefine asymptotically edits at the rate of 60 edits per minute (so, usually 60 items per minute). The first edits are made more quickly, which is convenient for small batches. + +QuickStatements performs incremental edits (for instance, when adding a statement with a qualifier and a reference, it will make three edits). That generally means lower speed, but more explicit item histories. + diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/architecture.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/architecture.md new file mode 100644 index 000000000..e80d7015a --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/architecture.md @@ -0,0 +1,283 @@ +--- +id: architecture +title: Architecture +sidebar_label: Architecture +--- + +OpenRefine is a web application, but is designed to be run locally on your own machine. The server-side maintains states of the data (undo/redo history, long-running processes, etc.) while the client-side maintains states of the user interface (facets and their selections, view pagination, etc.). The client-side makes GET and POST ajax calls to cause changes to the data and to fetch data and data-related states from the server-side. + +This architecture provides a good separation of concerns (data vs. UI); allows the use of familiar web technologies (HTML, CSS, Javascript) to implement user interface features; and enables the server side to be called by third-party software through standard GET and POST operations. + +## Technology stack {#technology-stack} + +The server-side part of OpenRefine is implemented in Java as one single servlet which is executed by the [Jetty](http://jetty.codehaus.org/jetty/) web server + servlet container. The use of Java strikes a balance between performance and portability across operating systems (there is very little OS-specific code and has mostly to do with starting the application). + +OpenRefine has no database. It uses its own in-memory data-store that is built up-front to be optimized for the operations required by faceted browsing and infinite undo. + +The client-side part of OpenRefine is implemented in HTML, CSS and Javascript and uses the following libraries: +* [jQuery](http://jquery.com/) +* [jQueryUI](http:jqueryui.com/) +* [Recurser jquery-i18n](https://github.com/recurser/jquery-i18n) + +The functional extensibility of OpenRefine is provided by a fork of the [SIMILE Butterfly](https://github.com/OpenRefine/simile-butterfly) modular web application framework. + +Several projects provide the functionality to read and write custom format files (POI, opencsv, JENA, marc4j). + +String clustering is provided by the [SIMILE Vicino](http://code.google.com/p/simile-vicino/) project. + +OAuth functionality is provided by the [Signpost](https://github.com/mttkay/signpost) project. + +## Server-side architecture {#server-side-architecture} + +OpenRefine's server-side is written entirely in Java (`main/src/`) and its entry point is the Java servlet `com.google.refine.RefineServlet`. By default, the servlet is hosted in the lightweight Jetty web server instantiated by `server/src/com.google.refine.Refine`. Note that the server class itself is under `server/src/`, not `main/src/`; this separation leaves the possibility of hosting `RefineServlet` in a different servlet container. + +The web server configuration is in `main/webapp/WEB-INF/web.xml`; that's where `RefineServlet` is hooked up. `RefineServlet` itself is simple: it just reacts to requests from the client-side by routing them to the right `Command` class in the packages `com.google.refine.commands.**`. + +As mentioned before, the server-side maintains states of the data, and the primary class involved is `com.google.refine.ProjectManager`. + +### Projects {#projects} + +In OpenRefine there's the concept of a workspace similar to that in Eclipse. When you run OpenRefine it manages projects within a single workspace, and the workspace is embodied in a file directory with sub-directories. The default workspace directories are listed in the [FAQs](https://github.com/OpenRefine/OpenRefine/wiki/FAQ-Where-Is-Data-Stored). You can get OpenRefine to use a different directory by specifying a -d parameter at the command line. + +The class `ProjectManager` is what manages the workspace. It keeps in memory the metadata of every project (in the class `ProjectMetadata`). This metadata includes the project's name and last modified date, and any other information necessary to present and let the user interact with the project as a whole. Only when the user decides to look at the project's data would `ProjectManager` load the project's actual data. The separation of project metadata and data is to minimize the amount of stuff loaded into memory. + +A project's _actual_ data includes the columns, rows, cells, reconciliation records, and history entries. + +A project is loaded into memory when it needs to be displayed or modified, and it remains in memory until 1 hour after the last time it gets modified. Periodically the project manager tries to save modified projects, and it saves as many modified projects as possible within 30 seconds. + +### Data Model {#data-model} + +A project's data consists of + +- _raw data_: a list of rows, each row consisting of a list of cells +- _models_ on top of that raw data that give high-level presentation or interpretation of that data. This design lets the same raw data be viewed in different ways by different models, and let the models be changed without costly changes to the raw data. + +#### Column Model {#column-model} + +Cells in rows are not named and can only be addressed by their list position indices. So, a _column model_ is needed to give a name to each list position. The column model also stores other metadata for each column, including the type that cells in the column have been reconciled to and the overall reconciliation statistics of those cells. + +Each column also acts as a cache for data computed from the raw data related to that column. + +Columns in the column model can be removed and re-ordered without changing the raw data--the cells in the rows. This makes column removal and ordering operations really quick. + +##### Column Groups {#column-groups} + +Consider the following data: + +![Illustration of row groups in OpenRefine](https://raw.github.com/OpenRefine/OpenRefine/2.0/graphics/row-groups.png) + +Although the data is in a grid, we humans can understand that it is a tree. First of all, all rows contain data ultimately linked to the movie Austin Powers, although only one row contains the text "Austin Powers" in the "movie title" column. We also know that "USA" and "Germany" are not related to Elizabeth Hurley and Mike Myers respectively (say, as their nationality), but rather, "USA" and "Germany" are related to the movie (where it was released). We know that Mike Myers played both the character "Austin Powers" and the character "Dr. Evil"; and for the latter he received 2 awards. We humans can understand how to interpret the grid as a tree based on its visual layout as well as some knowledge we have about the movie domain but is not encoded in the table. + +OpenRefine can capture our knowledge of this transformation from grid to tree using _column groups_, also stored in the column model. Each column group illustrated as a blue bracket above specifies which columns are grouped together, as well as which of those columns is the key column in that group (blue triangle). One column group can span over columns grouped by another column group, and in this way, column groups form a hierarchy determined by which column group envelopes another. This hierarchy of column groups allows the 2-dimensional (grid-shaped) table of rows and cells to be interpreted as a list of hierarchical (tree-shaped) data records. + +Blank cells play a very important role. The blank cell in a key column of a row (e.g., cell "character" on row 4) makes that row (row 4) _depend_ on the first preceding row with that column filled in (row 3). This means that "Best Comedy Perf" on row 4 applies to "Dr. Evil" on row 3. Row 3 is said to be a _context row_ for row 4. Similarly, since rows 2 - 6 all have blank cells in the first column, they all depend on row 1, and all their data ultimately applies to the movie Austin Powers. Row 1 depends on no other row and is said to be a _record row_. Rows 1 - 6 together form one _record_. + +Currently (as of 12th December 2017) only the XML and JSON importers create column groups, and while the data table view does display column groups but it doesn't support modifying them. + +### Changes, History, Processes, and Operations {#changes-history-processes-and-operations} + +All changes to the project's data are tracked (N.B. this does not include changes to a project's metadata - such as the project name.) + +Changes are stored as `com.google.refine.history.Change` objects. `com.google.refine.history.Change` is an interface, and implementing classes are in `com.google.refine.model.changes.**`. Each change object stores enough data to modify the project's data when its `apply()` method is called, and enough data to revert its effect when its `revert()` method is called. It's only supposed to _store_ data, not to actually _compute_ the change. In this way, it's like a .diff patch file for a code base. + +Some change objects can be huge, as huge as the project itself. So change objects are not kept in memory except when they are to be applied or reverted. However, since we still need to show the user some information about changes (as displayed in the History panel in the UI), we keep metadata of changes separate from the change objects. For each change object there is one corresponding `com.google.refine.history.HistoryEntry` for storing its metadata, such as the change's human-friendly description and timestamp. + +Each project has a `com.google.refine.history.History` object that contains an ordered list of all `HistoryEntry` objects storing metadata for all changes that have been done since after the project was created. Actually, there are 2 ordered lists: one for done changes that can be reverted (undone), an done for undone changes that can be re-applied (redone). Changes must be done or redone in their exact orders in these lists because each change makes certain assumptions about the state of the project before and after it is applied. As changes cannot be undone/redone out of order, when one change fails to revert, it blocks the whole history from being reverted to any state preceding that change (as happened in [Issue #2](https://github.com/OpenRefine/OpenRefine/issues/2)). + +As mentioned before, a change contains only the diff and does not actually compute that diff. The computation is performed by a `com.google.refine.process.Process` object--every change object is created by a process object. A process can be immediate, producing its change object synchronously within a very short period of time (e.g., starring one row); or a process can be long-running, producing its change object after a long time and a lot of computation, including network calls (e.g., reconciling a column). + +As the user interacts with the UI on the client-side, their interactions trigger ajax calls to the server-side. Some calls are meant to modify the project. Those are handled by commands that instantiates processes. Processes are queued in a first-in-first-out basis. The first-in process gets run and until it is done all the other processes are stuck in the queue. + +A process can effect a change in one thing in the project (e.g., edit one particular cell, star one particular row), or a process can effect changes in _potentially_ many things in the project (e.g., edit zero or more cells sharing the same content, starring all rows filtered by some facets). The latter kind of process is generalizable: it is meaningful to apply them on another similar project. Such a process is associated with an _abstract operation_ `com.google.refine.model.AbstractOperation` that encodes the information necessary to create another instance of that process, but potentially for a different project. When you click "extract" in the History panel, these abstract operations are called to serialize their information to JSON; and when you click "apply" in the History panel, the JSON you paste in is used to re-construct these abstract operations, which in turn create processes, which get run sequentially in a queue to generate change object and history entry pairs. + +In summary, + +- change objects store diffs +- history entries store metadata of change objects +- processes compute diffs and create change object and history entry pairs +- some processes are long-running and some are immediate; processes are run sequentially in a queue +- generalizable processes can be re-constructed from abstract operations + +## Client-side architecture {#client-side-architecture} +The client-side part of OpenRefine is implemented in HTML, CSS and Javascript and uses the following Javascript libraries: +* [jQuery](http://jquery.com/) +* [jQueryUI](http:jqueryui.com/) +* [Recurser jquery-i18n](https://github.com/recurser/jquery-i18n) + +### Importing architecture {#importing-architecture} + +OpenRefine has a sophisticated architecture for accommodating a diverse and extensible set of importable file formats and work flows. The formats range from simple CSV, TSV to fixed-width fields to line-based records to hierarchical XML and JSON. The work flows allow the user to preview and tweak many different import settings before creating the project. In some cases, such as XML and JSON, the user also has to select which elements in the data file to import. Additionally, a data file can also be an archive file (e.g., .zip) that contains many files inside; the user can select which of those files to import. Finally, extensions to OpenRefine can inject functionalities into any part of this architecture. + +### The Index Page and Action Areas {#the-index-page-and-action-areas} + +The opening screen of OpenRefine is implemented by the file refine/main/webapp/modules/core/index.vt and will be referred to here as the index page. Its default implementation contains 3 finger tabs labeled Create Project, Open Project, and Import Project. Each tab selects an "action area". The 3 default action areas are for, obviously, creating a new project, opening an existing project, and importing a project .tar file. + +Extensions can add more action areas in Javascript. For example, this is how the Create Project action area is added (refine/main/webapp/modules/core/scripts/index/create-project-ui.js): + +```javascript +Refine.actionAreas.push({ + id: "create-project", + label: "Create Project", + uiClass: Refine.CreateProjectUI +}); +``` + +The UI class is a constructor function that takes one argument, a jQuery-wrapped HTML element where the tab body of the action area should be rendered. + +If your extension requires a very unique importing work flow, or a very novel feature that should be exposed on the index page, then add a new action area. Otherwise, try to use the existing work flows as much as possible. + +### The Create Project Action Area {#the-create-project-action-area} + +The Create Project action area is itself extensible. Initially, it embeds a set of finger tabs corresponding to a variety of "source selection UIs": you can select a source of data by specifying a file on your computer, or you can specify the URL to a publicly accessible data file or data feed, or you can paste in from the clipboard a chunk of data. + +There are actually 3 points of extension in the Create Project action area, and the first is invisible. + +#### Importing Controllers {#importing-controllers} + +The Create Project action area manages a list of "importing controllers". Each controller follows a particular work flow (in UI terms, think "wizard"). Refine comes with a "default importing controller" (refine/main/webapp/modules/core/scripts/index/default-importing-controller/controller.js) and its work flow assumes that the data can be retrieved and cached in whole before getting processed in order to generate a preview for the user to inspect. (If the data cannot be retrieved and cached in whole before previewing, then another importing controller is needed.) + +An importing controller is just programming logic, but it can manifest itself visually by registering one or more data source UIs and one or more custom panels in the Create Project action area. The default importing controller registers 3 such custom panels, which act like pages of a wizard. + +An extension can register any number of importing controller. Each controller has a client-side part and a server-side part. Its client-side part is just a constructor function that takes an object representing the Create Project action area (usually named `createProjectUI`). The controller (client-side) is expected to use that object to register data source UIs and/or create custom panels. The controller is not expected to have any particular interface method. The default importing controller's client-side code looks like this (refine/main/webapp/modules/core/scripts/index/default-importing-controller/controller.js): + +```javascript +Refine.DefaultImportingController = function(createProjectUI) { + this._createProjectUI = createProjectUI; // save a reference to the create project action area + + this._progressPanel = createProjectUI.addCustomPanel(); // create a custom panel + this._progressPanel.html('...'); // render the custom panel + ... do other stuff ... +}; +Refine.CreateProjectUI.controllers.push(Refine.DefaultImportingController); // register the controller +``` + +We will cover the server-side code below. + +#### Data Source Selection UIs {#data-source-selection-uis} + +Data source selection UIs are another point of extensibility in the Create Project action area. As mentioned previously, by default there are 3 data source UIs. Those are added by the default importing controller. + +Extensions can also add their own data source UIs. A data source selection UI object can be registered like so + +```javascript +createProjectUI.addSourceSelectionUI({ + label: "This Computer", + id: "local-computer-source", + ui: theDataSourceSelectionUIObject +}); +``` + +`theDataSourceSelectionUIObject` is an object that has the following member methods: + +- `attachUI(bodyDiv)` +- `focus()` + +If you want to install a data source selection UI that is managed by the default importing controller, then register its UI class with the default importing controller, like so (refine/main/webapp/modules/core/scripts/index/default-importing-sources/sources.js): + +```javascript +Refine.DefaultImportingController.sources.push({ + "label": "This Computer", + "id": "upload", + "uiClass": ThisComputerImportingSourceUI +}); +``` + +The default importing controller will assume that the `uiClass` field is a constructor function and call it with one argument--the controller object itself. That constructor function should save the controller object for later use. More specifically, for data source UIs that use the default importing controller, they can call the controller to kickstart the process that retrieves and caches the data to import: + +```javascript +controller.startImportJob(form, "... status message ..."); +``` + +The argument `form` is a jQuery-wrapped FORM element that will get submitted to the server side at the command /command/core/create-importing-job. That command and the default importing controller will take care of uploading or downloading the data, caching it, updating the client side's progress display, and then showing the next importing step when the data is fully cached. + +See refine/main/webapp/modules/core/scripts/index/default-importing-sources/sources.js for examples of such source selection UIs. While we write about source selection UIs managed by the default importing controller here, chances are your own extension will not be adding such a new source selection UI. Your extension probably adds with a new importing controller as well as a new source selection UI that work together. + +#### File Selection Panel {#file-selection-panel} +Documentation not currently available + +#### Parsing UI Panel {#parsing-ui-panel} +Documentation not currently available + +### Server-side Components {#server-side-components} + +#### ImportingController {#importingcontroller} +Documentation not currently available + +#### UrlRewriter {#urlrewriter} +Documentation not currently available + +#### FormatGuesser {#formatguesser} +Documentation not currently available + +#### ImportingParser {#importingparser} +Documentation not currently available + + +## Faceted browsing architecture {#faceted-browsing-architecture} + +Faceted browsing support is core to OpenRefine as it is the primary and only mechanism for filtering to a subset of rows on which to do something _en masse_ (ie in bulk). Without faceted browsing or an equivalent querying/browsing mechanism, you can only change one thing at a time (one cell or row) or else change everything all at once; both kinds of editing are practically useless when dealing with large data sets. + +In OpenRefine, different components of the code need to know which rows to process from the faceted browsing state (how the facets are constrained). For example, when the user applies some facet selections and then exports the data, the exporter serializes only the matching rows, not all rows in the project. Thus, faceted browsing isn't only hooked up to the data view for displaying data to the user, but it is also hooked up to almost all other parts of the system. + +### Engine Configuration {#engine-configuration} + +As OpenRefine is a web app, there might be several browser windows opened on the same project, each in a different faceted browsing state. It is best to maintain the faceted browsing state in each browser window while keeping the server side completely stateless with regard to faceted browsing. Whenever the client-side needs something done by the server, it transfers the entire faceted browsing state over to the server-side. The faceted browsing state behaves much like the `WHERE` clause in a SQL query, telling the server-side how to select the rows to process. + +In fact, it is best to think of the faceted browsing state as just a database query much like a SQL query. It can be passed around the whole system, to any component needing to know which rows to process. It is serialized into JSON to pass between the client-side and the server side, or to save in an abstract operation's specification. The job of the faceted browsing subsystem on the client-side is to let the user interactively modify this "faceted browsing query", and the job of the faceted browsing subsystem on the server side is to resolve that query. + +In the code, the faceted browsing state, or faceted browsing query, is actually called the *engine configuration* or *engine config* for short. It consists mostly of an array facet configurations. For each facet, it stores the name of the column on which the facet is based (or an empty string if there is no base column). Each type of facet has different configuration. Text search facets have queries and flags for case-sensitivity mode and regular expression mode. Text facets (aka list facets) and numeric range facets have expressions. Each list facet also has an array of selected choices, an invert flag, and flags for whether blank and error cells are selected. Each numeric range facet has, among other things, a "from" and a "to" values. If you trace the AJAX calls, you'd see the engine configs being shuttled, e.g., + +```json +{ + "facets" : [ + { + "type": "text", + "name": "Shrt_Desc", + "columnName": "Shrt_Desc", + "mode": "text", + "caseSensitive": false, + "query": "cheese" + }, + { + "type": "list", + "name": "Shrt_Desc", + "columnName": "Shrt_Desc", + "expression": "grel:value.toLowercase().split(\",\")", + "omitBlank": false, + "omitError": false, + "selection": [], + "selectBlank":false, + "selectError":false, + "invert":false + }, + { + "type": "range", + "name": "Water", + "expression": "value", + "columnName": "Water", + "selectNumeric": true, + "selectNonNumeric": true, + "selectBlank": true, + "selectError": true, + "from": 0, + "to": 53 + } + ], + "includeDependent": false + } +``` + +### Server-Side Subsystem {#server-side-subsystem} + +From an engine configuration like the one above, the server-side faceted browsing subsystem is capable of producing: + +- an iteration over the rows matching the facets' constraints +- information on how to render the facets (e.g., choice and count pairs for a list facet, histogram for a numeric range facet) + +When the engine config JSON arrives in an HTTP request on the server-side, a `com.google.refine.browsing.Engine` object is constructed and initialized with that JSON. It in turns constructs zero or more `com.google.refine.browsing.facets.Facet` objects. Then for each facet, the engine calls its `getRowFilter()` method, which returns `null` if the facet isn't constrained in anyway, or a `com.google.refine.browsing.filters.RowFilter` object. Then, to when iterating over a project's rows, the engine calls on all row filters' `filterRow()` method. If and only if all row filters return `true` the row is considered to match the facets' constraints. How each row filter works depends on the corresponding type of facet. + +To produce information on how to render a particular facet in the UI, the engine follows the same procedure described in the previous except it skips over the facet in question. In other words, it produces an iteration over all rows constrained by the other facets. Then it feeds that iteration to the facet in question by calling the facet's `computeChoices()` method. This gives the method a chance to compute the rendering information for its UI counterpart on the client-side. When all facets have been given a chance to compute their rendering information, the engine calls all facets to serialize their information as JSON and returns the JSON to the client-side. Only one HTTP call is needed to compute all facets. + +### Client-side subsystem {#client-side-subsystem} + +On the client-side there is also an engine object (implemented in Javascript rather than Java) and zero or more facet objects (also in Javascript, obviously). The engine is responsible for distributing the rendering information computed on the server-side to the right facets, and when the user interacts with a facet, the facet tells the engine to update the whole UI. To do so, the engine gathers the configuration of each facet and composes the whole engine config as a single JSON object. Two separate AJAX calls are made with that engine config, one to retrieve the rows to render, and one to re-compute the rendering information for the facets because changing one facet does affect all the other facets. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/build-test-run.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/build-test-run.md new file mode 100644 index 000000000..300784ac8 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/build-test-run.md @@ -0,0 +1,283 @@ +--- +id: build-test-run +title: How to build, test and run +sidebar_label: How to build, test and run +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; + + +You will need: +* [OpenRefine source code](https://github.com/OpenRefine/OpenRefine) +* [Java JDK](http://java.sun.com/javase/downloads/index.jsp) (Get [OpenJDK from here](https://jdk.java.net/15/).) +* [Apache Maven](https://maven.apache.org) (OPTIONAL) +* A Unix/Linux shell environment OR the Windows command line + +From the top level directory in the OpenRefine application you can build, test and run OpenRefine using the `./refine` shell script (if you are working in a \*nix shell), or using the `refine.bat` script from the Windows command line. Note that the `refine.bat` on Windows only supports a subset of the functionality, supported by the `refine` shell script. The example commands below are using the `./refine` shell script, and you will need to use `refine.bat` if you are working from the Windows command line. + +### Get OpenRefine source code + +With Git installed, use the `git clone` command to download the [project's repo](https://github.com/OpenRefine/OpenRefine) to a directory of your choice. + +### Set up JDK {#set-up-jdk} + +You must [install JDK](https://jdk.java.net/15/) and set the JAVA_HOME environment variable (please ensure it points to the JDK, and not the JRE). + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + + +1. On Windows 10, click the Start Menu button, type `env`, and look at the search results. Click Edit the system environment variables. (If you are using an earlier version of Windows, use the “Search†or “Search programs and files†box in the Start Menu.) + +![A screenshot of the search results for 'env'.](/img/env.png "A screenshot of the search results for 'env'.") + +2. Click Environment Variables… at the bottom of the Advanced window. +3. In the Environment Variables window that appears, click New… and create a variable with the key `JAVA_HOME`. You can set the variable for only your user account, as in the screenshot below, or set it as a system variable - it will work either way. + +![A screenshot of 'Environment Variables'.](/img/javahome.png "A screenshot of 'Environment Variables'.") + +4. Set the `Value` to the folder where you installed JDK, in the format `D:\Programs\OpenJDK`. You can locate this folder with the Browse directory... button. + + + + + +First, find where Java is on your computer with this command: + +``` +which java +``` + +Check the environment variable `JAVA_HOME` with: + +``` +$JAVA_HOME/bin/java --version +``` + +To set the environment variable for the current Java version of your MacOS: + +``` +export JAVA_HOME="$(/usr/libexec/java_home)" +``` + +Or, for Java 13.x: + +``` +export JAVA_HOME="$(/usr/libexec/java_home -v 13)" +``` + + + + + +##### With the terminal {#with-the-terminal} + +Enter the following: + +``` +sudo apt install default-jre +``` + +This probably won’t install the latest JDK package available on the Java website, but it is faster and more straightforward. (At the time of writing, it installs OpenJDK 11.0.7.) + +##### Manually {#manually} + +First, [extract the JDK package](https://openjdk.java.net/install/) to the new directory `usr/lib/jvm`: + +``` +sudo mkdir -p /usr/lib/jvm +sudo tar -x -C /usr/lib/jvm -f /tmp/openjdk-14.0.1_linux-x64_bin.tar.gz +``` + +Then, navigate to this folder and confirm the final path (in this case, `usr/lib/jvm/jdk-14.0.1`). Open a terminal and type + +``` +sudo gedit /etc/profile +``` + +In the text window that opens, insert the following lines at the end of the `profile` file, using the path above: + +``` +JAVA_HOME=/usr/lib/jvm/jdk-14.0.1 +PATH=$PATH:$HOME/bin:$JAVA_HOME/bin +export JAVA_HOME +export PATH +``` + +Note: OpenRefine on Linux currently supports jdk versions 8 to 15. Reference: [Issue 4106](https://github.com/OpenRefine/OpenRefine/issues/4106). + +Save and close the file. When you are back in the terminal, type + +``` +source /etc/environment +``` + +Exit the terminal and restart your system. You can then check that `JAVA_HOME` is set properly by opening another terminal and typing +``` +echo $JAVA_HOME +``` + +It should show the path you set above. + + + + + +--- + + + +### Maven (Optional) {#maven-optional} +OpenRefine's build script will download Maven for you and use it, if not found already locally installed. + +If you will be using your Maven installation instead of OpenRefine's build script download installation, then set the `MVN_HOME` environment variable. You may need to reboot your machine after setting these environment variables. If you receive a message `Could not find the main class: com.google.refine.Refine. Program will exit.` it is likely `JAVA_HOME` is not set correctly. + +Ensure that you set your `MAVEN_HOME` environment variable, for example: + +```shell +MAVEN_HOME=E:\Downloads\apache-maven-3.5.4-bin\apache-maven-3.5.4\ +``` + +NOTE: You can use Maven commands directly, but running some goals in isolation might fail (try adding the `compile test-compile` goals in your invocation if that is the case). + +### Building {#building} + +To see what functions are supported by OpenRefine's build system, type +```shell +./refine -h +``` + +To build the OpenRefine application from source type: +```shell +./refine clean +./refine build +``` + +### Testing {#testing} +Since OpenRefine is composed of two parts, a server and a in-browser UI, the testing system reflects that: + +* on the server side, it's powered by [TestNG](http://testng.org/) and the unit tests are written in Java; +* on the client side, we use [Cypress](https://www.cypress.io/) and the tests are written in Javascript + +To run all tests, use: +```shell +./refine test +``` +**this option is not available when using refine.bat** + + +If you want to run only the server side portion of the tests, use: +```shell +./refine server_test +``` + +If you are running the UI tests for the first time, [you must go through the installation process.](functional-tests) +If you want to run only the client side portion of the tests, use: +```shell +./refine ui_test chrome +``` + +## Running {#running} +To run OpenRefine from the command line (assuming you have been able to build from the source code successfully) +```shell +./refine +``` +By default, OpenRefine will use [refine.ini](https://github.com/OpenRefine/OpenRefine/blob/master/refine.ini) for configuration. You can copy it and rename it to `refine-dev.ini`, which will be used for configuration instead. `refine-dev.ini` won't be tracked by Git, so feel free to put your custom configurations into it. + +## Building Distributions (Kits) {#building-distributions-kits} + +The Refine build system uses Apache Ant to automate the creation of the installation packages for the different operating systems. The packages are currently optimized to run on Mac OS X which is the only platform capable of creating the packages for all three OS that we support. + +To build the distributions type + +```shell +./refine dist +``` +where 'version' is the release version. + +## Building, Testing and Running OpenRefine from Eclipse {#building-testing-and-running-openrefine-from-eclipse} +OpenRefine' source comes with Maven configuration files which are recognized by [Eclipse](http://www.eclipse.org/) if the Eclipse Maven plugin (m2e) is installed. + +At the command line, go to a directory **not** under your Eclipse workspace directory and check out the source: + +```shell +git clone https://github.com/OpenRefine/OpenRefine.git +``` + +In Eclipse, invoke the `Import...` command and select `Existing Maven Projects`. + +![Screenshot of Import a Maven project option](/img/eclipse-import-maven-project-1.png) + +Choose the root directory of your clone of the repository. You get to choose which modules of the project will be imported. You can safely leave out the `packaging` module which is only used to generate the Linux, Windows and MacOS distributions. + +Screenshot of Select maven projects to import + +To run and debug OpenRefine from Eclipse, you will need to add an execution configuration on the `server` sub-project. +Right click on the `server` subproject, click `Run as...` and `Run configurations...` and create a new `Maven Build` run configuration. Rename the run configuration `OpenRefine`. Enter the root directory of the project as `Base directory` and use `exec:java` as a Maven goal. + +![Screenshot of Add a run configuration with the exec:java goal](/img/eclipse-exec-config.png) + +This will add a run configuration that you can then use to run OpenRefine from Eclipse. + +## Code style in Eclipse + +You can apply the supplied Eclipse code style (in `IDEs/eclipse/Refine.style.xml`) to make sure Eclipse lints your files according to the existing style. +Pull requests deviating from this style will fail in the CI. + +You can manually apply the code style (regardless of your IDE) with the `mvn formatter:format` command. + +## Testing in Eclipse {#testing-in-eclipse} + +You can run the server tests directly from Eclipse. To do that you need to have the TestNG launcher plugin installed, as well as the TestNG M2E plugin (for integration with Maven). If you don't have it, you can get it by [installing new software](https://help.eclipse.org/2020-03/index.jsp?topic=/org.eclipse.platform.doc.user/tasks/tasks-129.htm) from this update URL http://dl.bintray.com/testng-team/testng-eclipse-release/ + +Once the TestNG launching plugin is installed in your Eclipse, right click on the source folder "main/tests/server/src", select `Run As` -> `TestNG Test`. This should open a new tab with the TestNG launcher running the OpenRefine tests. + +### Test coverage in Eclipse {#test-coverage-in-eclipse} + +It is possible to analyze test coverage in Eclipse with the `EclEmma Java Code Coverage` plugin. It will add a `Coverage as…` menu similar to the `Run as…` and `Debug as…` menus which will then display the covered and missed lines in the source editor. + +### Debug with Eclipse {#debug-with-eclipse} +Here's an example of putting configuration in Eclipse for debugging, like putting values for the Google Data extension. Other type of configurations that can be set are memory, Wikidata login information and more. + +![Screenshot of Eclipse debug configuration](/img/eclipse-debug-config.png) + +## Building, Testing and Running OpenRefine from IntelliJ idea {#building-testing-and-running-openrefine-from-intellij-idea} + +At the command line, go to a directory you want to save the OpenRefine project and execute the following command to clone the repository: + +```shell +git clone https://github.com/OpenRefine/OpenRefine.git +``` + +Then, open the IntelliJ idea and go to `file -> open` and select the location of the cloned repository. + +![Screenshot of Open option on the IntelliJ File menu](/img/intellij-setup-1.png) + +It will prompt you to add as a maven project as the source code contains a pom.xml file in it. Allow `auto-import` so that it can add it as a maven project. +If it doesn't prompt something like this then you can go on the right side of the IDE and click on maven then, click on `reimport all the maven projects` that will add all the dependencies and jar files required for the project. + +![Screenshot of Maven project controls in IntelliJ](/img/intellij-maven.png) + +After this, you will be able to properly build, test, and run the OpenRefine project from the terminal. +But if you will go to any of the test folders and open some file it will show you some import errors because the project isn't yet set up at the module level. + +For removing those errors, and enjoying the features of the IDE like ctrl + click, etc you need to set up the project at the module level too. Open the different modules like `extensions/wikidata`, `main` as a project in the IDE. Then, right-click on the project folder and open the module settings. + +![Screenshot of open module settings menu in IntelliJ](/img/intellij-open-module-settings.png) + +In the module settings, add the source folder and test source folders of that module. + +![Screenshot of module settings in IntelliJ](/img/intellij-module-settings.png) + +Then, do the same thing for the main OpenRefine project and now you are good to go. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/contributing.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/contributing.md new file mode 100644 index 000000000..a9151abf7 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/contributing.md @@ -0,0 +1,70 @@ +--- +id: contributing +title: Contributing +sidebar_label: Contributing +--- + +Please read the general [guidelines on contributing to OpenRefine](https://github.com/OpenRefine/OpenRefine/blob/master/CONTRIBUTING.md) first, then review the information on [reporting and tracking issues](#reporting-and-tracking-issues), and on making your [first pull request](#your-first-pull-request) below) + +## Reporting and tracking issues {#reporting-and-tracking-issues} + +If you need to file a bug or request a feature, [create an Issue in the OpenRefine Github repository](https://github.com/OpenRefine/OpenRefine/issues). Github issues should be used for reporting specific bugs and requesting specific features. If you just don't know how to do something using OpenRefine, or want to discuss some ideas, please: + +- [Try the user manual](/) +- [post to our OpenRefine mailing list](http://groups.google.com/group/openrefine/) + +## Contributing to the documentation {#contributing-to-the-documentation} + +We use [Docusaurus](https://docusaurus.io/) for our docs. For small documentation changes, you should be able to edit the Markdown files directly and submit them as a pull request. A preview of the docs will be generated automatically. But it is also +possible to preview your changes locally. Assuming you have [Node.js](https://nodejs.org/en/download/) installed (which includes npm), you can install Docusaurus with: + +You will need to install [Yarn](https://yarnpkg.com/getting-started/install) before you can build the site. +```sh +npm install -g yarn +``` + +Once you have installed yarn, navigate to docs directory & set-up the dependencies. + +```sh +cd docs +yarn +``` + +Once this is done, generate the docs with: + +```sh +yarn build +``` + +You can also spin a local web server to serve the docs for you, with auto-refresh when you edit the source files, with: +```sh +yarn start +``` + +## Your first code pull request {#your-first-code-pull-request} + +This describes the overall steps to your first code contribution in OpenRefine. If you have trouble with any of these steps feel free to reach out on the [developer mailing list](https://groups.google.com/forum/#!forum/openrefine-dev) or the [Gitter channel](https://gitter.im/OpenRefine/OpenRefine). + +- Install OpenRefine, learn to use it by following some tutorials or watching [some videos](http://openrefine.org/). That will ensure you understand the user workflows and get familiar with the terminology used in the tool. + +- Fork the GitHub repository, clone it on your machine and set up your IDE to work on it. We have [instructions for this](https://github.com/OpenRefine/OpenRefine/wiki/Building-OpenRefine-From-Source). + +- Browse through the list of issues to find an issue that you find interesting. You should pick one where you understand what the problem is as a user, you can see why fixing it would be an improvement to the tool. It is also a good idea to pick an issue that matches your technical skills: some require work on the backend (in Java) or in the frontend (Javascript), often both. We try to maintain a list of [good first issues](https://github.com/OpenRefine/OpenRefine/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) which should be easier than others and should not require any difficult design decision. + +- Reproduce the issue locally, by following the steps described in the issue. You might need to locate a particular dialog, use a specific importer on a sample file, or follow any other user workflow. If you have followed all the steps described in the issue and cannot observe the issue mentioned, write a comment on the issue explaining that you are not able to reproduce it (perhaps it was fixed by another change). + +- Locate the code that is relevant for the issue you want to solve. Text search across files is often useful for that. For instance, if the issue you want to solve is about a dialog entitled "Columnize by key/values", you can search for "Columnize" in the entire source code. For more details about this technique, see [this comment](https://github.com/OpenRefine/OpenRefine/issues/3137#issuecomment-691649962). + +- Study how the current code works. You might want to use a debugger to put breakpoints at the relevant locations (for inspecting the backend, use your IDE's debugger, for the frontend, use your browser's developer tools). + +- Create a git branch for your fix. The name of your branch should contain the issue number, and a few words to describe the topic of the fix, for instance "issue-1234-columnize-layout". + +- Make changes to the code to fix the issue. If you are changing backend code, it would be great if you could also write a test in Java to demonstrate the fix. You can imitate existing tests for that. We currently do not have frontend tests. + +- If you made Java changes, run linting to make sure they conform to our code style, with `mvn formatter:format`. + +- commit your changes, using a message that contains one of the special words "closes" and "fixes" which are detected by Github, followed by the issue number, e.g. "closes #1234" or "fixes #1234", this will link the commit to the issue you are working on. + +- push your branch to your fork and create a pull request for it, explaining the approach you have used, any design decisions you have made. + +Thank you! diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/development-roadmap.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/development-roadmap.md new file mode 100644 index 000000000..da35f2f77 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/development-roadmap.md @@ -0,0 +1,29 @@ +--- +id: development-roadmap +title: Development roadmap +sidebar_label: Development roadmap +--- + +Please be aware that the OpenRefine roadmap is subject to change at any time, so please check back regularly, and monitor [milestones](https://github.com/OpenRefine/OpenRefine/milestones), [projects](https://github.com/OpenRefine/OpenRefine/projects) and [issues](https://github.com/OpenRefine/OpenRefine/issues) in Github to keep up to date with current plans. + +If there are features you would like to see that are not currently listed here or in current [milestones](https://github.com/OpenRefine/OpenRefine/milestones), [projects](https://github.com/OpenRefine/OpenRefine/projects) and [issues](https://github.com/OpenRefine/OpenRefine/issues), please add them to the [issue tracker](https://github.com/OpenRefine/OpenRefine/issues). + + +## Planned releases {#planned-releases} + +### 4.0 {#40} +[New backend storage option to allow using much bigger datasets at the expense of real-time feedback.](https://github.com/OpenRefine/OpenRefine/milestone/7) + +New UI (possibly Vue or React based) + +## Work in progress {#work-in-progress} +Alongside the planned releases there are often smaller pieces of work in progress. Check for [recently updated issues](https://github.com/OpenRefine/OpenRefine/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) and [pull requests](https://github.com/OpenRefine/OpenRefine/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc) to see what is currently in the works. + +## On the back burner {#on-the-back-burner} +Some aspects of OpenRefine have previously been targeted for release, but have not made it into a release and have not been worked on recently. If you would like to see features in these areas, please create an issue the describes what development you would like to see: + +- Streamlining traditional features +- Views: map, timeline, protovis (D3.js) charts +- Better machinery to guess and re-encode cell values (useful for fixing encoding issues) +- Collaborative editing support (see documentation on the '[broker protocol](https://github.com/OpenRefine/OpenRefine/wiki/Broker-Protocol)' to see where this work was going) +- Column groups diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/functional-tests.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/functional-tests.md new file mode 100644 index 000000000..afdfbe43c --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/functional-tests.md @@ -0,0 +1,241 @@ +--- +id: functional-tests +title: Functional tests +sidebar_label: Functional tests +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; + +## Introduction {#introduction} + +OpenRefine interface is tested with the [Cypress framework](https://www.cypress.io/). +With Cypress, tests are performing assertions using a real browser, the same way a real user would use the software. + +Cypress tests can be ran + +- using the Cypress test runner (development mode) +- using a command line (CI/CD mode) + +If you are writing tests, the Cypress test runner is good enough, and the command-line is mainly used by the CI/CD platform (Github actions) + +## Cypress brief overview {#cypress-brief-overview} + +Cypress operates insides a browser, it's internally using NodeJS. +That's a key difference with tools such as Selenium. + +**From the Cypress documentation:** + +> But what this also means is that your test code **is being evaluated inside the browser**. Test code is not evaluated in Node, or any other server side language. The **only** language we will ever support is the language of the web: JavaScript. + +Good starting points with Cypress are the [Getting started guide](https://docs.cypress.io/guides/getting-started/writing-your-first-test.html#Write-your-first-test), and the [Trade-offs](https://docs.cypress.io/guides/references/trade-offs.html#Permanent-trade-offs-1) + +The general workflow of a Cypress test is to + +- Start a browser (yarn run cypress open) +- Visit a URL +- Trigger user actions +- Assert that the DOM contains expected texts and elements using selectors + +## Getting started {#getting-started} + +If this is the first time you use Cypress, it is recommended for you to get familiar with the tool. + +- [Cypress overview](https://docs.cypress.io/guides/overview/why-cypress.html) +- [Cypress examples of tests and syntax](https://example.cypress.io/) + +### 1. Install Cypress {#1-install-cypress} + +You will need: + +- [Node.js 10 or 12 and above](https://nodejs.org) +- [Yarn or NPM](https://yarnpkg.com/) +- A Unix/Linux shell environment or the Windows command line + +To install Cypress and dependencies, run : + +```shell +cd ./main/tests/cypress +yarn install +``` + +### 2. Start the test runner {#2-start-the-test-runner} + +The test runner assumes that OpenRefine is up and running on the local machine, the tests themselves do not launch OpenRefine, nor restarts it. + +Start OpenRefine with + +```shell +./refine +``` + +Then start Cypress + +```shell +yarn --cwd ./main/tests/cypress run cypress open +``` + +### 3. Run the existing tests {#3-run-the-existing-tests} + +Once the test runner is up, you can choose to run one or several tests by selecting them from the interface. +Click on one of them and the test will start. + +### 4. Add your first test {#4-add-your-first-test} + +- Add a `test.spec.js` into the `main/tests/cypress/cypress/integration` folder. +- The test is instantly available in the list +- Click on the test +- Start to add some code + +## Tests technical documentation {#tests-technical-documentation} + +### A typical test {#a-typical-test} + +A typical OpenRefine test starts with the following code + +```javascript +it('Ensure cells are blanked down', function () { + cy.loadAndVisitProject('food.mini'); + cy.get('.viewpanel-sorting a').contains('Sort').click(); + cy.get('.viewpanel').should('to.contain', 'Something'); +}); +``` + +The first noticeable thing about a test is the description (`Ensure cells are blanked down`), which describes what the test is doing. +Lines usually starts with `cy.something...`, which is the main way to interact with the Cypress framework. + +A few examples: + +- `cy.get('a.my-class')` will retrieve the `` element +- `cy.click()` will click on the element +- eventually, `cy.should()` will perform an assertion, for example that the element contains an expected text with `cy.should('to.contains', 'my text')` + +On top of that, OpenRefine contributors have added some functions for common OpenRefine interactions. +For example + +- `cy.loadAndVisitProject` will create a fresh project in OpenRefine +- `cy.assertCellEquals` will ensure that a cell contains a given value + +See below on the dedicated section 'Testing utilities' + +### Testing guidelines {#testing-guidelines} + +- `cy.wait` should be used in the last resort scenario. It's considered a bad practice, though sometimes there is no other choice +- Tests should remain isolated from each other. It's best to try one feature at the time +- A test should always start with a fresh project +- The name of the files should mirror the OpenRefine UI organization + +### Testing utilities {#testing-utilities} + +OpenRefine contributors have added some utility methods on the top of the Cypress framework. +Those methods perform some common actions or assertions on OpenRefine, to avoid code duplication. + +Utilities can be found in `cypress/support/commands.js`. + +The most important utility method is `loadAndVisitProject`. +This method will create a fresh OpenRefine project based on a dataset given as a parameter. +The fixture parameter can be + +- An arbitrary array, the first row is for the column names, other rows are for the values + Use an arbitrary array **only** if the test requires some specific grid values + **Example:** + + ```javascript + const fixture = [ + ['Column A', 'Column B', 'Column C'], + ['0A', '0B', '0C'], + ['1A', '1B', '1C'], + ['2A', '2B', '2C'], + ]; + cy.loadAndVisitProject(fixture); + ``` + +- A referenced dataset: `food.small` or `food.mini` + Most of the time, tests does not require any specific grid values + Use food.mini as much as possible, it loads 2 rows and very few columns in the grid + Use food.small if the test requires a few hundred rows in the grid + + Those datasets live in `cypress/fixtures` + +### Browsers {#browsers} + +In terms of browsers, Cypress is using what is installed on your operating system. +See the [Cypress documentation](https://docs.cypress.io/guides/guides/launching-browsers.html#Browsers) for a list of supported browsers + +### Folder organization {#folder-organization} + +Tests are located in `main/tests/cypress/cypress` folder. +The test should not use any file outside the cypress folder. + +- `/fixtures` contains CSVs and OpenRefine project files used by the tests +- `/integration` contains the tests +- `/plugins` contains custom plugins for the OR project +- `/screenshots` and `/videos` contains the recording of the tests, Git ignored +- `/support` is a custom library of assertion and common user actions, to avoid code duplication in the tests themselves + +### Configuration {#configuration} + +Cypress execution can be configured with environment variables, they can be declared at the OS level, or when running the test + +Available variables are + +- OPENREFINE_URL, determine on which scheme://url:port to access OpenRefine, default to http://localhost:333 +- DISABLE_PROJECT_CLEANUP, If set to 1, projects will not be deleted after each run. Default to 0 to keep the OpenRefine instance clean + + +Cypress contains [exaustive documentation](https://docs.cypress.io/guides/guides/environment-variables.html#Setting) about configuration, but here are two simple ways to configure the execution of the tests: + +#### Overriding with a cypress.env.json file {#overriding-with-a-cypressenvjson-file} + +This file is ignored by Git, and you can use it to configure Cypress locally + +#### Command-line {#command-line} + +You can pass variables at the command-line level + +```shell +yarn --cwd ./main/tests/cypress run cypress open --env OPENREFINE_URL="http://localhost:1234" +``` + +### Visual testing {#visual-testing} + +Tests generally ensure application behavior by making assertions against the DOM, to ensure specific texts or css attributes are present in the document body. +Visual testing, on the contrary, is a way to test applications by comparing images. +A reference screenshot is taken the first time the test runs, and subsequent runs will compare a new screenshot against the reference, at the pixel level. + +Here is an [introduction to visual testing by Cypress](https://docs.cypress.io/plugins/directory#visual-testing). + +In some cases, we are using visual testing. +We are using [Cypress Image Snapshot](https://github.com/jaredpalmer/cypress-image-snapshot) + +Identified cases are so far: + +- testing images created by OpenRefine backend (scatterplots for example) + +Reference screenshots (Called snapshots), are stored in /cypress/snapshots. +And a snapshot can be taken for the whole page, or just a single part of the page. + +#### When a visual test fails {#when-a-visual-test-fails} + +First, Cypress will display the following error message: + +![Diff image when a visual test fails](/img/visual-test-cypress-failure.png) + +Then, a diff image will be created in /cypress/snapshots, this directory is ignored by Git. +The diff images shows the reference image on the left, the image that was taken during the test run on the right, and the diff in the middle. + +![Diff image when a visual test fails](/img/failed-visual-test.png) + +## CI/CD {#cicd} + +In CI/CD, tests are run headless, with the following command-line + +```shell +./refine ui_test chrome +``` + +Results are displayed in the standard output + +## Resources {#resources} + +[Cypress command line options](https://docs.cypress.io/guides/guides/command-line.html#Installation) +[Lots of good Cypress examples](https://example.cypress.io/) diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/homebrew-cask-process.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/homebrew-cask-process.md new file mode 100644 index 000000000..650af5ccf --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/homebrew-cask-process.md @@ -0,0 +1,5 @@ +--- +id: homebrew-cask-process +title: Maintaining OpenRefine's Homebrew cask +sidebar_label: Maintaining OpenRefine's Homebrew cask +--- diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/maintainer-guidelines.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/maintainer-guidelines.md new file mode 100644 index 000000000..b4ca7b20f --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/maintainer-guidelines.md @@ -0,0 +1,89 @@ +--- +id: maintainer-guidelines +title: Guidelines for maintaining OpenRefine +sidebar_label: Maintainer guidelines +--- + +This page describes our practices to review issues and pull requests in the OpenRefine project. + +## Reviewing issues {#reviewing-issues} + +When people create new issues, they automatically get assigned [the "to be reviewed" tag](https://github.com/OpenRefine/OpenRefine/issues?q=is%3Aissue+is%3Aopen+label%3A%22to+be+reviewed%22). + +Ideally, for each of these issues, someone familiar with OpenRefine (not necessarily a developer!) should read the issue and try to determine if there is a genuine bug to fix, or if the enhancement request is legitimate. In those cases, we can remove the "to be reviewed" tag and leave the issue open. In the others, the issue should be politely closed. + +### Bugs {#bugs} + +For a bug, we should first check if it is a real unexpected behaviour or if just comes from a misunderstanding of the intended behaviour of the tool (which could suggest an improvement to the documentation). Then, if it sounds like a genuine problem, we need to check if it can be reproduced independently on the master branch. If the issue does not give enough details about the bug to reproduce it on master, mark it as "not reproducible" and ask the reporter for more information. After some time without any information from the reporter, we can close the issue. + +### Enhancement requests {#enhancement-requests} + +For an enhancement, we need to make a judgment call of whether the proposed functionality is in the scope of the project. There is no universal rule for this of course, so just use your own intuition: do you think this would improve the tool? Would it be consistent with the spirit of the project? Trust your own opinion - if people disagree, they can have a discussion on the issue. + +### Tagging good first issues {#tagging-good-first-issues} + +Adding [the "good first issue" tag](https://github.com/OpenRefine/OpenRefine/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) is something that requires a bit more familiarity with the development process. This tag is used by GitHub to showcase issues in some project lists and we point interested potential contributors to it. It is therefore important that tackling these issues gives them a nice onboarding experience, with as few hurdles as possible. + +Develepers should add the "good first issue" tag when they are confident that they can provide a good pull request for the issue with at most a few hours of work. Also, solving the issue should not require any difficult design decision. The issue should be uncontentious: it should be clear that the proposed solution should be accepted by the team. + +## Reviewing pull requests {#reviewing-pull-requests} + +### Process {#process} + +1. A committer reviews the PR to check for the requirements below and tests it. Each PR should be linked to one or more corresponding issues and the reviewer should check that those are correctly addressed by the PR. The reviewer should be someone else than the PR author. For PRs with an important impact or contentious issues, it is important to leave enough time for other contributors to give their opinion. + +2. The reviewer merges the pull request by squashing its commits into one (except for Weblate PRs which should be merged without squashing). + +3. The reviewer adds the linked issues to the milestone for the next release (such as [the 3.5 milestone](https://github.com/OpenRefine/OpenRefine/milestone/17)) + +4. If the change is worth noting for users or developers, the reviewer adds an entry in the changelog for the next release (such as [Changes for 3.5](https://github.com/OpenRefine/OpenRefine/wiki/Changes-for-3.5)) + +### Requirements {#requirements} + +#### Code style {#code-style} + +Currently, only our code style for integration tests (using Cypress) is codified and enforced by the CI. +For the rest, we rely on imitating the surrounding code. [We should decide on a code style and check it in the CI for other areas of the tool](https://github.com/OpenRefine/OpenRefine/issues/2338). + +#### Testing {#testing} + +We currently rely have two sorts of tests: +* Backend tests, in Java, written with the TestNG framework. Their granularity varies, but generally speaking they are unit tests which test components in isolation. +* UI tests, in Javascript, written with the Cypress framework. They are integration tests which test both the frontend and the backend at the same time. + +Changes to the backend should generally come with the accompanying TestNG tests. +Functional changes to the UI should ideally come with corresponding Cypress tests as well. + +Those tests should be supplied in the same PR as the one that touches the product code. + +#### Documentation {#documentation} + +Changes to user-facing functionality should be reflected in the docs. Those documentation changes should happen in the same PR as the one that touches the product code. + +#### UI style {#ui-style} + +We do not have formally defined UI style guidelines. Contributors are invited to imitate the existing style. + +#### Licensing and dependencies {#licensing-and-dependencies} + +Dependencies can only be added if they are released under a license that is compatible with our BSD Clause-3 license. +One should pay attention to the size of the dependencies since they inflate the size of the release bundles. + +#### Continuous integration {#continuous-integration} + +The various check statuses reported by our continuous integration suite should be green. + +### Special pull requests {#special-pull-requests} + +#### Weblate PRs {#weblate-prs} + +Weblate PRs should not be squashed as it prevents Weblate from recognizing that the corresponding changes have been made in master. They should be merged without squashing. + +Reviewing Weblate PRs only amonuts to a quick visual sanity check as maintainers are not expected to master the languages involved. If corrections need to be made, they should be done in Weblate itself. + +#### Dependabot PRs {#dependabot-prs} + +When reviewing a Dependabot PR it is generally useful to pay attention to: +* the type of version change: most libraries follow the "semver" versioning convention, which indicates the nature of the change. +* the library's changelog, especially if the version change is more significant than a patch release + diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/migrating-older-extensions.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/migrating-older-extensions.md new file mode 100644 index 000000000..75f40015e --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/migrating-older-extensions.md @@ -0,0 +1,169 @@ +--- +id: migrating-older-extensions +title: Migrating older Extensions +sidebar_label: Migrating older Extensions +--- + +## Migrating from Ant to Maven {#migrating-from-ant-to-maven} + +### Why are we doing this change? {#why-are-we-doing-this-change} + +Ant is a fairly old (antique?) build system that does not incorporate any dependency management. +By migrating to Maven we are making it easier for developers to extend OpenRefine with new libraries, and stop having to ship dozens of .jar files in the repository. Using the Maven repository also encourages developers to add dependencies to released versions of libraries instead of custom snapshots that are hard to update. + +### When was this change made? {#when-was-this-change-made} + +The migration was done between 3.0 and 3.1-beta with this commit: +https://github.com/OpenRefine/OpenRefine/commit/47323a9e750a3bc9d43af606006b5eb20ca397b8 + +### How to migrate an extension {#how-to-migrate-an-extension} + +You will need to write a `pom.xml` in the root folder of your extension to configure the compilation process with Maven. Sample `pom.xml` files for extensions can be found in the extensions that are shipped with OpenRefine (`gdata`, `database`, `jython`, `pc-axis` and `wikidata`). A sample extension (`sample`) is also provided, with a minimal build file. + +For any library that your extension depends on, you should try to find a matching artifact in the Maven Central repository. If you can find such an artifact, delete the `.jar` file from your extension and add the dependency in your `pom.xml` file. If you cannot find such an artifact, it is still possible to incorporate your own `.jar` file using `maven-install-plugin` that you can configure in your `pom.xml` file as follows: + + + + org.apache.maven.plugins + maven-install-plugin + 2.5.2 + + + install-wdtk-datamodel + process-resources + + ${basedir}/lib/my-proprietary-library.jar + default + com.my.company + my-library + 0.5.3-SNAPSHOT + jar + true + + + install-file + + + + + + +And add the dependency to the `` section as usual: + + + com.my.company + my-library + 0.5.3-SNAPSHOT + + +## Migrating to Wikimedia's i18n jQuery plugin {#migrating-to-wikimedias-i18n-jquery-plugin} + +### Why are we doing this change? {#why-are-we-doing-this-change-1} + +This adds various important localization features, such as the ability to handle plurals or interpolation. This also restores the language fallback (displaying strings in English if they are not available in the target language) which did not work with the previous set up. + +### When was the migration made? {#when-was-the-migration-made} + +The migration was made between 3.1-beta and 3.1, with this commit: https://github.com/OpenRefine/OpenRefine/commit/22322bd0272e99869ab8381b1f28696cc7a26721 + +### How to migrate an extension {#how-to-migrate-an-extension-1} + +You will need to update your translation files, merging nested objets in one global object, concatenating keys. You can do this by running the following Python script on all your JSON translation files: + + import json + import sys + + with open(sys.argv[1], 'r') as f: + j = json.loads(f.read()) + + result = {} + def translate(obj, path): + res = {} + if type(obj) == str: + result['/'.join(path)] = obj + else: + for k, v in obj.items(): + new_path = path + [k] + translate(v, new_path) + + translate(j, []) + + with open(sys.argv[1], 'w') as f: + f.write(json.dumps(result, ensure_ascii=False, indent=4)) + +Then your javascript files which retrieve the translated strings should be updated: `$.i18n._('core-dialogs')['cancel']` becomes `$.i18n('core-dialogs/cancel')`. You can do this with the following `sed` script: + + sed -i "s/\$\.i18n._(['\"]\([A-Za-z0-9/_\\-]*\)['\"])\[['\"]\([A-Za-z0-9\-\_]*\)[\"']\]/$.i18n('\1\/\2')/g" my_javascript_file.js + +You can then chase down the places where you are concatenating translated strings, and replace that with more flexible patterns using [the plugin's features](https://github.com/wikimedia/jquery.i18n#jqueryi18n-plugin). + +## Migrating from org.json to Jackson {#migrating-from-orgjson-to-jackson} + +### Why are we doing this change? {#why-are-we-doing-this-change-2} + +The org.json (or json-java) library has multiple drawbacks. +* First, it has limited functionality - all the serialization and deserialization has to be done explicitly - an important proportion of OpenRefine's code was dedicated to implementing these; +* Second, its implementation is not optimized for speed - multiple projects have reported speedups when migrating to more modern JSON libraries; +* Third, and this was the decisive factor to initiate the migration: [its license](https://json.org/license) is the MIT license with an additional condition which makes it non-free. Getting rid of this dependency was required by the Software Freedom Conservancy as a prerequisite to become a fiscal sponsor for the project. + +### When was the migration made? {#when-was-the-migration-made-1} + +This change was made between 3.1 and 3.2-beta, with this commit: https://github.com/OpenRefine/OpenRefine/commit/5639f1b2f17303b03026629d763dcb6fef98550b + +### How to migrate an extension or fork {#how-to-migrate-an-extension-or-fork} + +You will need to use the Jackson library to serialize the classes that implement interfaces or extend classes exposed by OpenRefine. +The interface `Jsonizable` was deleted. Any class that used to implement this now needs to be serializable by Jackson, producing the same format as the previous serialization code. This applies to any operation, facet, overlay model or GREL function. If you are new to Jackson, have a look at [this tutorial](https://www.baeldung.com/jackson) to learn how to annotate your class for serialization. Once this is done, you can remove the `void write(JSONWriter writer, Properties options)` method from your class. Note that it is important that you do this migration for all classes implementing the `Jsonizable` interface that are exposed to OpenRefine's core. + +We encourage you to migrate out of org.json completely, but this is only required for the classes that interact with OpenRefine's core. + +#### General notes about migrating {#general-notes-about-migrating} + +OpenRefine's ObjectMapper is available at `ParsingUtilities.mapper`. It is configured to only serialize the fields and getters that have been explicitly marked with `@JsonProperty` (to avoid accidental JSON format changes due to refactoring). On deserialization it will ignore any field in the JSON payload that does not correspond to a field in the Java class. It has serializers and deserializers for `OffsetDateTime` and `LocalDateTime`. + +Useful snippets to use in tests: +* deserialize an instance: `MyClass instance = ParsingUtilities.mapper.readValue(jsonString, MyClass.class);` (replaces calls to `Jsonizable.write`); +* serialize an instance: `String json = ParsingUtilities.mapper.writeValueAsString(myInstance);` (replaces calls to static methods such as `load`, `loadStreaming` or `reconstruct`); +* the equivalent of `JSONObject` is `ObjectNode`, the equivalent of `JSONArray` is `ArrayNode`; +* create an empty JSON object: `ParsingUtilities.mapper.createObjectNode()` (replaces `new JSONObject()`); +* create an empty JSON array: `ParsingUtilities.mapper.createArrayNode()` (replaces `new JSONArray()`). + +Before undertaking the migration, we recommend that you write some tests which serialize and deserialize your objects. This will help you make sure that the JSON format is preserved during the migration. One way to do this is to collect some sample JSON representations of your objects, and check in your tests that deserializing these JSON payloads and serializing them back to JSON preserves the JSON payload. Some utilities are available to help you with that in [`TestUtils`](https://github.com/OpenRefine/OpenRefine/blob/master/main/tests/server/src/com/google/refine/tests/util/TestUtils.java) (we had [some to test org.json serialization](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/tests/server/src/com/google/refine/tests/util/TestUtils.java) before we got rid of the dependency, feel free to copy them). + +#### For functions {#for-functions} + +Before the migration, you had to explicitly define JSON serialization of functions with a `write` method. You should now override the getters returning the various documentation fields. + +Example: `Cos` function [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/expr/functions/math/Cos.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/expr/functions/math/Cos.java). + +#### For operations {#for-operations} + +Before the JSON migration we refactored engine-dependent operations so that the engine configuration is represented by an `EngineConfig` object instead of a `JSONObject`. Therefore the constructor for your operation should be updated to use this new class. Your constructor should also be annotated to be used during deserialization. + +Note that you do not need to explicitly serialize the operation type, this is already done for you by `AbstractOperation`. + +Example: `ColumnRemovalOperation` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/operations/column/ColumnRemovalOperation.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/operations/column/ColumnRemovalOperation.java). + +#### For changes {#for-changes} + +Changes are serialized in plain text but often relies on JSON serialization for parts of the data. Just use the methods above with `ParsingUtilities.mapper` to maintain this behaviour. + +Example: `ReconChange` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/model/changes/ReconChange.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/operations/column/ColumnRemovalOperation.java). + +#### For importers {#for-importers} + +The importing options have been migrated from `JSONObject` to `ObjectNode`. Your compiler should help you propagate this change. Utility functions in `JSONUtilities` have been migrated to Jackson so you should have minimal changes if you used them. + +Example: `TabularImportingParserBase` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/importers/TabularImportingParserBase.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/importers/TabularImportingParserBase.java). + +#### For overlay models {#for-overlay-models} + +Migrate serialization and deserialization as for other objects. + +Example: `WikibaseSchema` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/extensions/wikidata/src/org/openrefine/wikidata/schema/WikibaseSchema.java#L203) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/extensions/wikidata/src/org/openrefine/wikidata/schema/WikibaseSchema.java#L60) + +#### For preference values {#for-preference-values} + +Any class that is stored in OpenRefine's preference now needs to implement the `com.google.refine.preferences.PreferenceValue` interface. The static `load` method and the `write` method used previously for deserialization should be deleted and regular Jackson serialization and deserialization should be implemented instead. Note that you do not need to explicitly serialize the class name, this is already done for you by the interface. + +Example: `TopList` [before](https://github.com/OpenRefine/OpenRefine/blob/3.1/main/src/com/google/refine/preference/TopList.java) and [after](https://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/preference/TopList.java) diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/openrefine-api.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/openrefine-api.md new file mode 100644 index 000000000..7d1a4c402 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/openrefine-api.md @@ -0,0 +1,285 @@ +--- +id: openrefine-api +title: OpenRefine API +sidebar_label: OpenRefine API +--- + +This is a generic API reference for interacting with OpenRefine's HTTP API. + +**NOTE:** This protocol is subject to change without warning at any time (and has in the past) and is not versioned. Use at your own risk! + +For OpenRefine 3.3 and later, all POST requests need to include a CSRF token as described here: https://github.com/OpenRefine/OpenRefine/wiki/Changes-for-3.3#csrf-protection-changes + +## Create project: {#create-project} + +> **Command:** _POST /command/core/create-project-from-upload_ + +When uploading files you will need to send the data as `multipart/form-data`. This is different to all other API calls which use a mixture of query string and POST parameters. + +multipart form-data: + + 'project-file' : file contents + 'project-name' : project name + 'format' : format of data in project-file (e.g. 'text/line-based/*sv') [optional] + 'options' : json object containing options relevant to the file format [optional - however, some importers may have required options, such as `recordPath` for the JSON & XML importers]. + +The formats supported will depend on the version of OpenRefine you are using and any Extensions you have installed. The common formats include: + +* 'text/line-based': Line-based text files +* 'text/line-based/*sv': CSV / TSV / separator-based files [separator to be used in specified in the json submitted to the options parameter] +* 'text/line-based/fixed-width': Fixed-width field text files +* 'binary/text/xml/xls/xlsx': Excel files +* 'text/json': JSON files +* 'text/xml': XML files + +If the format is omitted OpenRefine will try to guess the format based on the file extension and MIME type. +The values which can be specified in the JSON object submitted to the 'options' parameter will vary depending on the format being imported. If not specified the options will either be guessed at by OpenRefine (e.g. separator being used in a separated values file) or a default value used. The import options for each file format are not currently documented, but can be seen in the OpenRefine GUI interface when importing a file of the relevant format. + +If the project creation is successful, you will be redirected to a URL of the form: + + http://127.0.0.1:3333/project?project= + +From the project parameter you can extract the project id for use in future API calls. The content of the response is the HTML for the OpenRefine interface for viewing the project. + +### Get project models: {#get-project-models} + +> **Command:** _GET /command/core/get-models?_ + + 'project' : project id + +Recovers the models for the specific project. This includes columns, records, overlay models, scripting. In the columnModel a list of the columns is displayed, key index and name, and column groupings. + +### Response: {#response} +**On success:** +```JSON +{ + "columnModel":{ + "columns":[ + { + "cellIndex":0, + "originalName":"email", + "name":"email" + }, + { + "cellIndex":1, + "originalName":"name", + "name":"name" + }, + { + "cellIndex":2, + "originalName":"state", + "name":"state" + }, + { + "cellIndex":3, + "originalName":"gender", + "name":"gender" + }, + { + "cellIndex":4, + "originalName":"purchase", + "name":"purchase" + } + ], + "keyCellIndex":0, + "keyColumnName":"email", + "columnGroups":[ + + ] + }, + "recordModel":{ + "hasRecords":false + }, + "overlayModels":{ + + }, + "scripting":{ + "grel":{ + "name":"General Refine Expression Language (GREL)", + "defaultExpression":"value" + }, + "jython":{ + "name":"Python / Jython", + "defaultExpression":"return value" + }, + "clojure":{ + "name":"Clojure", + "defaultExpression":"value" + } + } +} +``` + + + +## Apply operations {#apply-operations} + +> **Command:** _POST /command/core/apply-operations?_ + +In the parameter + + 'project' : project id + +In the form data + + 'operations' : Valid JSON **Array** of OpenRefine operations + +Example of a Valid JSON **Array** +```JSON +'[ + { + "op":"core/column-addition", + "description":"Create column zip type at index 15 based on column Zip Code 2 using expression grel:value.type()", + "engineConfig":{ + "mode":"row-based", + "facets":[] + }, + "newColumnName":"zip type", + "columnInsertIndex":15, + "baseColumnName":"Zip Code 2", + "expression":"grel:value.type()", + "onError":"set-to-blank" + }, + { + "op":"core/column-addition", + "description":"Create column testing at index 15 based on column Zip Code 2 using expression grel:value.toString()0,5]", + "engineConfig":{ + "mode":"row-based", + "facets":[] + }, + "newColumnName":"testing", + "columnInsertIndex":15, + "baseColumnName":"Zip Code 2", + "expression":"grel:value.toString()[0,5]", + "onError":"set-to-blank" + } +] +``` + +On success returns JSON response +`{ "code" : "ok" }` + +## Export rows {#export-rows} + +> **Command:** _POST /command/core/export-rows_ + +In the parameter + + 'project' : project id + 'format' : format... (e.g 'tsv', 'csv') + +In the form data + + 'engine' : JSON string... (e.g. '{"facets":[],"mode":"row-based"}') + +Returns exported row data in the specified format. The formats supported will depend on the version of OpenRefine you are using and any Extensions you have installed. The common formats include: + +* csv +* tsv +* xls +* xlsx +* ods +* html + +## Delete project {#delete-project} + +> **Command:** _POST /command/core/delete-project_ + + 'project' : project id... + +Returns JSON response + +## Check status of async processes {#check-status-of-async-processes} + +> **Command:** _GET /command/core/get-processes_ + + 'project' : project id... + +Returns JSON response + +## Get all projects metadata: {#get-all-projects-metadata} + +> **Command:** _GET /command/core/get-all-project-metadata_ + +Recovers the meta data for all projects. This includes the project's id, name, time of creation and last time of modification. + +### Response: {#response-1} +```json +{ + "projects":{ + "[project_id]":{ + "name":"[project_name]", + "created":"[project_creation_time]", + "modified":"[project_modification_time]" + }, + ...[More projects]... + } +} +``` + +## Expression Preview {#expression-preview} +> **Command:** _POST /command/core/preview-expression_ + +Pass some expression (GREL or otherwise) to the server where it will be executed on selected columns and the result returned. + +### Parameters: {#parameters} +* **cellIndex**: _[column]_ +The cell/column you wish to execute the expression on. +* **rowIndices**: _[rows]_ +The rows to execute the expression on as JSON array. Example: `[0,1]` +* **expression**: _[language]_:_[expression]_ +The expression to execute. The language can either be grel, jython or clojure. Example: grel:value.toLowercase() +* **project**: _[project_id]_ +The project id to execute the expression on. +* **repeat**: _[repeat]_ +A boolean value (true/false) indicating whether or not this command should be repeated multiple times. A repeated command will be executed until the result of the current iteration equals the result of the previous iteration. +* **repeatCount**: _[repeatCount]_ +The maximum amount of times a command will be repeated. + +### Response: {#response-2} +**On success:** +```json +{ + "code": "ok", + "results" : [result_array] +} +``` + +The result array will hold up to ten results, depending on how many rows there are in the project that was specified by the [project_id] parameter. Each result is the string that would be put in the cell if the GREL command was executed on that cell. Note that any expression that would return an array or JSon object will be jsonized, although the output can differ slightly from the jsonize() function. + +**On error:** +```JSON +{ + "code": "error", + "type": "[error_type]", + "message": "[error message]" +} +``` + +## Third-party software libraries {#third-party-software-libraries} +Libraries using the [OpenRefine API](openrefine-api): + +### Python {#python} +* [refine-client-py](https://github.com/PaulMakepeace/refine-client-py/) + * Or this fork of the above with an extended CLI [openrefine-client](https://github.com/felixlohmeier/openrefine-client) +* [refine-python](https://github.com/maxogden/refine-python) + +### Ruby {#ruby} +* [refine-ruby](https://github.com/distillytics/refine-ruby) + * The above is a maintained fork of [google-refine](https://github.com/maxogden/refine-ruby) +* [google_refine](https://github.com/chengguangnan/google_refine) + +### NodeJS {#nodejs} +* [node-openrefine](https://github.com/pm5/node-openrefine) + +### R {#r} +* [rrefine](https://cran.r-project.org/web/packages/rrefine/index.html) + +### PHP {#php} +* [openrefine-php-client](https://github.com/keboola/openrefine-php-client) + +### Java {#java} +* [refine-java](https://github.com/dtap-gmbh/refine-java) + +### Bash {#bash} +* [bash-refine.sh](https://gist.github.com/felixlohmeier/d76bd27fbc4b8ab6d683822cdf61f81d) (templates for shell scripts) diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/reconciliation-api.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/reconciliation-api.md new file mode 100644 index 000000000..7649a6ebb --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/reconciliation-api.md @@ -0,0 +1,24 @@ +--- +id: reconciliation-api +title: Reconciliation API +sidebar_label: Reconciliation API +--- + +_This is a technical description of the mechanisms behind the reconciliation system in OpenRefine. For usage instructions, see [Reconciliation](/manual/reconciling)._ + +A reconciliation service is a web service that, given some text which is a name or label for something, and optionally some additional details, returns a ranked list of potential entities matching the criteria. The candidate text does not have to match each entity's official name perfectly, and that's the whole point of reconciliation--to get from ambiguous text name to precisely identified entities. For instance, given the text "apple", a reconciliation service probably should return the fruit apple, the Apple Inc. company, and New York city (also known as the Big Apple). + +Entities are identified by strong identifiers in some particular identifier space. In the same identifier space, identifiers follow the same syntax. For example, given the string "apple", a reconciliation service might return entities identified by the strings " [Q89](https://www.wikidata.org/wiki/Q89)", "[Q312](https://www.wikidata.org/wiki/Q312)", and "[Q60](https://www.wikidata.org/wiki/Q60)", in the Wikidata ID space. Each reconciliation service can only reconcile to one single identifier space, but several reconciliation services can reconcile to the same identifier space. + +OpenRefine can connect to any reconciliation service which follows the [reconciliation API v0.1](https://reconciliation-api.github.io/specs/0.1/). This was formerly a specification edited by the OpenRefine project, which has now transitioned to its own +[W3C Entity Reconciliation Community Group](https://www.w3.org/community/reconciliation/). + +Informally, the main function of any reconciliation service is to find good candidates in the underlying database, given the following data: + +* A string, which is normally the name or title of the entity, in some language. +* Optionally, a type which can be used to narrow down the search to entities of this type. OpenRefine does not define a particular set of acceptable types: this choice is left to the reconciliation service (see the suggest API for that). +* Optionally, a list of properties and their values, which can be used to refine the search. For instance, when reconciling a database of books, the author name or the publication date are useful bits of information that can be transferred to the reconciliation service. This information will be sent to the reconciliation service if the user binds columns to properties. Again, the notion of property is not predefined in OpenRefine: its definition depends on the reconciliation service. + +See [the specifications of the protocol](https://reconciliation-api.github.io/specs/0.1) for more details about the protocol. You can suggest changes on its [issues tracker](https://github.com/reconciliation-api/specs/issues) or on the [group mailing +list](https://lists.w3.org/Archives/Public/public-reconciliation/). + diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/technical-reference-index.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/technical-reference-index.md new file mode 100644 index 000000000..170b60958 --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/technical-reference-index.md @@ -0,0 +1,7 @@ +--- +id: technical-reference-index +title: OpenRefine technical reference +sidebar_label: Technical Reference Index +--- + +Technical reference index diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/translating-docs.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/translating-docs.md new file mode 100644 index 000000000..eb8482e5f --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/translating-docs.md @@ -0,0 +1,19 @@ +--- +id: translating-docs +title: Translate OpenRefine's documentation +sidebar_label: Translate OpenRefine's documentation +--- + +Our user manual can be translated using [Crowdin](https://crowdin.com/project/openrefine). + +## Getting access to Crowdin + +You need to request access to Crowdin on [our developers mailing list](https://groups.google.com/forum/#!forum/openrefine-dev). You will then be granted translator access on the platform. + +## Publication of translations + +Only the user manual for the current development version is being translated. When we publish a new stable version, we take a snapshot of this and publish it on the website. + +In the meantime the pages you translate will be visible under https://docs.openrefine.org/next/ after a few days. + + diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/translating-ui.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/translating-ui.md new file mode 100644 index 000000000..2ca3a811e --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/translating-ui.md @@ -0,0 +1,105 @@ +--- +id: translating-ui +title: Translate OpenRefine's interface +sidebar_label: Translate OpenRefine's interface +--- + +Currently supported languages include English, Spanish, Chinese, French, Hebrew, Italian and Japanese. + +![Translation status](https://hosted.weblate.org/widgets/openrefine/-/287x66-grey.png) + +You can help translate OpenRefine into your language by visiting [Weblate](https://hosted.weblate.org/engage/openrefine/?utm_source=widget) which provides a web based UI to edit and add translations and sends automatic pull requests back to our project. + +Click to help translate --> [Weblate](https://hosted.weblate.org/engage/openrefine/?utm_source=widget) + +## Manual translation process {#manual-translation-process} + +Localized strings are entered in a .json file, one per language. They are located in the folder `main/webapp/modules/core/langs/` in a file named `translation-xx`.json, where xx is the language code (i.e. fr for French). + +### Simple case of localized string {#simple-case-of-localized-string} +This is an example of a simple string, with the start of the JSON file. This example is for French. +``` +{ + "name": "Français", + "core-index/help": "Aide", + (… more lines) +} +``` + +So the key `core-index/help` will render as `"Aide"` in French. + +### Localization with a parameterized value {#localization-with-a-parameterized-value} +In this example, the name of the column (represented by `$1` in this example), will be substituted with the string of the name of the column. + +`"core-facets/edit-facet-title": "Cliquez ici pour éditer le nom de la facette\nColonne : $1",` + +### Localization with a singular/plural value {#localization-with-a-singularplural-value} +In this example, one of the parameter will have a different string depending if the value is 1 or another value. +In this example, the string for page, the second parameter, `$2`, will have an « s » or not depending on the value of `$2`. + +`"core-views/goto-page": "$1 de $2 {{plural:$2|page|pages}}"` + +## Front-end development {#front-end-development} + +The OpenRefine front end has been localized using the [Wikidata jquery.i18n library](https://github.com/OpenRefine/OpenRefine/pull/1285. The localized text is stored in a JSON dictionary on the server and retrieved with a new OpenRefine command. + +### Adding a new string {#adding-a-new-string} + +There should be no hard-coded language strings in the HTML or JSON used for the front end. If you need a new string, first check the existing strings to make sure there isn't an equivalent string, **in an equivalent context**, that you can reuse. Context is important because it can affect how the same literal English text is translated. This cuts down on the amount of text which needs to be translated. + +Strings should be entire sentences or phrases and should include substitution variables for any parameters. Do not concatenate strings in either Java or Javascript (or implicitly by laying them out in a specific order). So, instead of `"You have " + count + " row(s)"` (or worse `count != 1 ? " rows" : " row"`), internationalize everything together so that it can be translated taking into account word ordering and plurals for different languages, ie `"You have $1 {{plural $1: row|rows}}"`, passing the parameter(s) into the `$.i18n` call. + +If there's no string you can reuse, allocate an available key in the appropriate translation dictionary and add the default string, e.g. + +```json +..., +"section/newkey": "new default string for this key", +... +``` + +and then set the text (or HTML) of your HTML element using i18n helper method. So given an HTML fragment like: +```html + +``` +we could set its text using: +``` +$('#new-html-element-id').text($.i18n('section/newkey'])); +``` +or, if you need to embed HTML tags: +``` +$('#new-html-element-id').html($.i18n('section/newkey']); +``` + +### Adding a new language {#adding-a-new-language} + +The language dictionaries are stored in the `langs` subdirectory for the module e.g. + +* https://github.com/OpenRefine/OpenRefine/tree/master/main/webapp/modules/core/langs for the main interface +* https://github.com/OpenRefine/OpenRefine/tree/master/extensions/gdata/module/langs for google spreadsheet connection +* https://github.com/OpenRefine/OpenRefine/tree/master/extensions/database/module/langs for database via JDBC +* https://github.com/OpenRefine/OpenRefine/tree/master/extensions/wikidata/module/langs for Wikidata + +To add support for a new language, the easiest way is to do it directly in Weblate. To do it manually, copy `translation-en.json` to `translation-.json` and have your translator translate all the value strings (ie right hand side). + +#### Main interface {#main-interface} + The translation is best done [with Weblate](https://hosted.weblate.org/engage/openrefine/?utm_source=widget). Files are periodically merged by the developer team. + +Run the latest (hopefully cloned from github) version and check whether translated words fit to the layout. Not all items can be translated word by word, especially into non-IÌ€ndo-European languages. + +If you see any text which remains in English even when you have checked all items, please create bug report in the issue tracker so that the developers can fix it. + +#### Extensions {#extensions} + +Extensions can be translated via Weblate just like the core software. + +The new extension for Wikidata contains lots of domain-specific concepts, with which you may not be familiar. The Wikidata may not have reconciliation service for your language. I recommend checking the glossary(https://www.wikidata.org/wiki/Wikidata:Glossary) to be consistent. + +By default, the system tries to load the language file corresponding to the currently in-use browser language. To override this setting a new menu item ("Language Settings") has been added at the index page. +To support a new language file, the developer should add a corresponding entry to the dropdown menu in this file: `/OpenRefine/main/webapp/modules/core/scripts/index/lang-settings-ui.html`. The entry should look like: +```javascript + +``` + +## Server-side localisation {#server--backend-coding} + +Currently no back end functions are translated, so things like error messages, undo history, etc may appear in English form. Rather than sending raw error text to the front end, it's better to send an error code which is translated into text on the front end. This allows for multiple languages to be supported. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/version-release-process.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/version-release-process.md new file mode 100644 index 000000000..0cf0b88df --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/version-release-process.md @@ -0,0 +1,51 @@ +--- +id: version-release-process +title: How to do an OpenRefine version release +sidebar_label: How to do an OpenRefine version release +--- + +When releasing a new version of Refine, the following steps should be followed: + +1. Make sure the `master` branch is stable and nothing has broken since the previous version. We need developers to stabilize the trunk and some volunteers to try out `master` for a few days. +2. Change the version number in [RefineServlet.java](http://github.com/OpenRefine/OpenRefine/blob/master/main/src/com/google/refine/RefineServlet.java#L62) and in the POM files using `mvn versions:set -DnewVersion=2.6-beta -DgenerateBackupPoms=false`. Commit the changes. +3. Compose the list of changes in the code and on the wiki. If the issues have been updated with the appropriate milestone, the Github issue tracker should be able to provide a good starting point for this. +4. Set up build machine. This needs to be Mac OS X or Linux. +5. Download Windows and Mac JREs to bundle them in the Windows and Mac packages from [AdoptOpenJDK](https://adoptopenjdk.net/). You only need the JREs, not the JDKs. Use the lowest version of Java supported (Java 8 currently). Configure the location of these JREs in the `settings.xml` file at the root of the repository. It is important to download recent versions of the JREs as this impacts which HTTPS certificates are accepted by the tool. +6. Insert the production Google credentials in https://github.com/OpenRefine/OpenRefine/blob/bc540a880eceb88e54f85ca43eb54769de3bfa4f/extensions/gdata/src/com/google/refine/extension/gdata/GoogleAPIExtension.java#L36-L39 without committing the changes. +7. [Build the release candidate kits using the shell script (not just Maven)](https://github.com/OpenRefine/OpenRefine/wiki/Building-OpenRefine-From-Source). This must be done on Mac OS X or Linux to be able to build all 3 kits. On Linux you will need to install the `genisoimage` program first. +```shell +./refine dist 2.6-beta.2 +``` +To build the Windows version with embedded JRE, use `mvn package -s settings.xml -P embedded-jre -DskipTests=true`. + +8. On a Mac machine, compress the Mac `.dmg` (`genisoimage` does not compress it by default) with the following command on a mac machine: `hdiutil convert openrefine-uncompressed.dmg -format UDZO -imagekey zlib-level=9 -o openrefine-3.1-mac.dmg`. If running OS X in a VM, it's probably quicker and more reliable to transfer the kits to the host machine first and then to Github. Finder -> Go -> Connect -> smb://10.0.2.2/. You can then sign the generated DMG file with `codesign -s "Apple Distribution: Code for Science and Society, Inc." openrefine-3.1-mac.dmg`. This requires that you have installed the appropriate certificate on your Mac, see below. + +9. Tag the release candidate in git and push the tag to Github. For example: +```shell +git tag -a -m "Second beta" 2.6-beta.2 + git push origin --tags +``` +10. Upload the kits to Github releases [https://github.com/OpenRefine/OpenRefine/releases/](https://github.com/OpenRefine/OpenRefine/releases/) Mention the SHA sums of all uploaded artifacts. +11. Announce the beta/release candidate for testing +12. Repeat build/release candidate/testing cycle, if necessary. +13. Tag the release in git. Build the distributions and upload them. +14. [Update the OpenRefine Homebrew cask](https://github.com/OpenRefine/OpenRefine/wiki/Maintaining-OpenRefine's-Homebrew-Cask) or coordinate an update via the [developer list](https://groups.google.com/forum/#!forum/openrefine-dev) +15. Verify that the correct versions are shown in the widget at [http://openrefine.org/download](http://openrefine.org/download) +16. Announce on the [OpenRefine mailing list](https://groups.google.com/forum/#!forum/openrefine). +17. Update the version in master to the next version number with `-SNAPSHOT` (such as `4.3-SNAPSHOT`) +```shell +mvn versions:set -DnewVersion=4.3-SNAPSHOT +``` +18. If releasing a new major or minor version, create a snapshot of the docs, following [Docusaurus' versioning procedure](https://docusaurus.io/docs/versioning). + +Apple code signing +================== + +We have code signing certificates for our iOS distributions. To use them, follow these steps: +* Request advisory.committee@openrefine.org to be added to the Apple team: you need to provide the email address that corresponds to your AppleID account; +* Create a certificate signing request from your Mac: https://help.apple.com/developer-account/#/devbfa00fef7 +* Go to https://developer.apple.com/account/resources/certificates/add and select "Apple Distribution" as certificate type +* Upload the certificate signing request in the form +* Download the generated certificate +* Import this certificate in the "Keychain Access" app on your mac +* You can now sign code on behalf of the team using the `codesign` utility, such as `codesign -s "Apple Distribution: Code for Science and Society, Inc." openrefine-3.1-mac.dmg`. diff --git a/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/writing-extensions.md b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/writing-extensions.md new file mode 100644 index 000000000..3511cc31f --- /dev/null +++ b/OpenRefine/docs/versioned_docs/version-3.5/technical-reference/writing-extensions.md @@ -0,0 +1,326 @@ +--- +id: writing-extensions +title: Writing Extensions +sidebar_label: Writing Extensions +--- + +## Introduction {#introduction} + +This is a very brief overview of the structure of OpenRefine extensions. For more detailed documentation and step-by-step guides please see the following external documentation/tutorials: + +* Giuliano Tortoreto has [written documentation detailling how to build extension for OpenRefine](https://github.com/giTorto/OpenRefineExtensionDoc/raw/master/main.pdf) +* Owen Stephens has written [a guide to developing an extension which adds new GREL functions to OpenRefine](http://www.meanboyfriend.com/overdue_ideas/2017/05/writing-an-extension-to-add-new-grel-functions-to-openrefine/). + +OpenRefine makes use of a modified version of the [Butterfly framework](https://github.com/OpenRefine/simile-butterfly/tree/openrefine) to provide an extension architecture. OpenRefine extensions are Butterfly modules. You don't really need to know about Butterfly itself, but you might encounter "butterfly" here and there in the code base. + +Extensions that come with the code base are located under [the extensions subdirectory](https://github.com/OpenRefine/OpenRefine/tree/master/extensions), but when you develop your own extension, you can put its code anywhere as long as you point Butterfly to it. That is done by any one of the following methods + +* refer to your extension's directory in [the butterfly.properties file](https://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/WEB-INF/butterfly.properties) through a `butterfly.modules.path` setting. +* specify the butterfly.modules.path property on the command line when you run OpenRefine. This overrides the values in the property file, so you need to include the default values first e.g. `-Dbutterfly.modules.path=modules,../../extensions,/path/to/your/extension` + +Please note that you should bundle any dependencies yourself, so you are insulated from OpenRefine packaging changes over time. + +### Directory Layout {#directory-layout} + +A OpenRefine extension sits in a file directory that contains the following files and sub-directories: + +``` +pom.xml + src/ + com/foo/bar/... *.java source files + module/ + *.html, *.vt files + scripts/... *.js files + styles/... *.css and *.less files + images/... image files + MOD-INF/ + lib/*.jar files + classes/... java class files + module.properties + controller.js +``` + +The file named module.properties (see [example](https://github.com/OpenRefine/OpenRefine/blob/master/extensions/sample/module/MOD-INF/module.properties)) contains the extension's metadata. Of importance is the name field, which gives the extension a name that's used in many other places to refer to it. This can be different from the extension's directory name. + +``` +name = my-extension-name +``` + +Your extension's client-side resources (.html, .js, .css files) stored in the module/ subdirectory will be accessible from http://127.0.0.1:3333/extension/my-extension-name/ when OpenRefine is running. + +Also of importance is the dependency + +``` +requires = core +``` + +which makes sure that the core module of OpenRefine is loaded before the extension attempts to hook into it. + +The file named controller.js is responsible for registering the extension's hooks into OpenRefine. Look at the sample-extension extension's [controller.js](https://github.com/OpenRefine/OpenRefine/blob/master/extensions/sample/module/MOD-INF/controller.js) file for an example. It should have a function called init() that does the hook registrations. + +The `pom.xml` file is an [Apache Maven](http://maven.apache.org/) build file. You can make a copy of the sample extension's `pom.xml` file to get started. The important point here is that the Java classes should be built into the `module/MOD-INF/classes` sub-directory. + +Note that your extension's Java code would need to reference some libraries used in OpenRefine and OpenRefine's Java classes themselves. These dependencies are reflected in the Maven configuration for the extension. + +## Sample extension {#sample-extension} + +The sample extension is included in the code base so that you can copy it and get started on writing your own extension. After you copy it, make sure you change its name inside its `module/MOD-INF/controller.js` file. + +### Basic Structure {#basic-structure} + +The sample extension's code is in `refine/extensions/sample/`. In that directory, Java source code is contained under the `src` sub-directory, and webapp code is under the `module` sub-directory. Here is the full directory layout: + +``` +refine/extensions/sample/ + build.xml (ant build script) + src/ + com/google/refine/sampleExtension/ + ... Java source code ... + module/ + MOD-INF/ + module.properties (module settings) + controller.js (module init and routing logic in Javascript) + classes/ + ... compiled Java classes ... + lib/ + ... Java jars ... + ... velocity templates (.vt) ... + ... LESS css files ... + ... client-side files (.html, .css, .js, image files) ... +``` + +The sub-directory `MOD-INF` contains the Butterfly module's metadata and is what Butterfly looks for when it scans directories for modules. `MOD-INF` serves similar functions as `WEB-INF` in other web frameworks. + +Java code is built into the sub-directory `classes` inside `MOD-INF`, and supporting external Java jars are in the `lib` sub-directory. Those will be automatically loaded by Butterfly. (The build.xml script is wired to compile into the `classes` sub-directory.) + +Client-side code is in the inner `module` sub-directory. They can be plain old .html, .css, .js, and image files, or they can be [LESS](http://lesscss.org/) files that get processed into CSS. There are also Velocity .vt files, but they need to be routed inside `MOD-INF/controller.js`. + +`MOD-INF/controller.js` lets you configure the extension's initialization and URL routing in Javascript rather than in Java. For example, when the requested URL path is either `/` or an empty string, we process and return `MOD-INF/index.vt` ( [see http://127.0.0.1:3333/extension/sample/](http://127.0.0.1:3333/extension/sample/) if OpenRefine is running). + +The `init()` function in `controller.js` allows the extension to register various client-side handlers for augmenting pages served by Refine's core. These handlers are feature-specific. For example, [this is where the jython extension adds its parser](https://github.com/OpenRefine/OpenRefine/blob/master/extensions/jython/module/MOD-INF/controller.js#L46). As for the sample extension, it adds its script `project-injection.js` and style `project-injection.less` into the `/project` page. If you [view the source of the /project page](http://127.0.0.1:3333/project), you will see references to those two files. + +### Wiring Up the Extension {#wiring-up-the-extension} + +The Extensions are loaded by the Butterfly framework. Butterfly refers to these as 'modules'. [The location of modules is set in the `main/webapp/butterfly.properties` file](https://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/WEB-INF/butterfly.properties#L27). Butterfly simply descends into each of those paths and looks for any `MOD-INF` directories. + +For more information, see [Extension Points](https://github.com/OpenRefine/OpenRefine/wiki/Extension-Points). + +## Extension points {#extension-points} + +### Client-side: Javascript and CSS {#client-side-javascript-and-css} + +The UI in OpenRefine for working with a project is coded in [the /main/webapp/modules/core/project.vt file](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/project.vt). The file is quite small, and that's because almost all of its content is to be expanded dynamically through the Velocity variables $scriptInjection and $styleInjection. So that your own Javascript and CSS files get loaded, you need to register them with the ClientSideResourceManager, which is done in the /module/MOD-INF/controller.js file. See [the controller.js file in this sample extension code](http://github.com/OpenRefine/OpenRefine/blob/master/extensions/sample/module/MOD-INF/controller.js) for an example. + +In the registration call, the variable `module` is already available to your code by default, and it refers to your own extension. + +``` +ClientSideResourceManager.addPaths( + "project/scripts", + module, + [ + "scripts/foo.js", + "scripts/subdir/bar.js" + ] + ); +``` + +You can specify one or more files for registration, and their paths are relative to the `module` subdirectory of your extension. They are included in the order listed. + +Javascript Bundling: Note that `project.vt` belongs to the core module and is thus under the control of the core module's [controller.js file](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/MOD-INF/controller.js). The Javascript files to be included in `project.vt` are by default bundled together for performance. When debugging, you can prevent this bundling behavior by setting `bundle` to `false` near the top of that `controller.js` file. (If you have commit access to this code base, be sure not to check that change in.) + +### Client-side: Images {#client-side-images} + +We recommend that you always refer to images through your CSS files rather than in your Javascript code. URLs to images will thus be relative to your CSS files, e.g., + +``` +.foo { + background: url(../images/x.png); + } +``` + +If you really really absolutely need to refer to your images in your Javascript code, then look up your extension's URL path in the global Javascript variable `ModuleWirings`: + +``` +ModuleWirings["my-extension"] + "images/x.png" +``` + +### Client-side: HTML Templates {#client-side-html-templates} + +Beside Javascript, CSS, and images, your extension might also include HTML templates that get loaded on the fly by your Javascript code and injected into the page's DOM. For example, here is [the Cluster edit dialog template](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/scripts/dialogs/clustering-dialog.html), which gets loaded by code in [the equivalent javascript file 'clustering-dialog.js'](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/scripts/dialogs/clustering-dialog.js): + +``` +var dialog = $(DOM.loadHTML("core", "scripts/dialogs/clustering-dialog.html")); +``` + +`DOM.loadHTML` returns the content of the file as a string, and `$(...)` turns it into a DOM fragment. Where `"core"` is, you would want your extension's name. The path of the HTML file is relative to your extension's `module` subdirectory. + +### Client-side: Project UI Extension Points {#client-side-project-ui-extension-points} + +Getting your extension's Javascript code included in `project.vt` doesn't accomplish much by itself unless your code also registers hooks into the UI. For example, you can surely implement an exporter in Javascript, but unless you add a corresponding menu command in the UI, your user can't use your exporter. + +#### Main Menu {#main-menu} + +The main menu can be extended by calling any one of the methods `MenuBar.appendTo`, `MenuBar.insertBefore`, and `MenuBar.insertAfter`. Each method takes 2 arguments: an array of strings that identify a particular existing menu item or submenu, and one new single menu item or submenu or an array of menu items and submenus. For example, to insert 2 menu items and a menu separator before the menu item Project > Export Filtered Rows > Templating..., write this Javascript code wherever that would execute when your Javascript files get loaded: + +``` +MenuBar.insertBefore( + ["core/project", "core/export", "core/export-templating"], + [ + { + "label":"Menu item 1", + "click": function() { ... } + }, + { + "label":"Menu item 2", + "click": function() { ... } + }, + {} // separator + ] + ); +``` + +The array `["core/project", "core/export", "core/export-templating"]` pinpoints the reference menu item. + +See the beginning of [/main/webapp/modules/core/scripts/project/menu-bar.js](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/scripts/project/menu-bar.js) for IDs of menu items and submenus. + +#### Column Header Menu {#column-header-menu} + +The drop-down menu of each column can also be extended, but the mechanism is slightly different compared to the main menu. Because the drop-down menu for a particular column is constructed on the fly when the user actually clicks the drop-down menu button, extending the column header menu can't really be done once at start-up time, but must be done every time a column header menu gets created. So, registration in this case involves providing a function that gets called each such time: + +``` +DataTableColumnHeaderUI.extendMenu(function(column, columnHeaderUI, menu) { ... do stuff to menu ... }); +``` + +That function takes in the column object (which contains the column's name), the column header UI object (generally not so useful), and the menu to extend. In the previous code line where it says "do stuff to menu", you can write something like this: + +``` +MenuSystem.appendTo(menu, ["core/facet"], [ + { + id: "core/text-facet", + label: "My Facet on " + column.name, + click: function() { + ... use column.name and do something ... + } + }, + ]); +``` + +In addition to `MenuSystem.appendTo`, you can also call `MenuSystem.insertBefore` and `MenuSystem.insertAfter` which the same 3 arguments. To see what IDs you can use, see the function `DataTableColumnHeaderUI.prototype._createMenuForColumnHeader` in [/main/webapp/modules/core/scripts/views/data-table/column-header-ui.js](http://github.com/OpenRefine/OpenRefine/blob/master/main/webapp/modules/core/scripts/views/data-table/column-header-ui.js). + +### Server-side: Ajax Commands {#server-side-ajax-commands} + +The client-side of OpenRefine gets things done by calling AJAX commands on the server-side. These commands must be registered with the OpenRefine servlet, so that the servlet knows how to route AJAX calls from the client-side. This can be done inside the `init` function in your extension's `controller.js` file, e.g., + +``` +function init() { + var RefineServlet = Packages.com.google.refine.RefineServlet; + RefineServlet.registerCommand(module, "my-command", new Packages.com.foo.bar.MyCommand()); + } +``` + +Your command will then be accessible at [http://127.0.0.1:3333/command/my-extension/my-command](http://127.0.0.1:3333/command/my-extension/my-command). + +### Server-side: Operations {#server-side-operations} + +Most commands change the project's data. Most of them do so by creating abstract operations. See the Changes, History, Processes, and Operations section of the [Server Side Architecture](https://github.com/OpenRefine/OpenRefine/wiki/Server-Side-Architecture) document. + +You can register an operation **class** in the `init` function as follows: + +``` +Packages.com.google.refine.operations.OperationRegistry.registerOperation( + module, + "operation-name", + Packages.com.foo.bar.MyOperation + ); +``` + +Do not call `new` to construct an operation instance. You must register the class itself. The class should have a static function for reconstructing an operation instance from a JSON blob: + +``` +static public AbstractOperation reconstruct(Project project, JSONObject obj) throws Exception { + ... + } +``` + +### Server-side: GREL {#server-side-grel} + +GREL can be extended with new functions. This is also done in the `init` function in `controller.js`, e.g., + +``` +Packages.com.google.refine.grel.ControlFunctionRegistry.registerFunction( + "functionName", new Packages.com.foo.bar.TheFunctionClass()); +``` + +You might also want to provide new variables (beyond just `value`, `cells`, `row`, etc.) available to expressions. This is done by registering a binder that implements the interface `com.google.refine.expr.Binder`: + +``` +Packages.com.google.refine.expr.ExpressionUtils.registerBinder( + new Packages.com.foo.bar.MyBinder()); +``` + +### Server-side: Importers {#server-side-importers} + +You can register an importer as follows: + +``` +Packages.com.google.refine.importers.ImporterRegistry.registerImporter( + "importer-name", new Packages.com.foo.bar.MyImporter()); +``` + +The string `"importer-name"` isn't important at all. It's not really related to file extension or mime-type. Just use something unique. Your importer will be explicitly called to test if it can import something. + +### Server-side: Exporters {#server-side-exporters} + +You can register an exporter as follows: + +``` +Packages.com.google.refine.exporters.ExporterRegistry.registerExporter( + "exporter-name", new Packages.com.foo.bar.MyExporter()); +``` + +The string `"exporter-name"` isn't important at all. It's only used by the client-side to tell the server-side which exporter to use. Just use something unique and, of course, relevant. + +### Server-side: Overlay Models {#server-side-overlay-models} + +Overlay models are objects attached onto a core Project object to store and manage additional data for that project. For example, the schema alignment skeleton is managed by the Protograph overlay model. An overlay model implements the interface `com.google.refine.model.OverlayModel` and can be registered like so: + +``` +Packages.com.google.refine.model.Project.registerOverlayModel( + "model-name", + Packages.com.foo.bar.MyOverlayModel); +``` + +Note that you register the **class** , not an instance. The class should implement the following static method for reconstructing an overlay model instance from a JSON blob: + +``` +static public OverlayModel reconstruct(JSONObject o) throws JSONException { + ... + } +``` + +When the project gets saved, the overlay model instance's `write` method will be called: + +``` +public void write(JSONWriter writer, Properties options) throws JSONException { + ... + } +``` + +### Server-side: Scripting Languages {#server-side-scripting-languages} + +A scripting language (such as Jython) can be registered as follows: + +``` +Packages.com.google.refine.expr.MetaParser.registerLanguageParser( + "jython", + "Jython", + Packages.com.google.refine.jython.JythonEvaluable.createParser(), + "return value" + ); +``` + +The first string is the prefix that gets prepended to each expression so that we know which language the expression is in. This should be short, unique, and identifying. The second string is a user-friendly name of the language. The third is an object that implements the interface `com.google.refine.expr.LanguageSpecificParser`. The final string is the default expression in that language that would return the cell's value. + +In 2018 we are making important changes to OpenRefine to modernize it, for the benefit of users and contributors. This page describes the changes that impact developers of extensions or forks and is intended to minimize the effort required on their end to follow the transition. The instructions are written specifically with extension maintainers in mind, but fork maintainers should also find it useful. + +This document describes the migrations in the order they are committed to the master branch. This means that it should be possible to perform each migration in turn, with the ability to run the software between each stage by checking out the appropriate git commit. diff --git a/OpenRefine/docs/versioned_sidebars/version-3.4-sidebars.json b/OpenRefine/docs/versioned_sidebars/version-3.4-sidebars.json new file mode 100644 index 000000000..89e8788b2 --- /dev/null +++ b/OpenRefine/docs/versioned_sidebars/version-3.4-sidebars.json @@ -0,0 +1,186 @@ +{ + "version-3.4/docs": [ + { + "collapsed": true, + "type": "category", + "label": "User Manual", + "items": [ + { + "type": "doc", + "id": "version-3.4/index" + }, + { + "type": "doc", + "id": "version-3.4/manual/installing" + }, + { + "type": "doc", + "id": "version-3.4/manual/running" + }, + { + "type": "doc", + "id": "version-3.4/manual/starting" + }, + { + "collapsed": true, + "type": "category", + "label": "Exploring data", + "items": [ + { + "type": "doc", + "id": "version-3.4/manual/exploring" + }, + { + "type": "doc", + "id": "version-3.4/manual/facets" + }, + { + "type": "doc", + "id": "version-3.4/manual/sortview" + } + ] + }, + { + "collapsed": true, + "type": "category", + "label": "Transforming data", + "items": [ + { + "type": "doc", + "id": "version-3.4/manual/transforming" + }, + { + "type": "doc", + "id": "version-3.4/manual/cellediting" + }, + { + "type": "doc", + "id": "version-3.4/manual/columnediting" + }, + { + "type": "doc", + "id": "version-3.4/manual/transposing" + } + ] + }, + { + "type": "doc", + "id": "version-3.4/manual/reconciling" + }, + { + "type": "doc", + "id": "version-3.4/manual/wikidata" + }, + { + "collapsed": true, + "type": "category", + "label": "Expressions", + "items": [ + { + "type": "doc", + "id": "version-3.4/manual/expressions" + }, + { + "type": "doc", + "id": "version-3.4/manual/grel" + }, + { + "type": "doc", + "id": "version-3.4/manual/grelfunctions" + }, + { + "type": "doc", + "id": "version-3.4/manual/jythonclojure" + } + ] + }, + { + "type": "doc", + "id": "version-3.4/manual/exporting" + }, + { + "type": "doc", + "id": "version-3.4/manual/troubleshooting" + } + ] + }, + { + "collapsed": true, + "type": "category", + "label": "GREL Reference", + "items": [ + { + "type": "doc", + "id": "version-3.4/manual/grelfunctions" + } + ] + }, + { + "collapsed": true, + "type": "category", + "label": "Technical Reference", + "items": [ + { + "type": "doc", + "id": "version-3.4/technical-reference/technical-reference-index" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/architecture" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/openrefine-api" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/reconciliation-api" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/suggest-api" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/data-extension-api" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/contributing" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/build-test-run" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/development-roadmap" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/version-release-process" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/homebrew-cask-process" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/writing-extensions" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/migrating-older-extensions" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/translating" + }, + { + "type": "doc", + "id": "version-3.4/technical-reference/functional-tests" + } + ] + } + ] +} diff --git a/OpenRefine/docs/versioned_sidebars/version-3.5-sidebars.json b/OpenRefine/docs/versioned_sidebars/version-3.5-sidebars.json new file mode 100644 index 000000000..d925ba1dc --- /dev/null +++ b/OpenRefine/docs/versioned_sidebars/version-3.5-sidebars.json @@ -0,0 +1,217 @@ +{ + "version-3.5/docs": [ + { + "collapsed": true, + "type": "category", + "label": "User Manual", + "items": [ + { + "type": "doc", + "id": "version-3.5/index" + }, + { + "type": "doc", + "id": "version-3.5/manual/installing" + }, + { + "type": "doc", + "id": "version-3.5/manual/running" + }, + { + "type": "doc", + "id": "version-3.5/manual/starting" + }, + { + "collapsed": true, + "type": "category", + "label": "Exploring data", + "items": [ + { + "type": "doc", + "id": "version-3.5/manual/exploring" + }, + { + "type": "doc", + "id": "version-3.5/manual/facets" + }, + { + "type": "doc", + "id": "version-3.5/manual/sortview" + } + ] + }, + { + "collapsed": true, + "type": "category", + "label": "Transforming data", + "items": [ + { + "type": "doc", + "id": "version-3.5/manual/transforming" + }, + { + "type": "doc", + "id": "version-3.5/manual/cellediting" + }, + { + "type": "doc", + "id": "version-3.5/manual/columnediting" + }, + { + "type": "doc", + "id": "version-3.5/manual/transposing" + } + ] + }, + { + "type": "doc", + "id": "version-3.5/manual/reconciling" + }, + { + "collapsed": true, + "type": "category", + "label": "Wikibase", + "items": [ + { + "type": "doc", + "id": "version-3.5/manual/wikibase/overview" + }, + { + "type": "doc", + "id": "version-3.5/manual/wikibase/configuration" + }, + { + "type": "doc", + "id": "version-3.5/manual/wikibase/reconciling" + }, + { + "type": "doc", + "id": "version-3.5/manual/wikibase/schema-alignment" + }, + { + "type": "doc", + "id": "version-3.5/manual/wikibase/new-entities" + }, + { + "type": "doc", + "id": "version-3.5/manual/wikibase/quality-assurance" + }, + { + "type": "doc", + "id": "version-3.5/manual/wikibase/uploading" + } + ] + }, + { + "collapsed": true, + "type": "category", + "label": "Expressions", + "items": [ + { + "type": "doc", + "id": "version-3.5/manual/expressions" + }, + { + "type": "doc", + "id": "version-3.5/manual/grel" + }, + { + "type": "doc", + "id": "version-3.5/manual/grelfunctions" + }, + { + "type": "doc", + "id": "version-3.5/manual/jythonclojure" + } + ] + }, + { + "type": "doc", + "id": "version-3.5/manual/exporting" + }, + { + "type": "doc", + "id": "version-3.5/manual/troubleshooting" + } + ] + }, + { + "collapsed": true, + "type": "category", + "label": "GREL Reference", + "items": [ + { + "type": "doc", + "id": "version-3.5/manual/grelfunctions" + } + ] + }, + { + "collapsed": true, + "type": "category", + "label": "Technical Reference", + "items": [ + { + "type": "doc", + "id": "version-3.5/technical-reference/technical-reference-index" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/architecture" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/openrefine-api" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/reconciliation-api" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/contributing" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/build-test-run" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/development-roadmap" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/version-release-process" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/homebrew-cask-process" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/writing-extensions" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/migrating-older-extensions" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/translating-ui" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/translating-docs" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/functional-tests" + }, + { + "type": "doc", + "id": "version-3.5/technical-reference/maintainer-guidelines" + } + ] + } + ] +} diff --git a/OpenRefine/docs/versions.json b/OpenRefine/docs/versions.json new file mode 100644 index 000000000..61b9fd005 --- /dev/null +++ b/OpenRefine/docs/versions.json @@ -0,0 +1,4 @@ +[ + "3.5", + "3.4" +] diff --git a/OpenRefine/docs/yarn.lock b/OpenRefine/docs/yarn.lock new file mode 100644 index 000000000..17141b3f5 --- /dev/null +++ b/OpenRefine/docs/yarn.lock @@ -0,0 +1,9509 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@algolia/autocomplete-core@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.5.0.tgz#6c91c9de7748e9c103846828a58dfe92bd4d6689" + integrity sha512-E7+VJwcvwMM8vPeaVn7fNUgix8WHV8A1WUeHDi2KHemCaaGc8lvUnP3QnvhMxiDhTe7OpMEv4o2TBUMyDgThaw== + dependencies: + "@algolia/autocomplete-shared" "1.5.0" + +"@algolia/autocomplete-preset-algolia@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.5.0.tgz#61671f09c0c77133d9baf1356719f8378c48437a" + integrity sha512-iiFxKERGHkvkiupmrFJbvESpP/zv5jSgH714XRiP5LDvUHaYOo4GLAwZCFf2ef/L5tdtPBARvekn6k1Xf33gjA== + dependencies: + "@algolia/autocomplete-shared" "1.5.0" + +"@algolia/autocomplete-shared@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.5.0.tgz#09580bc89408a2ab5f29e312120dad68f58019bd" + integrity sha512-bRSkqHHHSwZYbFY3w9hgMyQRm86Wz27bRaGCbNldLfbk0zUjApmE4ajx+ZCVSLqxvcUEjMqZFJzDsder12eKsg== + +"@algolia/cache-browser-local-storage@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.11.0.tgz#1c168add00b398a860db6c86039e33b2843a9425" + integrity sha512-4sr9vHIG1fVA9dONagdzhsI/6M5mjs/qOe2xUP0yBmwsTsuwiZq3+Xu6D3dsxsuFetcJgC6ydQoCW8b7fDJHYQ== + dependencies: + "@algolia/cache-common" "4.11.0" + +"@algolia/cache-browser-local-storage@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.9.1.tgz#784e91580dcca00a8280b0905197f5abbbdf4b48" + integrity sha512-bAUU9vKCy45uTTlzJw0LYu1IjoZsmzL6lgjaVFaW1crhX/4P+JD5ReQv3n/wpiXSFaHq1WEO3WyH2g3ymzeipQ== + dependencies: + "@algolia/cache-common" "4.9.1" + +"@algolia/cache-common@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.11.0.tgz#066fe6d58b18e4b028dbef9bb8de07c5e22a3594" + integrity sha512-lODcJRuPXqf+6mp0h6bOxPMlbNoyn3VfjBVcQh70EDP0/xExZbkpecgHyyZK4kWg+evu+mmgvTK3GVHnet/xKw== + +"@algolia/cache-common@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.9.1.tgz#2d5f37ba7aab7db76627c4a4fce51a7fd137fa65" + integrity sha512-tcvw4mOfFy44V4ZxDEy9wNGr6vFROZKRpXKTEBgdw/WBn6mX51H1ar4RWtceDEcDU4H5fIv5tsY3ip2hU+fTPg== + +"@algolia/cache-in-memory@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.11.0.tgz#763c8cb655e6fd2261588e04214fca0959ac07c1" + integrity sha512-aBz+stMSTBOBaBEQ43zJXz2DnwS7fL6dR0e2myehAgtfAWlWwLDHruc/98VOy1ZAcBk1blE2LCU02bT5HekGxQ== + dependencies: + "@algolia/cache-common" "4.11.0" + +"@algolia/cache-in-memory@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.9.1.tgz#3fd1d67aec804b6cc8439015b8b9c712a45c7ae0" + integrity sha512-IEJrHonvdymW2CnRfJtsTVWyfAH05xPEFkGXGCw00+6JNCj8Dln3TeaRLiaaY1srlyGedkemekQm1/Xb46CGOQ== + dependencies: + "@algolia/cache-common" "4.9.1" + +"@algolia/client-account@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.11.0.tgz#67fadd3b0802b013ebaaa4b47bb7babae892374e" + integrity sha512-jwmFBoUSzoMwMqgD3PmzFJV/d19p1RJXB6C1ADz4ju4mU7rkaQLtqyZroQpheLoU5s5Tilmn/T8/0U2XLoJCRQ== + dependencies: + "@algolia/client-common" "4.11.0" + "@algolia/client-search" "4.11.0" + "@algolia/transporter" "4.11.0" + +"@algolia/client-account@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.9.1.tgz#f2c1b3e49de2ee1fca44b8b5e64e1ce0dbdff0db" + integrity sha512-Shpjeuwb7i2LR5QuWREb6UbEQLGB+Pl/J5+wPgILJDP/uWp7jpl0ase9mYNQGKj7TjztpSpQCPZ3dSHPnzZPfw== + dependencies: + "@algolia/client-common" "4.9.1" + "@algolia/client-search" "4.9.1" + "@algolia/transporter" "4.9.1" + +"@algolia/client-analytics@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.11.0.tgz#cbdc8128205e2da749cafc79e54708d14c413974" + integrity sha512-v5U9585aeEdYml7JqggHAj3E5CQ+jPwGVztPVhakBk8H/cmLyPS2g8wvmIbaEZCHmWn4TqFj3EBHVYxAl36fSA== + dependencies: + "@algolia/client-common" "4.11.0" + "@algolia/client-search" "4.11.0" + "@algolia/requester-common" "4.11.0" + "@algolia/transporter" "4.11.0" + +"@algolia/client-analytics@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.9.1.tgz#56972496526910c53c5ce7844f4571efba63eb5f" + integrity sha512-/g6OkOSIA+A0t/tjvbL6iG/zV4El4LPFgv/tcAYHTH27BmlNtnEXw+iFpGjeUlQoPily9WVB3QNLMJkaNwL3HA== + dependencies: + "@algolia/client-common" "4.9.1" + "@algolia/client-search" "4.9.1" + "@algolia/requester-common" "4.9.1" + "@algolia/transporter" "4.9.1" + +"@algolia/client-common@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.11.0.tgz#9a2d1f6f8eaad25ba5d6d4ce307ba5bd84e6f999" + integrity sha512-Qy+F+TZq12kc7tgfC+FM3RvYH/Ati7sUiUv/LkvlxFwNwNPwWGoZO81AzVSareXT/ksDDrabD4mHbdTbBPTRmQ== + dependencies: + "@algolia/requester-common" "4.11.0" + "@algolia/transporter" "4.11.0" + +"@algolia/client-common@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.9.1.tgz#ae313b65d3249efcb4fafd2e92ed1fa2fd075482" + integrity sha512-UziRTZ8km3qwoVPIyEre8TV6V+MX7UtbfVqPmSafZ0xu41UUZ+sL56YoKjOXkbKuybeIC9prXMGy/ID5bXkTqg== + dependencies: + "@algolia/requester-common" "4.9.1" + "@algolia/transporter" "4.9.1" + +"@algolia/client-personalization@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.11.0.tgz#d3bf0e760f85df876b4baf5b81996f0aa3a59940" + integrity sha512-mI+X5IKiijHAzf9fy8VSl/GTT67dzFDnJ0QAM8D9cMPevnfX4U72HRln3Mjd0xEaYUOGve8TK/fMg7d3Z5yG6g== + dependencies: + "@algolia/client-common" "4.11.0" + "@algolia/requester-common" "4.11.0" + "@algolia/transporter" "4.11.0" + +"@algolia/client-recommendation@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/client-recommendation/-/client-recommendation-4.9.1.tgz#217af2a38d37ab12cf23a419cc9a576af9d15b13" + integrity sha512-Drtvvm1PNIOpYf4HFlkPFstFQ3IsN+TRmxur2F7y6Faplb5ybISa8ithu1tmlTdyTf3A78hQUQjgJet6qD2XZw== + dependencies: + "@algolia/client-common" "4.9.1" + "@algolia/requester-common" "4.9.1" + "@algolia/transporter" "4.9.1" + +"@algolia/client-search@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.11.0.tgz#c1105d715a2a04ba27231eca86f5d6620f68f4ae" + integrity sha512-iovPLc5YgiXBdw2qMhU65sINgo9umWbHFzInxoNErWnYoTQWfXsW6P54/NlKx5uscoLVjSf+5RUWwFu5BX+lpw== + dependencies: + "@algolia/client-common" "4.11.0" + "@algolia/requester-common" "4.11.0" + "@algolia/transporter" "4.11.0" + +"@algolia/client-search@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.9.1.tgz#a2fbc47a1b343dade9a8b06310231d51ff675b1b" + integrity sha512-r9Cw2r8kJr45iYncFDht6EshARghU265wuY8Q8oHrpFHjAziEYdsUOdNmQKbsSH5J3gLjDPx1EI5DzVd6ivn3w== + dependencies: + "@algolia/client-common" "4.9.1" + "@algolia/requester-common" "4.9.1" + "@algolia/transporter" "4.9.1" + +"@algolia/logger-common@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.11.0.tgz#bac1c2d59d29dee378b57412c8edd435b97de663" + integrity sha512-pRMJFeOY8hoWKIxWuGHIrqnEKN/kqKh7UilDffG/+PeEGxBuku+Wq5CfdTFG0C9ewUvn8mAJn5BhYA5k8y0Jqg== + +"@algolia/logger-common@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.9.1.tgz#3323834095f2916338d2535d2df91c4723ac19f2" + integrity sha512-9mPrbFlFyPT7or/7PXTiJjyOewWB9QRkZKVXkt5zHAUiUzGxmmdpJIGpPv3YQnDur8lXrXaRI0MHXUuIDMY1ng== + +"@algolia/logger-console@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.11.0.tgz#ced19e3abb22eb782ed5268d51efb5aa9ef109ef" + integrity sha512-wXztMk0a3VbNmYP8Kpc+F7ekuvaqZmozM2eTLok0XIshpAeZ/NJDHDffXK2Pw+NF0wmHqurptLYwKoikjBYvhQ== + dependencies: + "@algolia/logger-common" "4.11.0" + +"@algolia/logger-console@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.9.1.tgz#c324ef26843dbed06b44586309331dbb949744ad" + integrity sha512-74VUwjtFjFpjZpi3QoHIPv0kcr3vWUSHX/Vs8PJW3lPsD4CgyhFenQbG9v+ZnyH0JrJwiYTtzfmrVh7IMWZGrQ== + dependencies: + "@algolia/logger-common" "4.9.1" + +"@algolia/requester-browser-xhr@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.11.0.tgz#f9e1ad56f185432aa8dde8cad53ae271fd5d6181" + integrity sha512-Fp3SfDihAAFR8bllg8P5ouWi3+qpEVN5e7hrtVIYldKBOuI/qFv80Zv/3/AMKNJQRYglS4zWyPuqrXm58nz6KA== + dependencies: + "@algolia/requester-common" "4.11.0" + +"@algolia/requester-browser-xhr@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.9.1.tgz#0812f3c7c4105a4646c0fba8429b172b2d0e01c5" + integrity sha512-zc46tk5o0ikOAz3uYiRAMxC2iVKAMFKT7nNZnLB5IzT0uqAh7pz/+D/UvIxP4bKmsllpBSnPcpfQF+OI4Ag/BA== + dependencies: + "@algolia/requester-common" "4.9.1" + +"@algolia/requester-common@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.11.0.tgz#d16de98d3ff72434bac39e4d915eab08035946a9" + integrity sha512-+cZGe/9fuYgGuxjaBC+xTGBkK7OIYdfapxhfvEf03dviLMPmhmVYFJtJlzAjQ2YmGDJpHrGgAYj3i/fbs8yhiA== + +"@algolia/requester-common@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.9.1.tgz#50fcf4c7c1ed7ae13159167ac1da2844d036a630" + integrity sha512-9hPgXnlCSbqJqF69M5x5WN3h51Dc+mk/iWNeJSVxExHGvCDfBBZd0v6S15i8q2a9cD1I2RnhMpbnX5BmGtabVA== + +"@algolia/requester-node-http@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.11.0.tgz#beb2b6b68d5f4ce15aec80ede623f0ac96991368" + integrity sha512-qJIk9SHRFkKDi6dMT9hba8X1J1z92T5AZIgl+tsApjTGIRQXJLTIm+0q4yOefokfu4CoxYwRZ9QAq+ouGwfeOg== + dependencies: + "@algolia/requester-common" "4.11.0" + +"@algolia/requester-node-http@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.9.1.tgz#70054a0aa5643072404fcb68042eec97c7abd1c8" + integrity sha512-vYNVbSCuyrCSCjHBQJk+tLZtWCjvvDf5tSbRJjyJYMqpnXuIuP7gZm24iHil4NPYBhbBj5NU2ZDAhc/gTn75Ag== + dependencies: + "@algolia/requester-common" "4.9.1" + +"@algolia/transporter@4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.11.0.tgz#a8de3c173093ceceb02b26b577395ce3b3d4b96f" + integrity sha512-k4dyxiaEfYpw4UqybK9q7lrFzehygo6KV3OCYJMMdX0IMWV0m4DXdU27c1zYRYtthaFYaBzGF4Kjcl8p8vxCKw== + dependencies: + "@algolia/cache-common" "4.11.0" + "@algolia/logger-common" "4.11.0" + "@algolia/requester-common" "4.11.0" + +"@algolia/transporter@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.9.1.tgz#63ef3d9ae3b6556fa1ff1e6265bbab482bd084b7" + integrity sha512-AbjFfGzX+cAuj7Qyc536OxIQzjFOA5FU2ANGStx8LBH+AKXScwfkx67C05riuaRR5adSCLMSEbVvUscH0nF+6A== + dependencies: + "@algolia/cache-common" "4.9.1" + "@algolia/logger-common" "4.9.1" + "@algolia/requester-common" "4.9.1" + +"@babel/code-frame@7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" + integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== + dependencies: + "@babel/highlight" "^7.12.13" + +"@babel/code-frame@^7.16.0", "@babel/code-frame@^7.5.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" + integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== + dependencies: + "@babel/highlight" "^7.16.0" + +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.13.15": + version "7.13.15" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.15.tgz#7e8eea42d0b64fda2b375b22d06c605222e848f4" + integrity sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA== + +"@babel/compat-data@^7.16.0", "@babel/compat-data@^7.16.4": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" + integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== + +"@babel/core@7.12.9": + version "7.12.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.9.tgz#fd450c4ec10cdbb980e2928b7aa7a28484593fc8" + integrity sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.5" + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helpers" "^7.12.5" + "@babel/parser" "^7.12.7" + "@babel/template" "^7.12.7" + "@babel/traverse" "^7.12.9" + "@babel/types" "^7.12.7" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.19" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/core@^7.12.16", "@babel/core@^7.12.3": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.0.tgz#c4ff44046f5fe310525cc9eb4ef5147f0c5374d4" + integrity sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helpers" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/generator@^7.12.15", "@babel/generator@^7.12.5", "@babel/generator@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" + integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew== + dependencies: + "@babel/types" "^7.16.0" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab" + integrity sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw== + dependencies: + "@babel/types" "^7.12.13" + +"@babel/helper-annotate-as-pure@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d" + integrity sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.0.tgz#f1a686b92da794020c26582eb852e9accd0d7882" + integrity sha512-9KuleLT0e77wFUku6TUkqZzCEymBdtuQQ27MhEKzf9UOOJu3cYj98kyaDAzxpC7lV6DGiZFuC8XqDsq8/Kl6aQ== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/helper-compilation-targets@^7.13.0": + version "7.13.16" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz#6e91dccf15e3f43e5556dffe32d860109887563c" + integrity sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA== + dependencies: + "@babel/compat-data" "^7.13.15" + "@babel/helper-validator-option" "^7.12.17" + browserslist "^4.14.5" + semver "^6.3.0" + +"@babel/helper-compilation-targets@^7.16.0", "@babel/helper-compilation-targets@^7.16.3": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0" + integrity sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA== + dependencies: + "@babel/compat-data" "^7.16.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.17.5" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz#090d4d166b342a03a9fec37ef4fd5aeb9c7c6a4b" + integrity sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + +"@babel/helper-create-regexp-features-plugin@^7.12.13": + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz#a2ac87e9e319269ac655b8d4415e94d38d663cb7" + integrity sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + regexpu-core "^4.7.1" + +"@babel/helper-create-regexp-features-plugin@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz#06b2348ce37fccc4f5e18dcd8d75053f2a7c44ff" + integrity sha512-3DyG0zAFAZKcOp7aVr33ddwkxJ0Z0Jr5V99y3I690eYLpukJsJvAbzTy1ewoCqsML8SbIrjH14Jc/nSQ4TvNPA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + regexpu-core "^4.7.1" + +"@babel/helper-define-polyfill-provider@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.0.tgz#c5b10cf4b324ff840140bb07e05b8564af2ae971" + integrity sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-explode-assignable-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz#753017337a15f46f9c09f674cff10cee9b9d7778" + integrity sha512-Hk2SLxC9ZbcOhLpg/yMznzJ11W++lg5GMbxt1ev6TXUiJB0N42KPC+7w8a+eWGuqDnUYuwStJoZHM7RgmIOaGQ== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-function-name@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" + integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog== + dependencies: + "@babel/helper-get-function-arity" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/helper-get-function-arity@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" + integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-hoist-variables@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" + integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-member-expression-to-functions@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72" + integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw== + dependencies: + "@babel/types" "^7.13.12" + +"@babel/helper-member-expression-to-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" + integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" + integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA== + dependencies: + "@babel/types" "^7.13.12" + +"@babel/helper-module-imports@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" + integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-module-transforms@^7.12.1": + version "7.13.14" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz#e600652ba48ccb1641775413cb32cfa4e8b495ef" + integrity sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g== + dependencies: + "@babel/helper-module-imports" "^7.13.12" + "@babel/helper-replace-supers" "^7.13.12" + "@babel/helper-simple-access" "^7.13.12" + "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/helper-validator-identifier" "^7.12.11" + "@babel/template" "^7.12.13" + "@babel/traverse" "^7.13.13" + "@babel/types" "^7.13.14" + +"@babel/helper-module-transforms@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5" + integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA== + dependencies: + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-simple-access" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/helper-validator-identifier" "^7.15.7" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/helper-optimise-call-expression@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea" + integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA== + dependencies: + "@babel/types" "^7.12.13" + +"@babel/helper-optimise-call-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" + integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-plugin-utils@7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af" + integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ== + +"@babel/helper-plugin-utils@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== + +"@babel/helper-remap-async-to-generator@^7.16.0", "@babel/helper-remap-async-to-generator@^7.16.4": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.4.tgz#5d7902f61349ff6b963e07f06a389ce139fbfe6e" + integrity sha512-vGERmmhR+s7eH5Y/cp8PCVzj4XEjerq8jooMfxFdA5xVtAk9Sh4AQsrWgiErUEBjtGrBtOFKDUcWQFW4/dFwMA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-wrap-function" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/helper-replace-supers@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz#6442f4c1ad912502481a564a7386de0c77ff3804" + integrity sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.13.12" + "@babel/helper-optimise-call-expression" "^7.12.13" + "@babel/traverse" "^7.13.0" + "@babel/types" "^7.13.12" + +"@babel/helper-replace-supers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" + integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/helper-simple-access@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6" + integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA== + dependencies: + "@babel/types" "^7.13.12" + +"@babel/helper-simple-access@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" + integrity sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" + integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-split-export-declaration@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05" + integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg== + dependencies: + "@babel/types" "^7.12.13" + +"@babel/helper-split-export-declaration@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" + integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-validator-identifier@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" + integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== + +"@babel/helper-validator-identifier@^7.15.7": + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== + +"@babel/helper-validator-option@^7.12.17": + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" + integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== + +"@babel/helper-validator-option@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" + integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== + +"@babel/helper-wrap-function@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz#b3cf318afce774dfe75b86767cd6d68f3482e57c" + integrity sha512-VVMGzYY3vkWgCJML+qVLvGIam902mJW0FvT7Avj1zEe0Gn7D93aWdLblYARTxEw+6DhZmtzhBM2zv0ekE5zg1g== + dependencies: + "@babel/helper-function-name" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/helpers@^7.12.5": + version "7.13.17" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.17.tgz#b497c7a00e9719d5b613b8982bda6ed3ee94caf6" + integrity sha512-Eal4Gce4kGijo1/TGJdqp3WuhllaMLSrW6XcL0ulyUAQOuxHcCafZE8KHg9857gcTehsm/v7RcOx2+jp0Ryjsg== + dependencies: + "@babel/template" "^7.12.13" + "@babel/traverse" "^7.13.17" + "@babel/types" "^7.13.17" + +"@babel/helpers@^7.16.0": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.3.tgz#27fc64f40b996e7074dc73128c3e5c3e7f55c43c" + integrity sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w== + dependencies: + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.3" + "@babel/types" "^7.16.0" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" + integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/highlight@^7.12.13": + version "7.13.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.13.10.tgz#a8b2a66148f5b27d666b15d81774347a731d52d1" + integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg== + dependencies: + "@babel/helper-validator-identifier" "^7.12.11" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.12.13", "@babel/parser@^7.12.16", "@babel/parser@^7.12.7": + version "7.13.16" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.16.tgz#0f18179b0448e6939b1f3f5c4c355a3a9bcdfd37" + integrity sha512-6bAg36mCwuqLO0hbR+z7PHuqWiCeP7Dzg73OpQwsAB1Eb8HnGEz5xYBzCfbu+YjoaJsJs+qheDxVAuqbt3ILEw== + +"@babel/parser@^7.16.0", "@babel/parser@^7.16.3": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" + integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.2": + version "7.16.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.2.tgz#2977fca9b212db153c195674e57cfab807733183" + integrity sha512-h37CvpLSf8gb2lIJ2CgC3t+EjFbi0t8qS7LCS1xcJIlEXE4czlofwaW7W1HA8zpgOCzI9C1nmoqNR1zWkk0pQg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.0.tgz#358972eaab006f5eb0826183b0c93cbcaf13e1e2" + integrity sha512-4tcFwwicpWTrpl9qjf7UsoosaArgImF85AxqCRZlgc3IQDvkUHjJpruXAL58Wmj+T6fypWTC/BakfEkwIL/pwA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.0" + +"@babel/plugin-proposal-async-generator-functions@^7.16.4": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.4.tgz#e606eb6015fec6fa5978c940f315eae4e300b081" + integrity sha512-/CUekqaAaZCQHleSK/9HajvcD/zdnJiKRiuUFq8ITE+0HsPzquf53cpFiqAwl/UfmJbR6n5uGPQSPdrmKOvHHg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.16.4" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz#c029618267ddebc7280fa286e0f8ca2a278a2d1a" + integrity sha512-mCF3HcuZSY9Fcx56Lbn+CGdT44ioBMMvjNVldpKtj8tpniETdLjnxdHI1+sDWXIM1nNt+EanJOZ3IG9lzVjs7A== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-class-static-block@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.0.tgz#5296942c564d8144c83eea347d0aa8a0b89170e7" + integrity sha512-mAy3sdcY9sKAkf3lQbDiv3olOfiLqI51c9DR9b19uMoR2Z6r5pmGl7dfNFqEvqOyqbf1ta4lknK4gc5PJn3mfA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-dynamic-import@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz#783eca61d50526202f9b296095453977e88659f1" + integrity sha512-QGSA6ExWk95jFQgwz5GQ2Dr95cf7eI7TKutIXXTb7B1gCLTCz5hTjFTQGfLFBBiC5WSNi7udNwWsqbbMh1c4yQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz#9c01dee40b9d6b847b656aaf4a3976a71740f222" + integrity sha512-CjI4nxM/D+5wCnhD11MHB1AwRSAYeDT+h8gCdcVJZ/OK7+wRzFsf7PFPWVpVpNRkHMmMkQWAHpTq+15IXQ1diA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz#cae35a95ed1d2a7fa29c4dc41540b84a72e9ab25" + integrity sha512-kouIPuiv8mSi5JkEhzApg5Gn6hFyKPnlkO0a9YSzqRurH8wYzSlf6RJdzluAsbqecdW5pBvDJDfyDIUR/vLxvg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz#a711b8ceb3ffddd3ef88d3a49e86dbd3cc7db3fd" + integrity sha512-pbW0fE30sVTYXXm9lpVQQ/Vc+iTeQKiXlaNRZPPN2A2VdlWyAtsUrsQ3xydSlDW00TFMK7a8m3cDTkBF5WnV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz#44e1cce08fe2427482cf446a91bb451528ed0596" + integrity sha512-3bnHA8CAFm7cG93v8loghDYyQ8r97Qydf63BeYiGgYbjKKB/XP53W15wfRC7dvKfoiJ34f6Rbyyx2btExc8XsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz#5d418e4fbbf8b9b7d03125d3a52730433a373734" + integrity sha512-FAhE2I6mjispy+vwwd6xWPyEx3NYFS13pikDBWUAFGZvq6POGs5eNchw8+1CYoEgBl9n11I3NkzD7ghn25PQ9Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz#def9bd03cea0f9b72283dac0ec22d289c7691069" + integrity sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-transform-parameters" "^7.12.1" + +"@babel/plugin-proposal-object-rest-spread@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz#5fb32f6d924d6e6712810362a60e12a2609872e6" + integrity sha512-LU/+jp89efe5HuWJLmMmFG0+xbz+I2rSI7iLc1AlaeSMDMOGzWlc5yJrMN1d04osXN4sSfpo4O+azkBNBes0jg== + dependencies: + "@babel/compat-data" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.16.0" + +"@babel/plugin-proposal-optional-catch-binding@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz#5910085811ab4c28b00d6ebffa4ab0274d1e5f16" + integrity sha512-kicDo0A/5J0nrsCPbn89mTG3Bm4XgYi0CZtvex9Oyw7gGZE3HXGD0zpQNH+mo+tEfbo8wbmMvJftOwpmPy7aVw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz#56dbc3970825683608e9efb55ea82c2a2d6c8dc0" + integrity sha512-Y4rFpkZODfHrVo70Uaj6cC1JJOt3Pp0MdWSwIKtb8z1/lsjl9AmnB7ErRFV+QNGIfcY1Eruc2UMx5KaRnXjMyg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz#b4dafb9c717e4301c5776b30d080d6383c89aff6" + integrity sha512-IvHmcTHDFztQGnn6aWq4t12QaBXTKr1whF/dgp9kz84X6GUcwq9utj7z2wFCUfeOup/QKnOlt2k0zxkGFx9ubg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-private-property-in-object@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.0.tgz#69e935b2c5c79d2488112d886f0c4e2790fee76f" + integrity sha512-3jQUr/HBbMVZmi72LpjQwlZ55i1queL8KcDTQEkAHihttJnAPrcvG9ZNXIfsd2ugpizZo595egYV6xy+pv4Ofw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz#890482dfc5ea378e42e19a71e709728cabf18612" + integrity sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz#bebde51339be829c17aaaaced18641deb62b39ba" + integrity sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.12.13" + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz#9d9d357cc818aa7ae7935917c1257f67677a0926" + integrity sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-jsx@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.0.tgz#f9624394317365a9a88c82358d3f8471154698f1" + integrity sha512-8zv2+xiPHwly31RK4RmnEYY5zziuF3O7W2kIDW+07ewWDh6Oi0dRq8kwvulRkFgt6DB97RlKs5c1y068iPlCUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@7.8.3", "@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.0.tgz#2feeb13d9334cc582ea9111d3506f773174179bb" + integrity sha512-Xv6mEXqVdaqCBfJFyeab0fH2DnUoMsDmhamxsSi4j8nLd4Vtw213WMJr55xxqipC/YVWyPY3K0blJncPYji+dQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-arrow-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz#951706f8b449c834ed07bd474c0924c944b95a8e" + integrity sha512-vIFb5250Rbh7roWARvCLvIJ/PtAU5Lhv7BtZ1u24COwpI9Ypjsh+bZcKk6rlIyalK+r0jOc1XQ8I4ovNxNrWrA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-async-to-generator@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz#df12637f9630ddfa0ef9d7a11bc414d629d38604" + integrity sha512-PbIr7G9kR8tdH6g8Wouir5uVjklETk91GMVSUq+VaOgiinbCkBP6Q7NN/suM/QutZkMJMvcyAriogcYAdhg8Gw== + dependencies: + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.16.0" + +"@babel/plugin-transform-block-scoped-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz#c618763233ad02847805abcac4c345ce9de7145d" + integrity sha512-V14As3haUOP4ZWrLJ3VVx5rCnrYhMSHN/jX7z6FAt5hjRkLsb0snPCmJwSOML5oxkKO4FNoNv7V5hw/y2bjuvg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-block-scoping@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz#bcf433fb482fe8c3d3b4e8a66b1c4a8e77d37c16" + integrity sha512-27n3l67/R3UrXfizlvHGuTwsRIFyce3D/6a37GRxn28iyTPvNXaW4XvznexRh1zUNLPjbLL22Id0XQElV94ruw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-classes@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz#54cf5ff0b2242c6573d753cd4bfc7077a8b282f5" + integrity sha512-HUxMvy6GtAdd+GKBNYDWCIA776byUQH8zjnfjxwT1P1ARv/wFu8eBDpmXQcLS/IwRtrxIReGiplOwMeyO7nsDQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz#e0c385507d21e1b0b076d66bed6d5231b85110b7" + integrity sha512-63l1dRXday6S8V3WFY5mXJwcRAnPYxvFfTlt67bwV1rTyVTM5zrp0DBBb13Kl7+ehkCVwIZPumPpFP/4u70+Tw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-destructuring@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz#ad3d7e74584ad5ea4eadb1e6642146c590dee33c" + integrity sha512-Q7tBUwjxLTsHEoqktemHBMtb3NYwyJPTJdM+wDwb0g8PZ3kQUIzNvwD5lPaqW/p54TXBc/MXZu9Jr7tbUEUM8Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-dotall-regex@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz#50bab00c1084b6162d0a58a818031cf57798e06f" + integrity sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz#3f1601cc29905bfcb67f53910f197aeafebb25ad" + integrity sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.12.13" + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-transform-duplicate-keys@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz#8bc2e21813e3e89e5e5bf3b60aa5fc458575a176" + integrity sha512-LIe2kcHKAZOJDNxujvmp6z3mfN6V9lJxubU4fJIGoQCkKe3Ec2OcbdlYP+vW++4MpxwG0d1wSDOJtQW5kLnkZQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-exponentiation-operator@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz#a180cd2881e3533cef9d3901e48dad0fbeff4be4" + integrity sha512-OwYEvzFI38hXklsrbNivzpO3fh87skzx8Pnqi4LoSYeav0xHlueSoCJrSgTPfnbyzopo5b3YVAJkFIcUpK2wsw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-for-of@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz#f7abaced155260e2461359bbc7c7248aca5e6bd2" + integrity sha512-5QKUw2kO+GVmKr2wMYSATCTTnHyscl6sxFRAY+rvN7h7WB0lcG0o4NoV6ZQU32OZGVsYUsfLGgPQpDFdkfjlJQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-function-name@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz#02e3699c284c6262236599f751065c5d5f1f400e" + integrity sha512-lBzMle9jcOXtSOXUpc7tvvTpENu/NuekNJVova5lCCWCV9/U1ho2HH2y0p6mBg8fPm/syEAbfaaemYGOHCY3mg== + dependencies: + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-literals@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz#79711e670ffceb31bd298229d50f3621f7980cac" + integrity sha512-gQDlsSF1iv9RU04clgXqRjrPyyoJMTclFt3K1cjLmTKikc0s/6vE3hlDeEVC71wLTRu72Fq7650kABrdTc2wMQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-member-expression-literals@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz#5251b4cce01eaf8314403d21aedb269d79f5e64b" + integrity sha512-WRpw5HL4Jhnxw8QARzRvwojp9MIE7Tdk3ez6vRyUk1MwgjJN0aNpRoXainLR5SgxmoXx/vsXGZ6OthP6t/RbUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-modules-amd@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz#09abd41e18dcf4fd479c598c1cef7bd39eb1337e" + integrity sha512-rWFhWbCJ9Wdmzln1NmSCqn7P0RAD+ogXG/bd9Kg5c7PKWkJtkiXmYsMBeXjDlzHpVTJ4I/hnjs45zX4dEv81xw== + dependencies: + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz#add58e638c8ddc4875bd9a9ecb5c594613f6c922" + integrity sha512-Dzi+NWqyEotgzk/sb7kgQPJQf7AJkQBWsVp1N6JWc1lBVo0vkElUnGdr1PzUBmfsCCN5OOFya3RtpeHk15oLKQ== + dependencies: + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-simple-access" "^7.16.0" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz#a92cf240afeb605f4ca16670453024425e421ea4" + integrity sha512-yuGBaHS3lF1m/5R+6fjIke64ii5luRUg97N2wr+z1sF0V+sNSXPxXDdEEL/iYLszsN5VKxVB1IPfEqhzVpiqvg== + dependencies: + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-identifier" "^7.15.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz#195f26c2ad6d6a391b70880effce18ce625e06a7" + integrity sha512-nx4f6no57himWiHhxDM5pjwhae5vLpTK2zCnDH8+wNLJy0TVER/LJRHl2bkt6w9Aad2sPD5iNNoUpY3X9sTGDg== + dependencies: + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz#d3db61cc5d5b97986559967cd5ea83e5c32096ca" + integrity sha512-LogN88uO+7EhxWc8WZuQ8vxdSyVGxhkh8WTC3tzlT8LccMuQdA81e9SGV6zY7kY2LjDhhDOFdQVxdGwPyBCnvg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + +"@babel/plugin-transform-new-target@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz#af823ab576f752215a49937779a41ca65825ab35" + integrity sha512-fhjrDEYv2DBsGN/P6rlqakwRwIp7rBGLPbrKxwh7oVt5NNkIhZVOY2GRV+ULLsQri1bDqwDWnU3vhlmx5B2aCw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-object-super@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz#fb20d5806dc6491a06296ac14ea8e8d6fedda72b" + integrity sha512-fds+puedQHn4cPLshoHcR1DTMN0q1V9ou0mUjm8whx9pGcNvDrVVrgw+KJzzCaiTdaYhldtrUps8DWVMgrSEyg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.16.0" + +"@babel/plugin-transform-parameters@^7.12.1": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz#8fa7603e3097f9c0b7ca1a4821bc2fb52e9e5007" + integrity sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/plugin-transform-parameters@^7.16.0", "@babel/plugin-transform-parameters@^7.16.3": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.3.tgz#fa9e4c874ee5223f891ee6fa8d737f4766d31d15" + integrity sha512-3MaDpJrOXT1MZ/WCmkOFo7EtmVVC8H4EUZVrHvFOsmwkk4lOjQj8rzv8JKUZV4YoQKeoIgk07GO+acPU9IMu/w== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz#a95c552189a96a00059f6776dc4e00e3690c78d1" + integrity sha512-XLldD4V8+pOqX2hwfWhgwXzGdnDOThxaNTgqagOcpBgIxbUvpgU2FMvo5E1RyHbk756WYgdbS0T8y0Cj9FKkWQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-react-constant-elements@^7.12.1": + version "7.13.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.13.13.tgz#0208b1d942bf939cd4f7aa5b255d42602aa4a920" + integrity sha512-SNJU53VM/SjQL0bZhyU+f4kJQz7bQQajnrZRSaU21hruG/NWY41AEM9AWXeXX90pYr/C2yAmTgI6yW3LlLrAUQ== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/plugin-transform-react-display-name@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.0.tgz#9a0ad8aa8e8790883a7bd2736f66229a58125676" + integrity sha512-FJFdJAqaCpndL+pIf0aeD/qlQwT7QXOvR6Cc8JPvNhKJBi2zc/DPc4g05Y3fbD/0iWAMQFGij4+Xw+4L/BMpTg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-react-jsx-development@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.0.tgz#1cb52874678d23ab11d0d16488d54730807303ef" + integrity sha512-qq65iSqBRq0Hr3wq57YG2AmW0H6wgTnIzpffTphrUWUgLCOK+zf1f7G0vuOiXrp7dU1qq+fQBoqZ3wCDAkhFzw== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.16.0" + +"@babel/plugin-transform-react-jsx@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.0.tgz#55b797d4960c3de04e07ad1c0476e2bc6a4889f1" + integrity sha512-rqDgIbukZ44pqq7NIRPGPGNklshPkvlmvqjdx3OZcGPk4zGIenYkxDTvl3LsSL8gqcc3ZzGmXPE6hR/u/voNOw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-jsx" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/plugin-transform-react-pure-annotations@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.0.tgz#23db6ddf558d8abde41b8ad9d59f48ad5532ccab" + integrity sha512-NC/Bj2MG+t8Ef5Pdpo34Ay74X4Rt804h5y81PwOpfPtmAK3i6CizmQqwyBQzIepz1Yt8wNr2Z2L7Lu3qBMfZMA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-regenerator@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz#eaee422c84b0232d03aea7db99c97deeaf6125a4" + integrity sha512-JAvGxgKuwS2PihiSFaDrp94XOzzTUeDeOQlcKzVAyaPap7BnZXK/lvMDiubkPTdotPKOIZq9xWXWnggUMYiExg== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz#fff4b9dcb19e12619394bda172d14f2d04c0379c" + integrity sha512-Dgs8NNCehHSvXdhEhln8u/TtJxfVwGYCgP2OOr5Z3Ar+B+zXicEOKNTyc+eca2cuEOMtjW6m9P9ijOt8QdqWkg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-runtime@^7.12.15": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.4.tgz#f9ba3c7034d429c581e1bd41b4952f3db3c2c7e8" + integrity sha512-pru6+yHANMTukMtEZGC4fs7XPwg35v8sj5CIEmE+gEkFljFiVJxEWxx/7ZDkTK+iZRYo1bFXBtfIN95+K3cJ5A== + dependencies: + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.4.0" + babel-plugin-polyfill-regenerator "^0.3.0" + semver "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz#090372e3141f7cc324ed70b3daf5379df2fa384d" + integrity sha512-iVb1mTcD8fuhSv3k99+5tlXu5N0v8/DPm2mO3WACLG6al1CGZH7v09HJyUb1TtYl/Z+KrM6pHSIJdZxP5A+xow== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-spread@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz#d21ca099bbd53ab307a8621e019a7bd0f40cdcfb" + integrity sha512-Ao4MSYRaLAQczZVp9/7E7QHsCuK92yHRrmVNRe/SlEJjhzivq0BSn8mEraimL8wizHZ3fuaHxKH0iwzI13GyGg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + +"@babel/plugin-transform-sticky-regex@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz#c35ea31a02d86be485f6aa510184b677a91738fd" + integrity sha512-/ntT2NljR9foobKk4E/YyOSwcGUXtYWv5tinMK/3RkypyNBNdhHUaq6Orw5DWq9ZcNlS03BIlEALFeQgeVAo4Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-template-literals@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz#a8eced3a8e7b8e2d40ec4ec4548a45912630d302" + integrity sha512-Rd4Ic89hA/f7xUSJQk5PnC+4so50vBoBfxjdQAdvngwidM8jYIBVxBZ/sARxD4e0yMXRbJVDrYf7dyRtIIKT6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-typeof-symbol@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz#8b19a244c6f8c9d668dca6a6f754ad6ead1128f2" + integrity sha512-++V2L8Bdf4vcaHi2raILnptTBjGEFxn5315YU+e8+EqXIucA+q349qWngCLpUYqqv233suJ6NOienIVUpS9cqg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-typescript@^7.16.0": + version "7.16.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.1.tgz#cc0670b2822b0338355bc1b3d2246a42b8166409" + integrity sha512-NO4XoryBng06jjw/qWEU2LhcLJr1tWkhpMam/H4eas/CDKMX/b2/Ylb6EI256Y7+FVPCawwSM1rrJNOpDiz+Lg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-typescript" "^7.16.0" + +"@babel/plugin-transform-unicode-escapes@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz#1a354064b4c45663a32334f46fa0cf6100b5b1f3" + integrity sha512-VFi4dhgJM7Bpk8lRc5CMaRGlKZ29W9C3geZjt9beuzSUrlJxsNwX7ReLwaL6WEvsOf2EQkyIJEPtF8EXjB/g2A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-unicode-regex@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz#293b80950177c8c85aede87cef280259fb995402" + integrity sha512-jHLK4LxhHjvCeZDWyA9c+P9XH1sOxRd1RO9xMtDVRAOND/PczPqizEtVdx4TQF/wyPaewqpT+tgQFYMnN/P94A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.12.16": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.4.tgz#4f6ec33b2a3fe72d6bfdcdf3859500232563a2e3" + integrity sha512-v0QtNd81v/xKj4gNKeuAerQ/azeNn/G1B1qMLeXOcV8+4TWlD2j3NV1u8q29SDFBXx/NBq5kyEAO+0mpRgacjA== + dependencies: + "@babel/compat-data" "^7.16.4" + "@babel/helper-compilation-targets" "^7.16.3" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.2" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.0" + "@babel/plugin-proposal-async-generator-functions" "^7.16.4" + "@babel/plugin-proposal-class-properties" "^7.16.0" + "@babel/plugin-proposal-class-static-block" "^7.16.0" + "@babel/plugin-proposal-dynamic-import" "^7.16.0" + "@babel/plugin-proposal-export-namespace-from" "^7.16.0" + "@babel/plugin-proposal-json-strings" "^7.16.0" + "@babel/plugin-proposal-logical-assignment-operators" "^7.16.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.0" + "@babel/plugin-proposal-numeric-separator" "^7.16.0" + "@babel/plugin-proposal-object-rest-spread" "^7.16.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.0" + "@babel/plugin-proposal-private-methods" "^7.16.0" + "@babel/plugin-proposal-private-property-in-object" "^7.16.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.16.0" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.16.0" + "@babel/plugin-transform-async-to-generator" "^7.16.0" + "@babel/plugin-transform-block-scoped-functions" "^7.16.0" + "@babel/plugin-transform-block-scoping" "^7.16.0" + "@babel/plugin-transform-classes" "^7.16.0" + "@babel/plugin-transform-computed-properties" "^7.16.0" + "@babel/plugin-transform-destructuring" "^7.16.0" + "@babel/plugin-transform-dotall-regex" "^7.16.0" + "@babel/plugin-transform-duplicate-keys" "^7.16.0" + "@babel/plugin-transform-exponentiation-operator" "^7.16.0" + "@babel/plugin-transform-for-of" "^7.16.0" + "@babel/plugin-transform-function-name" "^7.16.0" + "@babel/plugin-transform-literals" "^7.16.0" + "@babel/plugin-transform-member-expression-literals" "^7.16.0" + "@babel/plugin-transform-modules-amd" "^7.16.0" + "@babel/plugin-transform-modules-commonjs" "^7.16.0" + "@babel/plugin-transform-modules-systemjs" "^7.16.0" + "@babel/plugin-transform-modules-umd" "^7.16.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.0" + "@babel/plugin-transform-new-target" "^7.16.0" + "@babel/plugin-transform-object-super" "^7.16.0" + "@babel/plugin-transform-parameters" "^7.16.3" + "@babel/plugin-transform-property-literals" "^7.16.0" + "@babel/plugin-transform-regenerator" "^7.16.0" + "@babel/plugin-transform-reserved-words" "^7.16.0" + "@babel/plugin-transform-shorthand-properties" "^7.16.0" + "@babel/plugin-transform-spread" "^7.16.0" + "@babel/plugin-transform-sticky-regex" "^7.16.0" + "@babel/plugin-transform-template-literals" "^7.16.0" + "@babel/plugin-transform-typeof-symbol" "^7.16.0" + "@babel/plugin-transform-unicode-escapes" "^7.16.0" + "@babel/plugin-transform-unicode-regex" "^7.16.0" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.16.0" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.4.0" + babel-plugin-polyfill-regenerator "^0.3.0" + core-js-compat "^3.19.1" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-react@^7.12.13", "@babel/preset-react@^7.12.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.16.0.tgz#f71d3e8dff5218478011df037fad52660ee6d82a" + integrity sha512-d31IFW2bLRB28uL1WoElyro8RH5l6531XfxMtCeCmp6RVAF1uTfxxUA0LH1tXl+psZdwfmIbwoG4U5VwgbhtLw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-transform-react-display-name" "^7.16.0" + "@babel/plugin-transform-react-jsx" "^7.16.0" + "@babel/plugin-transform-react-jsx-development" "^7.16.0" + "@babel/plugin-transform-react-pure-annotations" "^7.16.0" + +"@babel/preset-typescript@^7.12.16": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.0.tgz#b0b4f105b855fb3d631ec036cdc9d1ffd1fa5eac" + integrity sha512-txegdrZYgO9DlPbv+9QOVpMnKbOtezsLHWsnsRF4AjbSIsVaujrq1qg8HK0mxQpWv0jnejt0yEoW1uWpvbrDTg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-transform-typescript" "^7.16.0" + +"@babel/runtime-corejs3@^7.12.13": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.16.3.tgz#1e25de4fa994c57c18e5fdda6cc810dac70f5590" + integrity sha512-IAdDC7T0+wEB4y2gbIL0uOXEYpiZEeuFUTVbdGq+UwCcF35T/tS8KrmMomEwEc5wBbyfH3PJVpTSUqrhPDXFcQ== + dependencies: + core-js-pure "^3.19.0" + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5" + integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.12.13", "@babel/template@^7.12.7": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327" + integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@babel/parser" "^7.12.13" + "@babel/types" "^7.12.13" + +"@babel/template@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" + integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/traverse@^7.12.13", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.13.13", "@babel/traverse@^7.13.17", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" + integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/parser" "^7.16.3" + "@babel/types" "^7.16.0" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.12.13", "@babel/types@^7.12.6", "@babel/types@^7.12.7", "@babel/types@^7.13.12", "@babel/types@^7.13.14", "@babel/types@^7.13.17", "@babel/types@^7.4.4": + version "7.13.17" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.17.tgz#48010a115c9fba7588b4437dd68c9469012b38b4" + integrity sha512-RawydLgxbOPDlTLJNtoIypwdmAy//uQIzlKt2+iBiJaRlVuI6QLUxVAyWGNfOzp8Yu4L4lLIacoCyTNtpb4wiA== + dependencies: + "@babel/helper-validator-identifier" "^7.12.11" + to-fast-properties "^2.0.0" + +"@babel/types@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" + integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + to-fast-properties "^2.0.0" + +"@crowdin/cli@3": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@crowdin/cli/-/cli-3.7.7.tgz#0d2baf888b37aac1cd8d8cb484b0826fa7b82a26" + integrity sha512-wN0NXLDymC9PgT3I6jMx/YLjcEtegAnFg7VaavzLfc1vFegD4lKlrvRmc0qV2IIiRMZLShEsS0QtYtAyhi/qew== + dependencies: + shelljs "^0.8.4" + +"@docsearch/css@3.0.0-alpha.42": + version "3.0.0-alpha.42" + resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.0.0-alpha.42.tgz#deb6049e999d6ca9451eba4793cb5b6da28c8773" + integrity sha512-AGwI2AXUacYhVOHmYnsXoYDJKO6Ued2W+QO80GERbMLhC7GH5tfvtW5REs/s7jSdcU3vzFoxT8iPDBCh/PkrlQ== + +"@docsearch/react@^3.0.0-alpha.36": + version "3.0.0-alpha.42" + resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.0.0-alpha.42.tgz#1d22a2b05779f24d090ff8d7ff2699e4d50dff5c" + integrity sha512-1aOslZJDxwUUcm2QRNmlEePUgL8P5fOAeFdOLDMctHQkV2iTja9/rKVbkP8FZbIUnZxuuCCn8ErLrjD/oXWOag== + dependencies: + "@algolia/autocomplete-core" "1.5.0" + "@algolia/autocomplete-preset-algolia" "1.5.0" + "@docsearch/css" "3.0.0-alpha.42" + algoliasearch "^4.0.0" + +"@docusaurus/core@2.0.0-beta.759298296", "@docusaurus/core@^2.0.0-beta.10": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-beta.759298296.tgz#2390c401bf2ab46bf28eb93cd81759d682811388" + integrity sha512-qCvKt0KKjjMChAnlv1V/WocGNJ9up2uY9RKUzsBYIu0lKBGmrmmbPgXVJeQ/QYFqHtHR+qqYLfGsheRjXKXLbA== + dependencies: + "@babel/core" "^7.12.16" + "@babel/generator" "^7.12.15" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-transform-runtime" "^7.12.15" + "@babel/preset-env" "^7.12.16" + "@babel/preset-react" "^7.12.13" + "@babel/preset-typescript" "^7.12.16" + "@babel/runtime" "^7.12.5" + "@babel/runtime-corejs3" "^7.12.13" + "@babel/traverse" "^7.12.13" + "@docusaurus/cssnano-preset" "2.0.0-beta.759298296" + "@docusaurus/react-loadable" "5.5.0" + "@docusaurus/types" "2.0.0-beta.759298296" + "@docusaurus/utils" "2.0.0-beta.759298296" + "@docusaurus/utils-common" "2.0.0-beta.759298296" + "@docusaurus/utils-validation" "2.0.0-beta.759298296" + "@slorber/static-site-generator-webpack-plugin" "^4.0.0" + "@svgr/webpack" "^5.5.0" + autoprefixer "^10.2.5" + babel-loader "^8.2.2" + babel-plugin-dynamic-import-node "2.3.0" + boxen "^5.0.1" + chalk "^4.1.1" + chokidar "^3.5.1" + clean-css "^5.1.2" + commander "^5.1.0" + copy-webpack-plugin "^9.0.0" + core-js "^3.9.1" + css-loader "^5.1.1" + css-minimizer-webpack-plugin "^3.0.1" + cssnano "^5.0.4" + del "^6.0.0" + detect-port "^1.3.0" + escape-html "^1.0.3" + eta "^1.12.1" + express "^4.17.1" + file-loader "^6.2.0" + fs-extra "^10.0.0" + github-slugger "^1.3.0" + globby "^11.0.2" + html-minifier-terser "^5.1.1" + html-tags "^3.1.0" + html-webpack-plugin "^5.3.2" + import-fresh "^3.3.0" + is-root "^2.1.0" + leven "^3.1.0" + lodash "^4.17.20" + mini-css-extract-plugin "^1.6.0" + module-alias "^2.2.2" + nprogress "^0.2.0" + postcss "^8.2.15" + postcss-loader "^5.3.0" + prompts "^2.4.1" + react-dev-utils "^11.0.1" + react-error-overlay "^6.0.9" + react-helmet "^6.1.0" + react-loadable "^5.5.0" + react-loadable-ssr-addon-v5-slorber "^1.0.1" + react-router "^5.2.0" + react-router-config "^5.1.1" + react-router-dom "^5.2.0" + resolve-pathname "^3.0.0" + rtl-detect "^1.0.3" + semver "^7.3.4" + serve-handler "^6.1.3" + shelljs "^0.8.4" + std-env "^2.2.1" + strip-ansi "^6.0.0" + terser-webpack-plugin "^5.1.3" + tslib "^2.2.0" + update-notifier "^5.1.0" + url-loader "^4.1.1" + wait-on "^5.3.0" + webpack "^5.40.0" + webpack-bundle-analyzer "^4.4.2" + webpack-dev-server "^3.11.2" + webpack-merge "^5.8.0" + webpackbar "^5.0.0-3" + +"@docusaurus/cssnano-preset@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.0.0-beta.759298296.tgz#f5c4b5aae787fddebdd362e29da508cb97ccb932" + integrity sha512-JorG6umrBUxooQ3xbYKh9htmCQTdpzpVjEMdWgBjIn8DZWHH3e+u9IfcemAWz8GUm7wUz94PxDYKiXIICaZ0xA== + dependencies: + cssnano-preset-advanced "^5.1.1" + postcss "^8.2.15" + postcss-sort-media-queries "^3.10.11" + +"@docusaurus/mdx-loader@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.759298296.tgz#9c56162e58dc24cb384c5c6ed4e414700b8bdffd" + integrity sha512-sEiWj5Aehxs8JeqUsa/lfKbiEmJZpQU84drSXlejaW2NvEATuIqnNlWkGHEkK9t2qVx3/gwUFhaEt+dumttDVA== + dependencies: + "@babel/parser" "^7.12.16" + "@babel/traverse" "^7.12.13" + "@docusaurus/core" "2.0.0-beta.759298296" + "@docusaurus/utils" "2.0.0-beta.759298296" + "@mdx-js/mdx" "^1.6.21" + "@mdx-js/react" "^1.6.21" + escape-html "^1.0.3" + file-loader "^6.2.0" + fs-extra "^10.0.0" + github-slugger "^1.3.0" + gray-matter "^4.0.3" + mdast-util-to-string "^2.0.0" + remark-emoji "^2.1.0" + stringify-object "^3.3.0" + unist-util-visit "^2.0.2" + url-loader "^4.1.1" + webpack "^5.40.0" + +"@docusaurus/plugin-content-blog@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.759298296.tgz#48fc2350ecfeb18c4dbdf0fe514d73dd278708cd" + integrity sha512-EzfiGmfsY60Q6r53oGAxa2/643Rrs/QTLdFi3TbsFMfPZyg8sutNDdFbIXWMaDeQeO9qlreqT4wESxV3GltZkw== + dependencies: + "@docusaurus/core" "2.0.0-beta.759298296" + "@docusaurus/mdx-loader" "2.0.0-beta.759298296" + "@docusaurus/types" "2.0.0-beta.759298296" + "@docusaurus/utils" "2.0.0-beta.759298296" + "@docusaurus/utils-validation" "2.0.0-beta.759298296" + chalk "^4.1.1" + escape-string-regexp "^4.0.0" + feed "^4.2.2" + fs-extra "^10.0.0" + globby "^11.0.2" + loader-utils "^2.0.0" + lodash "^4.17.20" + reading-time "^1.3.0" + remark-admonitions "^1.2.1" + tslib "^2.2.0" + webpack "^5.40.0" + +"@docusaurus/plugin-content-docs@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.759298296.tgz#171d37add12c08ca5728c1e99f8cde9b2e4cd76c" + integrity sha512-I7cw05gIwaTvJ4vPXj6Kul3Cmo0DeoiSv3zLraL6WZyWOPmvvj0Lj2RMDvXO4ovEuzWGqTykpWRrJbvC/Q5VHg== + dependencies: + "@docusaurus/core" "2.0.0-beta.759298296" + "@docusaurus/mdx-loader" "2.0.0-beta.759298296" + "@docusaurus/types" "2.0.0-beta.759298296" + "@docusaurus/utils" "2.0.0-beta.759298296" + "@docusaurus/utils-validation" "2.0.0-beta.759298296" + chalk "^4.1.1" + combine-promises "^1.1.0" + escape-string-regexp "^4.0.0" + execa "^5.0.0" + fs-extra "^10.0.0" + globby "^11.0.2" + import-fresh "^3.2.2" + js-yaml "^4.0.0" + loader-utils "^1.2.3" + lodash "^4.17.20" + remark-admonitions "^1.2.1" + shelljs "^0.8.4" + tslib "^2.2.0" + utility-types "^3.10.0" + webpack "^5.40.0" + +"@docusaurus/plugin-content-pages@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.759298296.tgz#8b6e709b6b3a0935effffaec99a3068d245bbb7e" + integrity sha512-l/FNV1op2zrwTmSWrLVOghtfMpEoaXROvF19c7tU382BuRLi8fz0TixN/ZDr7f8avoN7smZ8j5HzaLb9lh6kZg== + dependencies: + "@docusaurus/core" "2.0.0-beta.759298296" + "@docusaurus/mdx-loader" "2.0.0-beta.759298296" + "@docusaurus/types" "2.0.0-beta.759298296" + "@docusaurus/utils" "2.0.0-beta.759298296" + "@docusaurus/utils-validation" "2.0.0-beta.759298296" + globby "^11.0.2" + lodash "^4.17.20" + minimatch "^3.0.4" + remark-admonitions "^1.2.1" + slash "^3.0.0" + tslib "^2.1.0" + webpack "^5.40.0" + +"@docusaurus/plugin-debug@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-beta.759298296.tgz#dcca80e4bd9a4f7ff3f49445a3b8abdd8af41f15" + integrity sha512-P1TVKBnWEWp/Q3gV8RcFH/kFY1fpgHABO4tjPqC6MOXrPURMGaBmqkicWzgg3ntoIIrqZthkjVLvyXAnPPpAIg== + dependencies: + "@docusaurus/core" "2.0.0-beta.759298296" + "@docusaurus/types" "2.0.0-beta.759298296" + "@docusaurus/utils" "2.0.0-beta.759298296" + react-json-view "^1.21.3" + tslib "^2.1.0" + +"@docusaurus/plugin-google-analytics@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.759298296.tgz#a66e1ea1e6635766d22b0ccf12fd72de0899367a" + integrity sha512-/LiLgSD8QI1DhXriZWSSoSmhtCYmvEDl6LyeeFuZV2gxMmBoqaAnb90d/fXWfaMMF2z7kcqUQOBhXb1aXTl8Gw== + dependencies: + "@docusaurus/core" "2.0.0-beta.759298296" + +"@docusaurus/plugin-google-gtag@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-beta.759298296.tgz#fa19004ee3355ff2e8ba65485cf4a82518ab4562" + integrity sha512-2bonG4VES4Ab3SZVv5VpgiCyqctpO7AtpHRF+r7+F3+NtlNV398Ov8mOuXkdcWLqM+xh3syHnqCeoAUzFjyBVw== + dependencies: + "@docusaurus/core" "2.0.0-beta.759298296" + +"@docusaurus/plugin-sitemap@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-beta.759298296.tgz#6e0a82fe85057f5972f260b636cbf7599abadb18" + integrity sha512-+Pv6CoBMufPmh1eqmOf+cMTdUOtpl5xh5Ggdt7FRpZABNTrAXCEdU3wv/s/vYx2+aXYB1LFhBUdMidZ41HMlMg== + dependencies: + "@docusaurus/core" "2.0.0-beta.759298296" + "@docusaurus/types" "2.0.0-beta.759298296" + "@docusaurus/utils" "2.0.0-beta.759298296" + "@docusaurus/utils-common" "2.0.0-beta.759298296" + "@docusaurus/utils-validation" "2.0.0-beta.759298296" + fs-extra "^10.0.0" + sitemap "^7.0.0" + tslib "^2.2.0" + +"@docusaurus/preset-classic@^2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-beta.759298296.tgz#6e1b3c8aed580f6e45fbf16151978530ca180410" + integrity sha512-NNkjwbN8G/GiQM8FukgIhQjmjjE23aKBny8q9wNVFdn/FGfLBXz21dEUQzqeaAfrr9xWLKOBeNFIJU1DTv98rg== + dependencies: + "@docusaurus/core" "2.0.0-beta.759298296" + "@docusaurus/plugin-content-blog" "2.0.0-beta.759298296" + "@docusaurus/plugin-content-docs" "2.0.0-beta.759298296" + "@docusaurus/plugin-content-pages" "2.0.0-beta.759298296" + "@docusaurus/plugin-debug" "2.0.0-beta.759298296" + "@docusaurus/plugin-google-analytics" "2.0.0-beta.759298296" + "@docusaurus/plugin-google-gtag" "2.0.0-beta.759298296" + "@docusaurus/plugin-sitemap" "2.0.0-beta.759298296" + "@docusaurus/theme-classic" "2.0.0-beta.759298296" + "@docusaurus/theme-search-algolia" "2.0.0-beta.759298296" + +"@docusaurus/react-loadable@5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@docusaurus/react-loadable/-/react-loadable-5.5.0.tgz#6d6f0c8fd9a434b62a1ab1f8645ee7bde5a9ec21" + integrity sha512-Ld/kwUE6yATIOTLq3JCsWiTa/drisajwKqBQ2Rw6IcT+sFsKfYek8F2jSH8f68AT73xX97UehduZeCSlnuCBIg== + dependencies: + prop-types "^15.6.2" + +"@docusaurus/theme-classic@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-beta.759298296.tgz#5b5a67be17527e870eda62648dab15ce9bf117bb" + integrity sha512-EKvthWxalq1wh0LQCC0mOzUjwBOytg2gg6Z6yFeDQiqR940VEZUy/7nKOA0QrK6dPjB2yhICXamJ3xZ40GsfPg== + dependencies: + "@docusaurus/core" "2.0.0-beta.759298296" + "@docusaurus/plugin-content-blog" "2.0.0-beta.759298296" + "@docusaurus/plugin-content-docs" "2.0.0-beta.759298296" + "@docusaurus/plugin-content-pages" "2.0.0-beta.759298296" + "@docusaurus/theme-common" "2.0.0-beta.759298296" + "@docusaurus/types" "2.0.0-beta.759298296" + "@docusaurus/utils" "2.0.0-beta.759298296" + "@docusaurus/utils-common" "2.0.0-beta.759298296" + "@docusaurus/utils-validation" "2.0.0-beta.759298296" + "@mdx-js/mdx" "^1.6.21" + "@mdx-js/react" "^1.6.21" + chalk "^4.1.1" + clsx "^1.1.1" + copy-text-to-clipboard "^3.0.1" + fs-extra "^10.0.0" + globby "^11.0.2" + infima "0.2.0-alpha.26" + lodash "^4.17.20" + parse-numeric-range "^1.2.0" + postcss "^8.2.15" + prism-react-renderer "^1.2.1" + prismjs "^1.23.0" + prop-types "^15.7.2" + react-router-dom "^5.2.0" + rtlcss "^3.1.2" + +"@docusaurus/theme-common@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.0.0-beta.759298296.tgz#917156961a0c8b162dfb72280b62d34b92f83183" + integrity sha512-OlFHH9ukTYXkh2Q+7Cd29JYA2JMwhLA/vkZMTpLjjmR1w2MiaCfB3wF1qq+C84EZ7hrmWrI2fHoJmkXVDIVTiQ== + dependencies: + "@docusaurus/core" "2.0.0-beta.759298296" + "@docusaurus/plugin-content-blog" "2.0.0-beta.759298296" + "@docusaurus/plugin-content-docs" "2.0.0-beta.759298296" + "@docusaurus/plugin-content-pages" "2.0.0-beta.759298296" + "@docusaurus/types" "2.0.0-beta.759298296" + tslib "^2.1.0" + +"@docusaurus/theme-search-algolia@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-beta.759298296.tgz#c9e9b1b43267af757c4ceac72010328aa3f6a3fd" + integrity sha512-+JHLK2PL88NoJh6JFYeUgjPjxWq3n2SepNnFj+7rX7lymXmaVdSy7nQKpM8FpkN0Q23zCdYpdnm+y+fgBBPojg== + dependencies: + "@docsearch/react" "^3.0.0-alpha.36" + "@docusaurus/core" "2.0.0-beta.759298296" + "@docusaurus/theme-common" "2.0.0-beta.759298296" + "@docusaurus/utils" "2.0.0-beta.759298296" + "@docusaurus/utils-validation" "2.0.0-beta.759298296" + algoliasearch "^4.8.4" + algoliasearch-helper "^3.3.4" + clsx "^1.1.1" + eta "^1.12.1" + lodash "^4.17.20" + +"@docusaurus/types@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-beta.759298296.tgz#27b48ce8e55aa8548c405e087b245e5b7699131e" + integrity sha512-1qk9qRHZGHiZbwUr6YY41DFOA451QMlHf3zFhNPr7hGxyPPbbzvo+awEpEwhniTgoGjlPNRjw/KJEu0kRUl5OQ== + dependencies: + commander "^5.1.0" + joi "^17.4.0" + querystring "0.2.0" + webpack "^5.40.0" + webpack-merge "^5.8.0" + +"@docusaurus/utils-common@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.0.0-beta.759298296.tgz#228aa5eae19666c5ccff3cd0b172cbca01a2fdf5" + integrity sha512-it0LfFUPEEOXYB5xi/moeH1dJ43bBAE41kvfYefBwN4YRprziFNKcv3vk+xcBPscpUksoEATSbaIBFWvvgjVvQ== + dependencies: + "@docusaurus/types" "2.0.0-beta.759298296" + tslib "^2.2.0" + +"@docusaurus/utils-validation@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.759298296.tgz#ed264ed2c524ab34127356ae099232f25a564f2b" + integrity sha512-Zn7eAo+q/DdDgRscj5bNw8eTdLOFT8U9BNpdYRCC9sMMQR+shgkuKL3gKlC/wDOWEx4nQd1R83bLhmPTXppE2A== + dependencies: + "@docusaurus/utils" "2.0.0-beta.759298296" + chalk "^4.1.1" + joi "^17.4.0" + tslib "^2.1.0" + +"@docusaurus/utils@2.0.0-beta.759298296": + version "2.0.0-beta.759298296" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-beta.759298296.tgz#d7d404b0982583c5baa38fa844c863c5ec6907ac" + integrity sha512-QQCgNVu2Vuuw9m2k0iX4CFSR9emSTHs20A7tdoNl+WRcep8DjtG0Oy2TyQTH3C7l2l46jSzbCG1wHtf3hKLvjg== + dependencies: + "@docusaurus/types" "2.0.0-beta.759298296" + "@types/github-slugger" "^1.3.0" + chalk "^4.1.1" + escape-string-regexp "^4.0.0" + fs-extra "^10.0.0" + gray-matter "^4.0.3" + lodash "^4.17.20" + resolve-pathname "^3.0.0" + tslib "^2.2.0" + +"@hapi/hoek@^9.0.0": + version "9.2.0" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.0.tgz#f3933a44e365864f4dad5db94158106d511e8131" + integrity sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug== + +"@hapi/topo@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.0.0.tgz#c19af8577fa393a06e9c77b60995af959be721e7" + integrity sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@mdx-js/mdx@^1.6.21": + version "1.6.22" + resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-1.6.22.tgz#8a723157bf90e78f17dc0f27995398e6c731f1ba" + integrity sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA== + dependencies: + "@babel/core" "7.12.9" + "@babel/plugin-syntax-jsx" "7.12.1" + "@babel/plugin-syntax-object-rest-spread" "7.8.3" + "@mdx-js/util" "1.6.22" + babel-plugin-apply-mdx-type-prop "1.6.22" + babel-plugin-extract-import-names "1.6.22" + camelcase-css "2.0.1" + detab "2.0.4" + hast-util-raw "6.0.1" + lodash.uniq "4.5.0" + mdast-util-to-hast "10.0.1" + remark-footnotes "2.0.0" + remark-mdx "1.6.22" + remark-parse "8.0.3" + remark-squeeze-paragraphs "4.0.0" + style-to-object "0.3.0" + unified "9.2.0" + unist-builder "2.0.3" + unist-util-visit "2.0.3" + +"@mdx-js/react@^1.6.21": + version "1.6.22" + resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-1.6.22.tgz#ae09b4744fddc74714ee9f9d6f17a66e77c43573" + integrity sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg== + +"@mdx-js/util@1.6.22": + version "1.6.22" + resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b" + integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA== + +"@nodelib/fs.scandir@2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69" + integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA== + dependencies: + "@nodelib/fs.stat" "2.0.4" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655" + integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063" + integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow== + dependencies: + "@nodelib/fs.scandir" "2.1.4" + fastq "^1.6.0" + +"@polka/url@^1.0.0-next.9": + version "1.0.0-next.12" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.12.tgz#431ec342a7195622f86688bbda82e3166ce8cb28" + integrity sha512-6RglhutqrGFMO1MNUXp95RBuYIuc8wTnMAV5MUhLmjTOy78ncwOw7RgeQ/HeymkKXRhZd0s2DNrM1rL7unk3MQ== + +"@sideway/address@^4.1.0": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.1.tgz#9e321e74310963fdf8eebfbee09c7bd69972de4d" + integrity sha512-+I5aaQr3m0OAmMr7RQ3fR9zx55sejEYR2BFJaxL+zT3VM2611X0SHvPWIbAUBZVTn/YzYKbV8gJ2oT/QELknfQ== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/address@^4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" + integrity sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" + integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + +"@slorber/static-site-generator-webpack-plugin@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.1.tgz#0c8852146441aaa683693deaa5aee2f991d94841" + integrity sha512-PSv4RIVO1Y3kvHxjvqeVisk3E9XFoO04uwYBDWe217MFqKspplYswTuKLiJu0aLORQWzuQjfVsSlLPojwfYsLw== + dependencies: + bluebird "^3.7.1" + cheerio "^0.22.0" + eval "^0.1.4" + url "^0.11.0" + webpack-sources "^1.4.3" + +"@svgr/babel-plugin-add-jsx-attribute@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz#81ef61947bb268eb9d50523446f9c638fb355906" + integrity sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg== + +"@svgr/babel-plugin-remove-jsx-attribute@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz#6b2c770c95c874654fd5e1d5ef475b78a0a962ef" + integrity sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg== + +"@svgr/babel-plugin-remove-jsx-empty-expression@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz#25621a8915ed7ad70da6cea3d0a6dbc2ea933efd" + integrity sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA== + +"@svgr/babel-plugin-replace-jsx-attribute-value@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz#0b221fc57f9fcd10e91fe219e2cd0dd03145a897" + integrity sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ== + +"@svgr/babel-plugin-svg-dynamic-title@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz#139b546dd0c3186b6e5db4fefc26cb0baea729d7" + integrity sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg== + +"@svgr/babel-plugin-svg-em-dimensions@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz#6543f69526632a133ce5cabab965deeaea2234a0" + integrity sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw== + +"@svgr/babel-plugin-transform-react-native-svg@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz#00bf9a7a73f1cad3948cdab1f8dfb774750f8c80" + integrity sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q== + +"@svgr/babel-plugin-transform-svg-component@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz#583a5e2a193e214da2f3afeb0b9e8d3250126b4a" + integrity sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ== + +"@svgr/babel-preset@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-5.5.0.tgz#8af54f3e0a8add7b1e2b0fcd5a882c55393df327" + integrity sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig== + dependencies: + "@svgr/babel-plugin-add-jsx-attribute" "^5.4.0" + "@svgr/babel-plugin-remove-jsx-attribute" "^5.4.0" + "@svgr/babel-plugin-remove-jsx-empty-expression" "^5.0.1" + "@svgr/babel-plugin-replace-jsx-attribute-value" "^5.0.1" + "@svgr/babel-plugin-svg-dynamic-title" "^5.4.0" + "@svgr/babel-plugin-svg-em-dimensions" "^5.4.0" + "@svgr/babel-plugin-transform-react-native-svg" "^5.4.0" + "@svgr/babel-plugin-transform-svg-component" "^5.5.0" + +"@svgr/core@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/core/-/core-5.5.0.tgz#82e826b8715d71083120fe8f2492ec7d7874a579" + integrity sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ== + dependencies: + "@svgr/plugin-jsx" "^5.5.0" + camelcase "^6.2.0" + cosmiconfig "^7.0.0" + +"@svgr/hast-util-to-babel-ast@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz#5ee52a9c2533f73e63f8f22b779f93cd432a5461" + integrity sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ== + dependencies: + "@babel/types" "^7.12.6" + +"@svgr/plugin-jsx@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz#1aa8cd798a1db7173ac043466d7b52236b369000" + integrity sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA== + dependencies: + "@babel/core" "^7.12.3" + "@svgr/babel-preset" "^5.5.0" + "@svgr/hast-util-to-babel-ast" "^5.5.0" + svg-parser "^2.0.2" + +"@svgr/plugin-svgo@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz#02da55d85320549324e201c7b2e53bf431fcc246" + integrity sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ== + dependencies: + cosmiconfig "^7.0.0" + deepmerge "^4.2.2" + svgo "^1.2.2" + +"@svgr/webpack@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-5.5.0.tgz#aae858ee579f5fa8ce6c3166ef56c6a1b381b640" + integrity sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g== + dependencies: + "@babel/core" "^7.12.3" + "@babel/plugin-transform-react-constant-elements" "^7.12.1" + "@babel/preset-env" "^7.12.1" + "@babel/preset-react" "^7.12.5" + "@svgr/core" "^5.5.0" + "@svgr/plugin-jsx" "^5.5.0" + "@svgr/plugin-svgo" "^5.5.0" + loader-utils "^2.0.0" + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + +"@trysound/sax@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669" + integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow== + +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + +"@types/cssnano@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/cssnano/-/cssnano-4.0.1.tgz#67fa912753d80973a016e7684a47fedf338aacff" + integrity sha512-hGOroxRTBkYl5gSBRJOffhV4+io+Y2bFX1VP7LgKEVHJt/LPPJaWUIuDAz74Vlp7l7hCDZfaDi7iPxwNwuVA4Q== + dependencies: + postcss "5 - 7" + +"@types/eslint-scope@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.0.tgz#4792816e31119ebd506902a482caec4951fabd86" + integrity sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "7.2.10" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.10.tgz#4b7a9368d46c0f8cd5408c23288a59aa2394d917" + integrity sha512-kUEPnMKrqbtpCq/KTaGFFKAcz6Ethm2EjCoKIDaCmfRBWLbFuTcOJfTlorwbnboXBzahqWLgUp1BQeKHiJzPUQ== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "0.0.47" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.47.tgz#d7a51db20f0650efec24cd04994f523d93172ed4" + integrity sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg== + +"@types/estree@^0.0.50": + version "0.0.50" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" + integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== + +"@types/github-slugger@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@types/github-slugger/-/github-slugger-1.3.0.tgz#16ab393b30d8ae2a111ac748a015ac05a1fc5524" + integrity sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g== + +"@types/glob@^7.1.1": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/hast@^2.0.0": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.1.tgz#b16872f2a6144c7025f296fb9636a667ebb79cd9" + integrity sha512-viwwrB+6xGzw+G1eWpF9geV3fnsDgXqHG+cqgiHrvQfDUW5hzhCyV7Sy3UJxhfRFBsgky2SSW33qi/YrIkjX5Q== + dependencies: + "@types/unist" "*" + +"@types/html-minifier-terser@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.0.0.tgz#563c1c6c132cd204e71512f9c0b394ff90d3fae7" + integrity sha512-NZwaaynfs1oIoLAV1vg18e7QMVDvw+6SQrdJc8w3BwUaoroVSf6EBj/Sk4PBWGxsq0dzhA2drbsuMC1/6C6KgQ== + +"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6": + version "7.0.7" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" + integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== + +"@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/mdast@^3.0.0": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.3.tgz#2d7d671b1cd1ea3deb306ea75036c2a0407d2deb" + integrity sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw== + dependencies: + "@types/unist" "*" + +"@types/minimatch@*": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + +"@types/node@*": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.1.tgz#ef34dea0881028d11398be5bf4e856743e3dc35a" + integrity sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA== + +"@types/node@^15.0.1": + version "15.12.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.3.tgz#2817bf5f25bc82f56579018c53f7d41b1830b1af" + integrity sha512-SNt65CPCXvGNDZ3bvk1TQ0Qxoe3y1RKH88+wZ2Uf05dduBCqqFQ76ADP9pbT+Cpvj60SkRppMCh2Zo8tDixqjQ== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/parse5@^5.0.0": + version "5.0.3" + resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109" + integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw== + +"@types/q@^1.5.1": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" + integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug== + +"@types/sax@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@types/sax/-/sax-1.2.1.tgz#e0248be936ece791a82db1a57f3fb5f7c87e8172" + integrity sha512-dqYdvN7Sbw8QT/0Ci5rhjE4/iCMJEM0Y9rHpCu+gGXD9Lwbz28t6HI2yegsB6BoV1sShRMU6lAmAcgRjmFy7LA== + dependencies: + "@types/node" "*" + +"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" + integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ== + +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== + +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== + +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== + +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== + +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== + +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-wasm-section" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-opt" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wast-printer" "1.11.1" + +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + +"@webassemblyjs/wasm-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + +acorn-walk@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.1.0.tgz#d3c6a9faf00987a5e2b9bdb506c2aa76cd707f83" + integrity sha512-mjmzmv12YIG/G8JQdQuz2MUDShEJ6teYpT5bmWA4q7iwoGen8xtt3twF3OvzIUl+Q06aWIjvnwQUKvQ6TtMRjg== + +acorn@^8.0.4: + version "8.2.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.2.1.tgz#0d36af126fb6755095879c1dc6fd7edf7d60a5fb" + integrity sha512-z716cpm5TX4uzOzILx8PavOE6C6DKshHDw1aQN52M/yNSqE9s5O8SMfyhCCfCJ3HmTL0NkVOi+8a/55T7YB3bg== + +acorn@^8.4.1: + version "8.5.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" + integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== + +address@1.1.2, address@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" + integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.1.0, ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.1.0, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.8.0: + version "8.8.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb" + integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +algoliasearch-helper@^3.3.4: + version "3.6.2" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.6.2.tgz#45e19b12589cfa0c611b573287f65266ea2cc14a" + integrity sha512-Xx0NOA6k4ySn+R2l3UMSONAaMkyfmrZ3AP1geEMo32MxDJQJesZABZYsldO9fa6FKQxH91afhi4hO1G0Zc2opg== + dependencies: + events "^1.1.1" + +algoliasearch@^4.0.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.9.1.tgz#1fa8ece3f9808e465226176b88b953801c2274e0" + integrity sha512-EeJUYXzBEhZSsL6tXc3hseLBCtlNLa1MZ4mlMK6EeX38yRjY5vgnFcNNml6uUhlOjvheKxgkKRpPWkxgL8Cqkg== + dependencies: + "@algolia/cache-browser-local-storage" "4.9.1" + "@algolia/cache-common" "4.9.1" + "@algolia/cache-in-memory" "4.9.1" + "@algolia/client-account" "4.9.1" + "@algolia/client-analytics" "4.9.1" + "@algolia/client-common" "4.9.1" + "@algolia/client-recommendation" "4.9.1" + "@algolia/client-search" "4.9.1" + "@algolia/logger-common" "4.9.1" + "@algolia/logger-console" "4.9.1" + "@algolia/requester-browser-xhr" "4.9.1" + "@algolia/requester-common" "4.9.1" + "@algolia/requester-node-http" "4.9.1" + "@algolia/transporter" "4.9.1" + +algoliasearch@^4.8.4: + version "4.11.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.11.0.tgz#234befb3ac355c094077f0edf3777240b1ee013c" + integrity sha512-IXRj8kAP2WrMmj+eoPqPc6P7Ncq1yZkFiyDrjTBObV1ADNL8Z/KdZ+dWC5MmYcBLAbcB/mMCpak5N/D1UIZvsA== + dependencies: + "@algolia/cache-browser-local-storage" "4.11.0" + "@algolia/cache-common" "4.11.0" + "@algolia/cache-in-memory" "4.11.0" + "@algolia/client-account" "4.11.0" + "@algolia/client-analytics" "4.11.0" + "@algolia/client-common" "4.11.0" + "@algolia/client-personalization" "4.11.0" + "@algolia/client-search" "4.11.0" + "@algolia/logger-common" "4.11.0" + "@algolia/logger-console" "4.11.0" + "@algolia/requester-browser-xhr" "4.11.0" + "@algolia/requester-common" "4.11.0" + "@algolia/requester-node-http" "4.11.0" + "@algolia/transporter" "4.11.0" + +alphanum-sort@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= + +ansi-align@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" + integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== + dependencies: + string-width "^3.0.0" + +ansi-colors@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== + +ansi-escapes@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-html-community@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.0.tgz#a20e2bb5710e82950a516b3f933fee5ed478be90" + integrity sha512-4P8Zm2H+BRS+c/xX1LrHw0qKpEhdlZjLCgWy+d78T9vqa2Z2SiD2wMrYuWIAFy5IZUD7nnNXroRttz+0RzlrzQ== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autoprefixer@^10.2.5, autoprefixer@^10.3.7: + version "10.4.0" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.0.tgz#c3577eb32a1079a440ec253e404eaf1eb21388c8" + integrity sha512-7FdJ1ONtwzV1G43GDD0kpVMn/qbiNqyOPMFTX5nRffI+7vgWoFEc6DcXOxHJxrWNDXrZh18eDsZjvZGUljSRGA== + dependencies: + browserslist "^4.17.5" + caniuse-lite "^1.0.30001272" + fraction.js "^4.1.1" + normalize-range "^0.1.2" + picocolors "^1.0.0" + postcss-value-parser "^4.1.0" + +axios@^0.21.1: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + +babel-loader@^8.2.2: + version "8.2.2" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81" + integrity sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g== + dependencies: + find-cache-dir "^3.3.1" + loader-utils "^1.4.0" + make-dir "^3.1.0" + schema-utils "^2.6.5" + +babel-plugin-apply-mdx-type-prop@1.6.22: + version "1.6.22" + resolved "https://registry.yarnpkg.com/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz#d216e8fd0de91de3f1478ef3231e05446bc8705b" + integrity sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ== + dependencies: + "@babel/helper-plugin-utils" "7.10.4" + "@mdx-js/util" "1.6.22" + +babel-plugin-dynamic-import-node@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" + integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-extract-import-names@1.6.22: + version "1.6.22" + resolved "https://registry.yarnpkg.com/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz#de5f9a28eb12f3eb2578bf74472204e66d1a13dc" + integrity sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ== + dependencies: + "@babel/helper-plugin-utils" "7.10.4" + +babel-plugin-polyfill-corejs2@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.0.tgz#407082d0d355ba565af24126fb6cb8e9115251fd" + integrity sha512-wMDoBJ6uG4u4PNFh72Ty6t3EgfA91puCuAwKIazbQlci+ENb/UU9A3xG5lutjUIiXCIn1CY5L15r9LimiJyrSA== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.3.0" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz#0b571f4cf3d67f911512f5c04842a7b8e8263087" + integrity sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.0" + core-js-compat "^3.18.0" + +babel-plugin-polyfill-regenerator@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.0.tgz#9ebbcd7186e1a33e21c5e20cae4e7983949533be" + integrity sha512-dhAPTDLGoMW5/84wkgwiLRwMnio2i1fUe53EuvtKMv0pn2p3S8OCoV1xAzfJPl0KOX7IB89s2ib85vbYiea3jg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.0" + +bail@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" + integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base16@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70" + integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA= + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bluebird@^3.7.1: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +boxen@^5.0.0, boxen@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.0.1.tgz#657528bdd3f59a772b8279b831f27ec2c744664b" + integrity sha512-49VBlw+PrWEF51aCmy7QIteYPIFZxSpvqBdP/2itCPPlJ49kj9zg/XPRFrdkne2W+CfwXUls8exMvu1RysZpKA== + dependencies: + ansi-align "^3.0.0" + camelcase "^6.2.0" + chalk "^4.1.0" + cli-boxes "^2.2.1" + string-width "^4.2.0" + type-fest "^0.20.2" + widest-line "^3.1.0" + wrap-ansi "^7.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@4.14.2: + version "4.14.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.2.tgz#1b3cec458a1ba87588cc5e9be62f19b6d48813ce" + integrity sha512-HI4lPveGKUR0x2StIz+2FXfDk9SfVMrxn6PLh1JeGUwcuoDkdKZebWiyLRJ68iIPDpMI4JLVDf7S7XzslgWOhw== + dependencies: + caniuse-lite "^1.0.30001125" + electron-to-chromium "^1.3.564" + escalade "^3.0.2" + node-releases "^1.1.61" + +browserslist@^4.0.0, browserslist@^4.14.5: + version "4.16.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.5.tgz#952825440bca8913c62d0021334cbe928ef062ae" + integrity sha512-C2HAjrM1AI/djrpAUU/tr4pml1DqLIzJKSLDBXBrNErl9ZCCTXdhwxdJjYc16953+mBWf7Lw+uUJgpgb8cN71A== + dependencies: + caniuse-lite "^1.0.30001214" + colorette "^1.2.2" + electron-to-chromium "^1.3.719" + escalade "^3.1.1" + node-releases "^1.1.71" + +browserslist@^4.16.0, browserslist@^4.16.6: + version "4.16.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" + integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== + dependencies: + caniuse-lite "^1.0.30001219" + colorette "^1.2.2" + electron-to-chromium "^1.3.723" + escalade "^3.1.1" + node-releases "^1.1.71" + +browserslist@^4.17.5, browserslist@^4.18.1: + version "4.18.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.18.1.tgz#60d3920f25b6860eb917c6c7b185576f4d8b017f" + integrity sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ== + dependencies: + caniuse-lite "^1.0.30001280" + electron-to-chromium "^1.3.896" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^4.1.1, camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + +camelcase-css@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001214, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001272, caniuse-lite@^1.0.30001280: + version "1.0.30001303" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001303.tgz" + integrity sha512-/Mqc1oESndUNszJP0kx0UaQU9kEv9nNtJ7Kn8AdA0mNnH8eR1cj0kG+NbNuC1Wq/b21eA8prhKRA3bbkjONegQ== + +ccount@^1.0.0, ccount@^1.0.3: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" + integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg== + +chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.1.0, chalk@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + +cheerio@^0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" + integrity sha1-qbqoYKP5tZWmuBsahocxIe06Jp4= + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.0" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash.assignin "^4.0.9" + lodash.bind "^4.1.4" + lodash.defaults "^4.0.1" + lodash.filter "^4.4.0" + lodash.flatten "^4.2.0" + lodash.foreach "^4.3.0" + lodash.map "^4.4.0" + lodash.merge "^4.4.0" + lodash.pick "^4.2.1" + lodash.reduce "^4.4.0" + lodash.reject "^4.4.0" + lodash.some "^4.4.0" + +chokidar@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chokidar@^3.5.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +ci-info@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.1.1.tgz#9a32fcefdf7bcdb6f0a7e1c0f8098ec57897b80a" + integrity sha512-kdRWLBIJwdsYJWYJFtAFFYxybguqeF91qpZaggjG5Nf8QKdizFG2hjqvaTXbxFIcYbSaD74KpAXv6BSm17DHEQ== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clean-css@^4.2.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.4.tgz#733bf46eba4e607c6891ea57c24a989356831178" + integrity sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A== + dependencies: + source-map "~0.6.0" + +clean-css@^5.1.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.2.2.tgz#d3a7c6ee2511011e051719838bdcf8314dc4548d" + integrity sha512-/eR8ru5zyxKzpBLv9YZvMXgTSSQn7AdkMItMYynsFgGwTveCRVam9IUPFloE85B4vAIj05IuKmmEoV7/AQjT0w== + dependencies: + source-map "~0.6.0" + +clean-css@^5.1.5: + version "5.1.5" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.1.5.tgz#3b0af240dcfc9a3779a08c2332df3ebd4474f232" + integrity sha512-9dr/cU/LjMpU57PXlSvDkVRh0rPxJBXiBtD0+SgYt8ahTCsXtfKjCkNYgIoTC6mBg8CFr5EKhW3DKCaGMUbUfQ== + dependencies: + source-map "~0.6.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-boxes@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" + integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + +clsx@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" + integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== + +coa@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" + integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== + dependencies: + "@types/q" "^1.5.1" + chalk "^2.4.1" + q "^1.1.2" + +collapse-white-space@^1.0.2: + version "1.0.6" + resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" + integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colord@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.0.1.tgz#1e7fb1f9fa1cf74f42c58cb9c20320bab8435aa0" + integrity sha512-vm5YpaWamD0Ov6TSG0GGmUIwstrWcfKQV/h2CmbR7PbNu41+qdB5PW9lpzhjedrpm08uuYvcXi0Oel1RLZIJuA== + +colord@^2.6: + version "2.8.0" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.8.0.tgz#64fb7aa03de7652b5a39eee50271a104c2783b12" + integrity sha512-kNkVV4KFta3TYQv0bzs4xNwLaeag261pxgzGQSh4cQ1rEhYjcTJfFRP0SDlbhLONg0eSoLzrDd79PosjbltufA== + +colord@^2.9.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.1.tgz#c961ea0efeb57c9f0f4834458f26cb9cc4a3f90e" + integrity sha512-4LBMSt09vR0uLnPVkOUBnmxgoaeN4ewRbx801wY/bXcltXfpR/G46OdWn96XpYmCWuYvO46aBZP4NgX8HpNAcw== + +colorette@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" + integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== + +combine-promises@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/combine-promises/-/combine-promises-1.1.0.tgz#72db90743c0ca7aab7d0d8d2052fd7b0f674de71" + integrity sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg== + +comma-separated-tokens@^1.0.0: + version "1.0.8" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" + integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +commander@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== + +commander@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== + +commander@^7.1.0, commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +commander@^8.1.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.2.0.tgz#37fe2bde301d87d47a53adeff8b5915db1381ca8" + integrity sha512-LLKxDvHeL91/8MIyTAD5BFMNtoIwztGPMiM/7Bl8rIPmHCZXRxmSWr91h57dpOpnQ6jIUqEWdXE/uBYMfiVZDA== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +configstore@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + +connect-history-api-fallback@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + +consola@^2.15.0: + version "2.15.3" + resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550" + integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw== + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +copy-text-to-clipboard@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz#8cbf8f90e0a47f12e4a24743736265d157bce69c" + integrity sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q== + +copy-webpack-plugin@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz#2d2c460c4c4695ec0a58afb2801a1205256c4e6b" + integrity sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA== + dependencies: + fast-glob "^3.2.7" + glob-parent "^6.0.1" + globby "^11.0.3" + normalize-path "^3.0.0" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + +core-js-compat@^3.18.0, core-js-compat@^3.19.1: + version "3.19.3" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.19.3.tgz#de75e5821c5ce924a0a1e7b7d5c2cb973ff388aa" + integrity sha512-59tYzuWgEEVU9r+SRgceIGXSSUn47JknoiXW6Oq7RW8QHjXWz3/vp8pa7dbtuVu40sewz3OP3JmQEcDdztrLhA== + dependencies: + browserslist "^4.18.1" + semver "7.0.0" + +core-js-pure@^3.19.0: + version "3.19.3" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.19.3.tgz#c69b2b36b58927317824994b532ec3f0f7e49607" + integrity sha512-N3JruInmCyt7EJj5mAq3csCgGYgiSqu7p7TQp2KOztr180/OAIxyIvL1FCjzgmQk/t3Yniua50Fsak7FShI9lA== + +core-js@^3.9.1: + version "3.19.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.19.3.tgz#6df8142a996337503019ff3235a7022d7cdf4559" + integrity sha512-LeLBMgEGSsG7giquSzvgBrTS7V5UL6ks3eQlUSbN8dJStlLFiRzUm5iqsRyzUB8carhfKjkJ2vzKqE6z1Vga9g== + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" + integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +cross-fetch@^3.0.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" + integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== + dependencies: + node-fetch "2.6.1" + +cross-spawn@7.0.3, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +css-color-names@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-1.0.1.tgz#6ff7ee81a823ad46e020fa2fd6ab40a887e2ba67" + integrity sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA== + +css-declaration-sorter@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.0.3.tgz#9dfd8ea0df4cc7846827876fafb52314890c21a9" + integrity sha512-52P95mvW1SMzuRZegvpluT6yEv0FqQusydKQPZsNN5Q7hh8EwQvN8E2nwuJ16BBvNN6LcoIZXu/Bk58DAhrrxw== + dependencies: + timsort "^0.3.0" + +css-loader@^5.1.1: + version "5.2.4" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.2.4.tgz#e985dcbce339812cb6104ef3670f08f9893a1536" + integrity sha512-OFYGyINCKkdQsTrSYxzGSFnGS4gNjcXkKkQgWxK138jgnPt+lepxdjSZNc8sHAl5vP3DhsJUxufWIjOwI8PMMw== + dependencies: + camelcase "^6.2.0" + icss-utils "^5.1.0" + loader-utils "^2.0.0" + postcss "^8.2.10" + postcss-modules-extract-imports "^3.0.0" + postcss-modules-local-by-default "^4.0.0" + postcss-modules-scope "^3.0.0" + postcss-modules-values "^4.0.0" + postcss-value-parser "^4.1.0" + schema-utils "^3.0.0" + semver "^7.3.5" + +css-minimizer-webpack-plugin@^3.0.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.2.0.tgz#f59c56ec11137b37f000081bd19b450095094ad2" + integrity sha512-5q4myvkmm29jRlI73Fl8Mc008i6o6hCEKnV6/fOrzRVDWD6EFGwDRX+SM2qCVeZ7XiztRDKHpTGDUeUMAOOagg== + dependencies: + "@types/cssnano" "^4.0.1" + cssnano "^5.0.6" + jest-worker "^27.0.2" + postcss "^8.3.5" + schema-utils "^4.0.0" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== + +css-select@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" + integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== + dependencies: + boolbase "^1.0.0" + css-what "^3.2.1" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-select@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-3.1.2.tgz#d52cbdc6fee379fba97fb0d3925abbd18af2d9d8" + integrity sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA== + dependencies: + boolbase "^1.0.0" + css-what "^4.0.0" + domhandler "^4.0.0" + domutils "^2.4.3" + nth-check "^2.0.0" + +css-select@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" + integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== + dependencies: + boolbase "^1.0.0" + css-what "^5.0.0" + domhandler "^4.2.0" + domutils "^2.6.0" + nth-check "^2.0.0" + +css-select@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-tree@1.0.0-alpha.37: + version "1.0.0-alpha.37" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" + integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== + dependencies: + mdn-data "2.0.4" + source-map "^0.6.1" + +css-tree@^1.1.2, css-tree@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +css-what@2.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + +css-what@^3.2.1: + version "3.4.2" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" + integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== + +css-what@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-4.0.0.tgz#35e73761cab2eeb3d3661126b23d7aa0e8432233" + integrity sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A== + +css-what@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad" + integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-advanced@^5.1.1: + version "5.1.8" + resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.1.8.tgz#48678297b93d4964cd437ed1fa28d7f11ebf353c" + integrity sha512-QUR5/s3ZKX4hdrefOdTMdyzZ5RbBIt+GxcDh7bmu2yG21PqszQBtA02QG9ilsI1E7OCjkM4KlzaGtQ75GdGa3g== + dependencies: + autoprefixer "^10.3.7" + cssnano-preset-default "^5.1.8" + postcss-discard-unused "^5.0.1" + postcss-merge-idents "^5.0.1" + postcss-reduce-idents "^5.0.1" + postcss-zindex "^5.0.1" + +cssnano-preset-default@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.4.tgz#359943bf00c5c8e05489f12dd25f3006f2c1cbd2" + integrity sha512-sPpQNDQBI3R/QsYxQvfB4mXeEcWuw0wGtKtmS5eg8wudyStYMgKOQT39G07EbW1LB56AOYrinRS9f0ig4Y3MhQ== + dependencies: + css-declaration-sorter "^6.0.3" + cssnano-utils "^2.0.1" + postcss-calc "^8.0.0" + postcss-colormin "^5.2.0" + postcss-convert-values "^5.0.1" + postcss-discard-comments "^5.0.1" + postcss-discard-duplicates "^5.0.1" + postcss-discard-empty "^5.0.1" + postcss-discard-overridden "^5.0.1" + postcss-merge-longhand "^5.0.2" + postcss-merge-rules "^5.0.2" + postcss-minify-font-values "^5.0.1" + postcss-minify-gradients "^5.0.2" + postcss-minify-params "^5.0.1" + postcss-minify-selectors "^5.1.0" + postcss-normalize-charset "^5.0.1" + postcss-normalize-display-values "^5.0.1" + postcss-normalize-positions "^5.0.1" + postcss-normalize-repeat-style "^5.0.1" + postcss-normalize-string "^5.0.1" + postcss-normalize-timing-functions "^5.0.1" + postcss-normalize-unicode "^5.0.1" + postcss-normalize-url "^5.0.2" + postcss-normalize-whitespace "^5.0.1" + postcss-ordered-values "^5.0.2" + postcss-reduce-initial "^5.0.1" + postcss-reduce-transforms "^5.0.1" + postcss-svgo "^5.0.2" + postcss-unique-selectors "^5.0.1" + +cssnano-preset-default@^5.1.8: + version "5.1.8" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.8.tgz#7525feb1b72f7b06e57f55064cbdae341d79dea2" + integrity sha512-zWMlP0+AMPBVE852SqTrP0DnhTcTA2C1wAF92TKZ3Va+aUVqLIhkqKlnJIXXdqXD7RN+S1ujuWmNpvrJBiM/vg== + dependencies: + css-declaration-sorter "^6.0.3" + cssnano-utils "^2.0.1" + postcss-calc "^8.0.0" + postcss-colormin "^5.2.1" + postcss-convert-values "^5.0.2" + postcss-discard-comments "^5.0.1" + postcss-discard-duplicates "^5.0.1" + postcss-discard-empty "^5.0.1" + postcss-discard-overridden "^5.0.1" + postcss-merge-longhand "^5.0.4" + postcss-merge-rules "^5.0.3" + postcss-minify-font-values "^5.0.1" + postcss-minify-gradients "^5.0.3" + postcss-minify-params "^5.0.2" + postcss-minify-selectors "^5.1.0" + postcss-normalize-charset "^5.0.1" + postcss-normalize-display-values "^5.0.1" + postcss-normalize-positions "^5.0.1" + postcss-normalize-repeat-style "^5.0.1" + postcss-normalize-string "^5.0.1" + postcss-normalize-timing-functions "^5.0.1" + postcss-normalize-unicode "^5.0.1" + postcss-normalize-url "^5.0.3" + postcss-normalize-whitespace "^5.0.1" + postcss-ordered-values "^5.0.2" + postcss-reduce-initial "^5.0.2" + postcss-reduce-transforms "^5.0.1" + postcss-svgo "^5.0.3" + postcss-unique-selectors "^5.0.2" + +cssnano-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-2.0.1.tgz#8660aa2b37ed869d2e2f22918196a9a8b6498ce2" + integrity sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ== + +cssnano@^5.0.4: + version "5.0.12" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.12.tgz#2c083a1c786fc9dc2d5522bd3c0e331b7cd302ab" + integrity sha512-U38V4x2iJ3ijPdeWqUrEr4eKBB5PbEKsNP5T8xcik2Au3LeMtiMHX0i2Hu9k51FcKofNZumbrcdC6+a521IUHg== + dependencies: + cssnano-preset-default "^5.1.8" + is-resolvable "^1.1.0" + lilconfig "^2.0.3" + yaml "^1.10.2" + +cssnano@^5.0.6: + version "5.0.8" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.8.tgz#39ad166256980fcc64faa08c9bb18bb5789ecfa9" + integrity sha512-Lda7geZU0Yu+RZi2SGpjYuQz4HI4/1Y+BhdD0jL7NXAQ5larCzVn+PUGuZbDMYz904AXXCOgO5L1teSvgu7aFg== + dependencies: + cssnano-preset-default "^5.1.4" + is-resolvable "^1.1.0" + lilconfig "^2.0.3" + yaml "^1.10.2" + +csso@^4.0.2, csso@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== + dependencies: + css-tree "^1.1.2" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.1.1, debug@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.1.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +deep-equal@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== + dependencies: + is-arguments "^1.0.4" + is-date-object "^1.0.1" + is-regex "^1.0.4" + object-is "^1.0.1" + object-keys "^1.1.1" + regexp.prototype.flags "^1.2.0" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +default-gateway@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" + integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== + dependencies: + execa "^1.0.0" + ip-regex "^2.1.0" + +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" + integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== + dependencies: + "@types/glob" "^7.1.1" + globby "^6.1.0" + is-path-cwd "^2.0.0" + is-path-in-cwd "^2.0.0" + p-map "^2.0.0" + pify "^4.0.1" + rimraf "^2.6.3" + +del@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/del/-/del-6.0.0.tgz#0b40d0332cea743f1614f818be4feb717714c952" + integrity sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ== + dependencies: + globby "^11.0.1" + graceful-fs "^4.2.4" + is-glob "^4.0.1" + is-path-cwd "^2.2.0" + is-path-inside "^3.0.2" + p-map "^4.0.0" + rimraf "^3.0.2" + slash "^3.0.0" + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detab@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detab/-/detab-2.0.4.tgz#b927892069aff405fbb9a186fe97a44a92a94b43" + integrity sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g== + dependencies: + repeat-string "^1.5.4" + +detect-node@^2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.5.tgz#9d270aa7eaa5af0b72c4c9d9b814e7f4ce738b79" + integrity sha512-qi86tE6hRcFHy8jI1m2VG+LaPUR1LhqDa5G8tVjuUXmOrpuAgqsA1pN0+ldgr3aKUH+QLI9hCY/OcRYisERejw== + +detect-port-alt@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" + integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q== + dependencies: + address "^1.0.1" + debug "^2.6.0" + +detect-port@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.3.0.tgz#d9c40e9accadd4df5cac6a782aefd014d573d1f1" + integrity sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ== + dependencies: + address "^1.0.1" + debug "^2.6.0" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= + +dns-packet@^1.3.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f" + integrity sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA== + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= + dependencies: + buffer-indexof "^1.0.0" + +dom-converter@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-serializer@^1.0.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.1.tgz#d845a1565d7c041a95e5dab62184ab41e3a519be" + integrity sha512-Pv2ZluG5ife96udGgEDovOOOA5UELkltfJpnIExPrAk1LTvecolUGn6lIaoLh86d83GiB86CjzciMd9BuRB71Q== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + entities "^2.0.0" + +dom-serializer@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" + integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== + dependencies: + domelementtype "^1.3.0" + entities "^1.1.1" + +domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" + integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + +domhandler@^4.0.0, domhandler@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059" + integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA== + dependencies: + domelementtype "^2.2.0" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1, domutils@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^2.4.3: + version "2.6.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.6.0.tgz#2e15c04185d43fb16ae7057cb76433c6edb938b7" + integrity sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +domutils@^2.5.2, domutils@^2.6.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.7.0.tgz#8ebaf0c41ebafcf55b0b72ec31c56323712c5442" + integrity sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +dot-prop@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +duplexer@^0.1.1, duplexer@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +electron-to-chromium@^1.3.564: + version "1.4.15" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.15.tgz#4bd144d9d13f8b375c65e1a593e7f4a90bd01b90" + integrity sha512-WDw2IUL3k4QpbzInV3JZK+Zd1NjWJPDZ28oUSchWb/kf6AVj7/niaAlgcJlvojFa1d7pJSyQ/KSZsEtq5W7aGQ== + +electron-to-chromium@^1.3.719: + version "1.3.723" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.723.tgz#52769a75635342a4db29af5f1e40bd3dad02c877" + integrity sha512-L+WXyXI7c7+G1V8ANzRsPI5giiimLAUDC6Zs1ojHHPhYXb3k/iTABFmWjivEtsWrRQymjnO66/rO2ZTABGdmWg== + +electron-to-chromium@^1.3.723: + version "1.3.725" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.725.tgz#04fc83f9189169aff50f0a00c6b4090b910cba85" + integrity sha512-2BbeAESz7kc6KBzs7WVrMc1BY5waUphk4D4DX5dSQXJhsc3tP5ZFaiyuL0AB7vUKzDYpIeYwTYlEfxyjsGUrhw== + +electron-to-chromium@^1.3.896: + version "1.4.14" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.14.tgz#b0aa41fbfbf2eff8c2c6f7a871c03075250f8956" + integrity sha512-RsGkAN9JEAYMObS72kzUsPPcPGMqX1rBqGuXi9aa4TBKLzICoLf+DAAtd0fVFzrniJqYzpby47gthCUoObfs0Q== + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +emoticon@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/emoticon/-/emoticon-3.2.0.tgz#c008ca7d7620fac742fe1bf4af8ff8fed154ae7f" + integrity sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^5.8.3: + version "5.8.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" + integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +errno@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.2, es-abstract@^1.18.0-next.2: + version "1.18.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0.tgz#ab80b359eecb7ede4c298000390bc5ac3ec7b5a4" + integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.2" + is-callable "^1.2.3" + is-negative-zero "^2.0.1" + is-regex "^1.1.2" + is-string "^1.0.5" + object-inspect "^1.9.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.0" + +es-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.0.2, escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-goat@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" + integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== + +escape-html@^1.0.3, escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eta@^1.12.1: + version "1.12.3" + resolved "https://registry.yarnpkg.com/eta/-/eta-1.12.3.tgz#2982d08adfbef39f9fa50e2fbd42d7337e7338b1" + integrity sha512-qHixwbDLtekO/d51Yr4glcaUJCIjGVJyTzuqV4GPlgZo1YpgOKG+avQynErZIYrfM6JIJdtiG2Kox8tbb+DoGg== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eval@^0.1.4: + version "0.1.6" + resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.6.tgz#9620d7d8c85515e97e6b47c5814f46ae381cb3cc" + integrity sha512-o0XUw+5OGkXw4pJZzQoXUk+H87DHuC+7ZE//oSrRGtatTmr12oTnLfg6QOq9DyTt0c/p4TwzgmkKrBzWTSizyQ== + dependencies: + require-like ">= 0.1.1" + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +eventsource@^1.0.7: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf" + integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg== + dependencies: + original "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376" + integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +express@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.1.1: + version "3.2.5" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" + integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + +fast-glob@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-url-parser@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" + integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0= + dependencies: + punycode "^1.3.2" + +fastq@^1.6.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858" + integrity sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g== + dependencies: + reusify "^1.0.4" + +faye-websocket@^0.11.3: + version "0.11.3" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e" + integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA== + dependencies: + websocket-driver ">=0.5.1" + +fbemitter@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-3.0.0.tgz#00b2a1af5411254aab416cd75f9e6289bee4bff3" + integrity sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw== + dependencies: + fbjs "^3.0.0" + +fbjs-css-vars@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" + integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== + +fbjs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.0.tgz#0907067fb3f57a78f45d95f1eacffcacd623c165" + integrity sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg== + dependencies: + cross-fetch "^3.0.4" + fbjs-css-vars "^1.0.0" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + +feed@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/feed/-/feed-4.2.2.tgz#865783ef6ed12579e2c44bbef3c9113bc4956a7e" + integrity sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ== + dependencies: + xml-js "^1.6.11" + +figures@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-loader@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" + integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +filesize@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.1.0.tgz#e81bdaa780e2451d714d71c0d7a4f3238d37ad00" + integrity sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-cache-dir@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" + integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-up@4.1.0, find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flux@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.1.tgz#7843502b02841d4aaa534af0b373034a1f75ee5c" + integrity sha512-emk4RCvJ8RzNP2lNpphKnG7r18q8elDYNAPx7xn+bDeOIo9FFfxEfIQ2y6YbQNmnsGD3nH1noxtLE64Puz1bRQ== + dependencies: + fbemitter "^3.0.0" + fbjs "^3.0.0" + +follow-redirects@^1.0.0, follow-redirects@^1.14.0: + version "1.14.7" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" + integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ== + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +fork-ts-checker-webpack-plugin@4.1.6: + version "4.1.6" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz#5055c703febcf37fa06405d400c122b905167fc5" + integrity sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw== + dependencies: + "@babel/code-frame" "^7.5.5" + chalk "^2.4.1" + micromatch "^3.1.10" + minimatch "^3.0.4" + semver "^5.6.0" + tapable "^1.0.0" + worker-rpc "^0.1.0" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fraction.js@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.1.tgz#ac4e520473dae67012d618aab91eda09bcb400ff" + integrity sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg== + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs-extra@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.13" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-own-enumerable-property-symbols@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" + integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== + +get-stream@^4.0.0, get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +github-slugger@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.4.0.tgz#206eb96cdb22ee56fdc53a28d5a302338463444e" + integrity sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ== + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-parent@^5.1.0, glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^7.0.0, glob@^7.0.3, glob@^7.1.3: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" + integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA== + dependencies: + ini "2.0.0" + +global-modules@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globby@11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" + integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +globby@^11.0.1, globby@^11.0.2, globby@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +graceful-fs@^4.1.11: + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: + version "4.2.6" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" + integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== + +gray-matter@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798" + integrity sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q== + dependencies: + js-yaml "^3.13.1" + kind-of "^6.0.2" + section-matter "^1.0.0" + strip-bom-string "^1.0.0" + +gzip-size@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" + integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA== + dependencies: + duplexer "^0.1.1" + pify "^4.0.1" + +gzip-size@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" + integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== + dependencies: + duplexer "^0.1.2" + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has-yarn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" + integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hast-to-hyperscript@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz#9b67fd188e4c81e8ad66f803855334173920218d" + integrity sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA== + dependencies: + "@types/unist" "^2.0.3" + comma-separated-tokens "^1.0.0" + property-information "^5.3.0" + space-separated-tokens "^1.0.0" + style-to-object "^0.3.0" + unist-util-is "^4.0.0" + web-namespaces "^1.0.0" + +hast-util-from-parse5@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-5.0.3.tgz#3089dc0ee2ccf6ec8bc416919b51a54a589e097c" + integrity sha512-gOc8UB99F6eWVWFtM9jUikjN7QkWxB3nY0df5Z0Zq1/Nkwl5V4hAAsl0tmwlgWl/1shlTF8DnNYLO8X6wRV9pA== + dependencies: + ccount "^1.0.3" + hastscript "^5.0.0" + property-information "^5.0.0" + web-namespaces "^1.1.2" + xtend "^4.0.1" + +hast-util-from-parse5@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz#554e34abdeea25ac76f5bd950a1f0180e0b3bc2a" + integrity sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA== + dependencies: + "@types/parse5" "^5.0.0" + hastscript "^6.0.0" + property-information "^5.0.0" + vfile "^4.0.0" + vfile-location "^3.2.0" + web-namespaces "^1.0.0" + +hast-util-parse-selector@^2.0.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" + integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== + +hast-util-raw@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-6.0.1.tgz#973b15930b7529a7b66984c98148b46526885977" + integrity sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig== + dependencies: + "@types/hast" "^2.0.0" + hast-util-from-parse5 "^6.0.0" + hast-util-to-parse5 "^6.0.0" + html-void-elements "^1.0.0" + parse5 "^6.0.0" + unist-util-position "^3.0.0" + vfile "^4.0.0" + web-namespaces "^1.0.0" + xtend "^4.0.0" + zwitch "^1.0.0" + +hast-util-to-parse5@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz#1ec44650b631d72952066cea9b1445df699f8479" + integrity sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ== + dependencies: + hast-to-hyperscript "^9.0.0" + property-information "^5.0.0" + web-namespaces "^1.0.0" + xtend "^4.0.0" + zwitch "^1.0.0" + +hastscript@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-5.1.2.tgz#bde2c2e56d04c62dd24e8c5df288d050a355fb8a" + integrity sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ== + dependencies: + comma-separated-tokens "^1.0.0" + hast-util-parse-selector "^2.0.0" + property-information "^5.0.0" + space-separated-tokens "^1.0.0" + +hastscript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" + integrity sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w== + dependencies: + "@types/hast" "^2.0.0" + comma-separated-tokens "^1.0.0" + hast-util-parse-selector "^2.0.0" + property-information "^5.0.0" + space-separated-tokens "^1.0.0" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +history@^4.9.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" + integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== + dependencies: + "@babel/runtime" "^7.1.2" + loose-envify "^1.2.0" + resolve-pathname "^3.0.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + value-equal "^1.0.1" + +hoist-non-react-statics@^3.1.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" + integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== + +html-minifier-terser@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#922e96f1f3bb60832c2634b79884096389b1f054" + integrity sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg== + dependencies: + camel-case "^4.1.1" + clean-css "^4.2.3" + commander "^4.1.1" + he "^1.2.0" + param-case "^3.0.3" + relateurl "^0.2.7" + terser "^4.6.3" + +html-minifier-terser@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.0.2.tgz#14059ad64b69bf9f8b8a33f25b53411d8321e75d" + integrity sha512-AgYO3UGhMYQx2S/FBJT3EM0ZYcKmH6m9XL9c1v77BeK/tYJxGPxT1/AtsdUi4FcP8kZGmqqnItCcjFPcX9hk6A== + dependencies: + camel-case "^4.1.2" + clean-css "^5.1.5" + commander "^8.1.0" + he "^1.2.0" + param-case "^3.0.4" + relateurl "^0.2.7" + terser "^5.7.2" + +html-tags@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" + integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== + +html-void-elements@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-1.0.5.tgz#ce9159494e86d95e45795b166c2021c2cfca4483" + integrity sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w== + +html-webpack-plugin@^5.3.2: + version "5.5.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50" + integrity sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw== + dependencies: + "@types/html-minifier-terser" "^6.0.0" + html-minifier-terser "^6.0.2" + lodash "^4.17.21" + pretty-error "^4.0.0" + tapable "^2.0.0" + +htmlparser2@^3.9.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== + dependencies: + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +http-cache-semantics@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-parser-js@>=0.5.1: + version "0.5.3" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9" + integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg== + +http-proxy-middleware@0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" + integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== + dependencies: + http-proxy "^1.17.0" + is-glob "^4.0.0" + lodash "^4.17.11" + micromatch "^3.1.10" + +http-proxy@^1.17.0: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +icss-utils@^5.0.0, icss-utils@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +ignore@^5.1.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + +immer@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" + integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA== + +import-fresh@^3.2.1, import-fresh@^3.2.2, import-fresh@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= + +import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +infima@0.2.0-alpha.26: + version "0.2.0-alpha.26" + resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.26.tgz#8582d40ef01a09dbbde8f0e574f8c61d6bc0992b" + integrity sha512-0/Dt+89mf8xW+9/hKGmynK+WOAsiy0QydVJL0qie6WK57yGIQv+SjJrhMybKndnmkZBQ+Vlt0tWPnTakx8X2Qw== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== + +ini@^1.3.5, ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +inline-style-parser@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" + integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== + +internal-ip@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" + integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== + dependencies: + default-gateway "^4.2.0" + ipaddr.js "^1.9.0" + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ip@^1.1.0, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.9.1, ipaddr.js@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-absolute-url@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" + integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-alphabetical@1.0.4, is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + +is-arguments@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" + integrity sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg== + dependencies: + call-bind "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-bigint@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.1.tgz#6923051dfcbc764278540b9ce0e6b3213aa5ebc2" + integrity sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg== + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.0.tgz#e2aaad3a3a8fca34c28f6eee135b156ed2587ff0" + integrity sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA== + dependencies: + call-bind "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-buffer@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + +is-callable@^1.1.4, is-callable@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" + integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-core-module@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.3.0.tgz#d341652e3408bca69c4671b79a0954a3d349f887" + integrity sha512-xSphU2KG9867tsYdLD4RWQ1VqdFl4HTO9Thf3I/3dLEfr0dbPTWKsuCKrgqMljg4nPE+Gq0VCnzT3gr0CyBmsw== + dependencies: + has "^1.0.3" + +is-core-module@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + +is-installed-globally@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" + integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== + dependencies: + global-dirs "^3.0.0" + is-path-inside "^3.0.2" + +is-negative-zero@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== + +is-npm@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-5.0.0.tgz#43e8d65cc56e1b67f8d47262cf667099193f45a8" + integrity sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA== + +is-number-object@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" + integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-cwd@^2.0.0, is-path-cwd@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-in-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" + integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== + dependencies: + is-path-inside "^2.1.0" + +is-path-inside@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" + integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== + dependencies: + path-is-inside "^1.0.2" + +is-path-inside@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-regex@^1.0.4, is-regex@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" + integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg== + dependencies: + call-bind "^1.0.2" + has-symbols "^1.0.1" + +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= + +is-resolvable@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== + +is-root@2.1.0, is-root@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" + integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" + integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + +is-string@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" + integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + dependencies: + has-symbols "^1.0.1" + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-whitespace-character@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" + integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w== + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-word-character@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230" + integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +is-wsl@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +is-yarn-global@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" + integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +jest-worker@^27.0.2: + version "27.0.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.2.tgz#4ebeb56cef48b3e7514552f80d0d80c0129f0b05" + integrity sha512-EoBdilOTTyOgmHXtw/cPc+ZrCA0KJMrkXzkrPGNwLmnvvlN1nj7MPrxpT7m+otSv2e1TLaVffzDnE/LB14zJMg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest-worker@^27.0.6: + version "27.2.5" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.2.5.tgz#ed42865661959488aa020e8a325df010597c36d4" + integrity sha512-HTjEPZtcNKZ4LnhSp02NEH4vE+5OpJ0EsOWYvGQpHgUMLngydESAAMH5Wd/asPf29+XUDQZszxpLg1BkIIA2aw== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +joi@^17.3.0: + version "17.5.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.5.0.tgz#7e66d0004b5045d971cf416a55fb61d33ac6e011" + integrity sha512-R7hR50COp7StzLnDi4ywOXHrBrgNXuUUfJWIR5lPY5Bm/pOD3jZaTwpluUXVLRWcoWZxkrHBBJ5hLxgnlehbdw== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.0.0" + +joi@^17.4.0: + version "17.4.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.4.0.tgz#b5c2277c8519e016316e49ababd41a1908d9ef20" + integrity sha512-F4WiW2xaV6wc1jxete70Rw4V/VuMd6IN+a5ilZsxG4uYtUXWu2kq9W5P2dz30e7Gmw8RCbY/u/uk+dMPma9tAg== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.0" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.0.0" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json3@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" + integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + +killable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +klona@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" + integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== + +latest-version@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" + integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== + dependencies: + package-json "^6.3.0" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +lilconfig@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.3.tgz#68f3005e921dafbd2a2afb48379986aa6d2579fd" + integrity sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg== + +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + +loader-runner@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" + integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== + +loader-utils@2.0.0, loader-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" + integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +loader-utils@^1.2.3, loader-utils@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.assignin@^4.0.9: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI= + +lodash.bind@^4.1.4: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" + integrity sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU= + +lodash.curry@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170" + integrity sha1-JI42By7ekGUB11lmIAqG2riyMXA= + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.defaults@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.filter@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" + integrity sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4= + +lodash.flatten@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.flow@^3.3.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a" + integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o= + +lodash.foreach@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM= + +lodash.map@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" + integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM= + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.merge@^4.4.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.pick@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= + +lodash.reduce@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + integrity sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs= + +lodash.reject@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" + integrity sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU= + +lodash.some@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= + +lodash.toarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" + integrity sha1-JMS/zWsvuji/0FlNsRedjptlZWE= + +lodash.uniq@4.5.0, lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loglevel@^1.6.8: + version "1.8.0" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114" + integrity sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA== + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +markdown-escapes@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" + integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== + +mdast-squeeze-paragraphs@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz#7c4c114679c3bee27ef10b58e2e015be79f1ef97" + integrity sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ== + dependencies: + unist-util-remove "^2.0.0" + +mdast-util-definitions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz#c5c1a84db799173b4dcf7643cda999e440c24db2" + integrity sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ== + dependencies: + unist-util-visit "^2.0.0" + +mdast-util-to-hast@10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz#0cfc82089494c52d46eb0e3edb7a4eb2aea021eb" + integrity sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + mdast-util-definitions "^4.0.0" + mdurl "^1.0.0" + unist-builder "^2.0.0" + unist-util-generated "^1.0.0" + unist-util-position "^3.0.0" + unist-util-visit "^2.0.0" + +mdast-util-to-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" + integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + +mdn-data@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" + integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== + +mdurl@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +memory-fs@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +microevent.ts@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" + integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + +mime-db@1.47.0, "mime-db@>= 1.43.0 < 2": + version "1.47.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c" + integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw== + +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== + +mime-types@2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== + dependencies: + mime-db "~1.33.0" + +mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.24: + version "2.1.30" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d" + integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg== + dependencies: + mime-db "1.47.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.3.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" + integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== + +mime@^2.4.4: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +mini-create-react-context@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz#072171561bfdc922da08a60c2197a497cc2d1d5e" + integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ== + dependencies: + "@babel/runtime" "^7.12.1" + tiny-warning "^1.0.3" + +mini-css-extract-plugin@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.0.tgz#b4db2525af2624899ed64a23b0016e0036411893" + integrity sha512-nPFKI7NSy6uONUo9yn2hIfb9vyYvkFu95qki0e21DQ9uaqNKDP15DGpK0KnV6wDroWxPHtExrdEwx/yDQ8nVRw== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + webpack-sources "^1.1.0" + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.1, mkdirp@^0.5.5, mkdirp@~0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +module-alias@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0" + integrity sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +nan@^2.12.1: + version "2.15.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" + integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== + +nanoid@^3.1.28, nanoid@^3.1.30: + version "3.2.0" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" + integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-emoji@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da" + integrity sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw== + dependencies: + lodash.toarray "^4.4.0" + +node-fetch@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + +node-forge@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" + integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== + +node-releases@^1.1.61: + version "1.1.77" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e" + integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ== + +node-releases@^1.1.71: + version "1.1.71" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb" + integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg== + +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-url@^4.1.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== + +normalize-url@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.0.1.tgz#a4f27f58cf8c7b287b440b8a8201f42d0b00d256" + integrity sha512-VU4pzAuh7Kip71XEmO9aNREYAdMHFGTVj/i+CaTImS8x0i1d3jUZkXhqluy/PRgjPLMgsLQulYY3PJ/aSbSjpQ== + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nprogress@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" + integrity sha1-y480xTIT2JVyP8urkH6UIq28r7E= + +nth-check@^1.0.2, nth-check@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +nth-check@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125" + integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q== + dependencies: + boolbase "^1.0.0" + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.9.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.2.tgz#b6385a3e2b7cae0b5eafcf90cddf85d128767f30" + integrity sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA== + +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.getownpropertydescriptors@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" + integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.values@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.3.tgz#eaa8b1e17589f02f698db093f7c62ee1699742ee" + integrity sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + has "^1.0.3" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^7.0.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + +opener@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" + integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== + +opn@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== + dependencies: + is-wsl "^1.1.0" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + dependencies: + url-parse "^1.4.3" + +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-retry@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" + integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== + dependencies: + retry "^0.12.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json@^6.3.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" + integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== + dependencies: + got "^9.6.0" + registry-auth-token "^4.0.0" + registry-url "^5.0.0" + semver "^6.2.0" + +param-case@^3.0.3, param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse-numeric-range@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz#7c63b61190d61e4d53a1197f0c83c47bb670ffa3" + integrity sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ== + +parse5@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== + +parse5@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@1.0.2, path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6, path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-to-regexp@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" + integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== + +path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d" + integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg== + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-dir@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-up@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + +portfinder@^1.0.26: + version "1.0.28" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" + integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== + dependencies: + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.5" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-calc@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.0.0.tgz#a05b87aacd132740a5db09462a3612453e5df90a" + integrity sha512-5NglwDrcbiy8XXfPM11F3HeC6hoT9W7GUH/Zi5U/p7u3Irv4rHhdDcIZwG0llHXV4ftsBjpfWMXAnXNl4lnt8g== + dependencies: + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.2" + +postcss-colormin@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.0.tgz#2b620b88c0ff19683f3349f4cf9e24ebdafb2c88" + integrity sha512-+HC6GfWU3upe5/mqmxuqYZ9B2Wl4lcoUUNkoaX59nEWV4EtADCMiBqui111Bu8R8IvaZTmqmxrqOAqjbHIwXPw== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + colord "^2.0.1" + postcss-value-parser "^4.1.0" + +postcss-colormin@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.1.tgz#6e444a806fd3c578827dbad022762df19334414d" + integrity sha512-VVwMrEYLcHYePUYV99Ymuoi7WhKrMGy/V9/kTS0DkCoJYmmjdOMneyhzYUxcNgteKDVbrewOkSM7Wje/MFwxzA== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + colord "^2.9.1" + postcss-value-parser "^4.1.0" + +postcss-convert-values@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.1.tgz#4ec19d6016534e30e3102fdf414e753398645232" + integrity sha512-C3zR1Do2BkKkCgC0g3sF8TS0koF2G+mN8xxayZx3f10cIRmTaAnpgpRQZjNekTZxM2ciSPoh2IWJm0VZx8NoQg== + dependencies: + postcss-value-parser "^4.1.0" + +postcss-convert-values@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz#879b849dc3677c7d6bc94b6a2c1a3f0808798059" + integrity sha512-KQ04E2yadmfa1LqXm7UIDwW1ftxU/QWZmz6NKnHnUvJ3LEYbbcX6i329f/ig+WnEByHegulocXrECaZGLpL8Zg== + dependencies: + postcss-value-parser "^4.1.0" + +postcss-discard-comments@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz#9eae4b747cf760d31f2447c27f0619d5718901fe" + integrity sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg== + +postcss-discard-duplicates@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz#68f7cc6458fe6bab2e46c9f55ae52869f680e66d" + integrity sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA== + +postcss-discard-empty@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz#ee136c39e27d5d2ed4da0ee5ed02bc8a9f8bf6d8" + integrity sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw== + +postcss-discard-overridden@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz#454b41f707300b98109a75005ca4ab0ff2743ac6" + integrity sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q== + +postcss-discard-unused@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-5.0.1.tgz#63e35a74a154912f93d4e75a1e6ff3cc146f934b" + integrity sha512-tD6xR/xyZTwfhKYRw0ylfCY8wbfhrjpKAMnDKRTLMy2fNW5hl0hoV6ap5vo2JdCkuHkP3CHw72beO4Y8pzFdww== + dependencies: + postcss-selector-parser "^6.0.5" + +postcss-loader@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-5.3.0.tgz#1657f869e48d4fdb018a40771c235e499ee26244" + integrity sha512-/+Z1RAmssdiSLgIZwnJHwBMnlABPgF7giYzTN2NOfr9D21IJZ4mQC1R2miwp80zno9M4zMD/umGI8cR+2EL5zw== + dependencies: + cosmiconfig "^7.0.0" + klona "^2.0.4" + semver "^7.3.4" + +postcss-merge-idents@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-5.0.1.tgz#6b5856fc28f2571f28ecce49effb9b0e64be9437" + integrity sha512-xu8ueVU0RszbI2gKkxR6mluupsOSSLvt8q4gA2fcKFkA+x6SlH3cb4cFHpDvcRCNFbUmCR/VUub+Y6zPOjPx+Q== + dependencies: + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + +postcss-merge-longhand@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.2.tgz#277ada51d9a7958e8ef8cf263103c9384b322a41" + integrity sha512-BMlg9AXSI5G9TBT0Lo/H3PfUy63P84rVz3BjCFE9e9Y9RXQZD3+h3YO1kgTNsNJy7bBc1YQp8DmSnwLIW5VPcw== + dependencies: + css-color-names "^1.0.1" + postcss-value-parser "^4.1.0" + stylehacks "^5.0.1" + +postcss-merge-longhand@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz#41f4f3270282ea1a145ece078b7679f0cef21c32" + integrity sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw== + dependencies: + postcss-value-parser "^4.1.0" + stylehacks "^5.0.1" + +postcss-merge-rules@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.2.tgz#d6e4d65018badbdb7dcc789c4f39b941305d410a" + integrity sha512-5K+Md7S3GwBewfB4rjDeol6V/RZ8S+v4B66Zk2gChRqLTCC8yjnHQ601omj9TKftS19OPGqZ/XzoqpzNQQLwbg== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + cssnano-utils "^2.0.1" + postcss-selector-parser "^6.0.5" + vendors "^1.0.3" + +postcss-merge-rules@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.3.tgz#b5cae31f53129812a77e3eb1eeee448f8cf1a1db" + integrity sha512-cEKTMEbWazVa5NXd8deLdCnXl+6cYG7m2am+1HzqH0EnTdy8fRysatkaXb2dEnR+fdaDxTvuZ5zoBdv6efF6hg== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + cssnano-utils "^2.0.1" + postcss-selector-parser "^6.0.5" + +postcss-minify-font-values@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz#a90cefbfdaa075bd3dbaa1b33588bb4dc268addf" + integrity sha512-7JS4qIsnqaxk+FXY1E8dHBDmraYFWmuL6cgt0T1SWGRO5bzJf8sUoelwa4P88LEWJZweHevAiDKxHlofuvtIoA== + dependencies: + postcss-value-parser "^4.1.0" + +postcss-minify-gradients@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.2.tgz#7c175c108f06a5629925d698b3c4cf7bd3864ee5" + integrity sha512-7Do9JP+wqSD6Prittitt2zDLrfzP9pqKs2EcLX7HJYxsxCOwrrcLt4x/ctQTsiOw+/8HYotAoqNkrzItL19SdQ== + dependencies: + colord "^2.6" + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + +postcss-minify-gradients@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.3.tgz#f970a11cc71e08e9095e78ec3a6b34b91c19550e" + integrity sha512-Z91Ol22nB6XJW+5oe31+YxRsYooxOdFKcbOqY/V8Fxse1Y3vqlNRpi1cxCqoACZTQEhl+xvt4hsbWiV5R+XI9Q== + dependencies: + colord "^2.9.1" + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + +postcss-minify-params@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.1.tgz#371153ba164b9d8562842fdcd929c98abd9e5b6c" + integrity sha512-4RUC4k2A/Q9mGco1Z8ODc7h+A0z7L7X2ypO1B6V8057eVK6mZ6xwz6QN64nHuHLbqbclkX1wyzRnIrdZehTEHw== + dependencies: + alphanum-sort "^1.0.2" + browserslist "^4.16.0" + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + uniqs "^2.0.0" + +postcss-minify-params@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.2.tgz#1b644da903473fbbb18fbe07b8e239883684b85c" + integrity sha512-qJAPuBzxO1yhLad7h2Dzk/F7n1vPyfHfCCh5grjGfjhi1ttCnq4ZXGIW77GSrEbh9Hus9Lc/e/+tB4vh3/GpDg== + dependencies: + alphanum-sort "^1.0.2" + browserslist "^4.16.6" + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + +postcss-minify-selectors@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz#4385c845d3979ff160291774523ffa54eafd5a54" + integrity sha512-NzGBXDa7aPsAcijXZeagnJBKBPMYLaJJzB8CQh6ncvyl2sIndLVWfbcDi0SBjRWk5VqEjXvf8tYwzoKf4Z07og== + dependencies: + alphanum-sort "^1.0.2" + postcss-selector-parser "^6.0.5" + +postcss-modules-extract-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== + +postcss-modules-local-by-default@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" + integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-normalize-charset@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz#121559d1bebc55ac8d24af37f67bd4da9efd91d0" + integrity sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg== + +postcss-normalize-display-values@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.1.tgz#62650b965981a955dffee83363453db82f6ad1fd" + integrity sha512-uupdvWk88kLDXi5HEyI9IaAJTE3/Djbcrqq8YgjvAVuzgVuqIk3SuJWUisT2gaJbZm1H9g5k2w1xXilM3x8DjQ== + dependencies: + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + +postcss-normalize-positions@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.0.1.tgz#868f6af1795fdfa86fbbe960dceb47e5f9492fe5" + integrity sha512-rvzWAJai5xej9yWqlCb1OWLd9JjW2Ex2BCPzUJrbaXmtKtgfL8dBMOOMTX6TnvQMtjk3ei1Lswcs78qKO1Skrg== + dependencies: + postcss-value-parser "^4.1.0" + +postcss-normalize-repeat-style@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.1.tgz#cbc0de1383b57f5bb61ddd6a84653b5e8665b2b5" + integrity sha512-syZ2itq0HTQjj4QtXZOeefomckiV5TaUO6ReIEabCh3wgDs4Mr01pkif0MeVwKyU/LHEkPJnpwFKRxqWA/7O3w== + dependencies: + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + +postcss-normalize-string@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.0.1.tgz#d9eafaa4df78c7a3b973ae346ef0e47c554985b0" + integrity sha512-Ic8GaQ3jPMVl1OEn2U//2pm93AXUcF3wz+OriskdZ1AOuYV25OdgS7w9Xu2LO5cGyhHCgn8dMXh9bO7vi3i9pA== + dependencies: + postcss-value-parser "^4.1.0" + +postcss-normalize-timing-functions@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.1.tgz#8ee41103b9130429c6cbba736932b75c5e2cb08c" + integrity sha512-cPcBdVN5OsWCNEo5hiXfLUnXfTGtSFiBU9SK8k7ii8UD7OLuznzgNRYkLZow11BkQiiqMcgPyh4ZqXEEUrtQ1Q== + dependencies: + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + +postcss-normalize-unicode@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.1.tgz#82d672d648a411814aa5bf3ae565379ccd9f5e37" + integrity sha512-kAtYD6V3pK0beqrU90gpCQB7g6AOfP/2KIPCVBKJM2EheVsBQmx/Iof+9zR9NFKLAx4Pr9mDhogB27pmn354nA== + dependencies: + browserslist "^4.16.0" + postcss-value-parser "^4.1.0" + +postcss-normalize-url@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.2.tgz#ddcdfb7cede1270740cf3e4dfc6008bd96abc763" + integrity sha512-k4jLTPUxREQ5bpajFQZpx8bCF2UrlqOTzP9kEqcEnOfwsRshWs2+oAFIHfDQB8GO2PaUaSE0NlTAYtbluZTlHQ== + dependencies: + is-absolute-url "^3.0.3" + normalize-url "^6.0.1" + postcss-value-parser "^4.1.0" + +postcss-normalize-url@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.3.tgz#42eca6ede57fe69075fab0f88ac8e48916ef931c" + integrity sha512-qWiUMbvkRx3kc1Dp5opzUwc7MBWZcSDK2yofCmdvFBCpx+zFPkxBC1FASQ59Pt+flYfj/nTZSkmF56+XG5elSg== + dependencies: + is-absolute-url "^3.0.3" + normalize-url "^6.0.1" + postcss-value-parser "^4.1.0" + +postcss-normalize-whitespace@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz#b0b40b5bcac83585ff07ead2daf2dcfbeeef8e9a" + integrity sha512-iPklmI5SBnRvwceb/XH568yyzK0qRVuAG+a1HFUsFRf11lEJTiQQa03a4RSCQvLKdcpX7XsI1Gen9LuLoqwiqA== + dependencies: + postcss-value-parser "^4.1.0" + +postcss-ordered-values@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz#1f351426977be00e0f765b3164ad753dac8ed044" + integrity sha512-8AFYDSOYWebJYLyJi3fyjl6CqMEG/UVworjiyK1r573I56kb3e879sCJLGvR3merj+fAdPpVplXKQZv+ey6CgQ== + dependencies: + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + +postcss-reduce-idents@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.0.1.tgz#99b49ce8ee6f9c179447671cc9693e198e877bb7" + integrity sha512-6Rw8iIVFbqtaZExgWK1rpVgP7DPFRPh0DDFZxJ/ADNqPiH10sPCoq5tgo6kLiTyfh9sxjKYjXdc8udLEcPOezg== + dependencies: + postcss-value-parser "^4.1.0" + +postcss-reduce-initial@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.1.tgz#9d6369865b0f6f6f6b165a0ef5dc1a4856c7e946" + integrity sha512-zlCZPKLLTMAqA3ZWH57HlbCjkD55LX9dsRyxlls+wfuRfqCi5mSlZVan0heX5cHr154Dq9AfbH70LyhrSAezJw== + dependencies: + browserslist "^4.16.0" + caniuse-api "^3.0.0" + +postcss-reduce-initial@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.2.tgz#fa424ce8aa88a89bc0b6d0f94871b24abe94c048" + integrity sha512-v/kbAAQ+S1V5v9TJvbGkV98V2ERPdU6XvMcKMjqAlYiJ2NtsHGlKYLPjWWcXlaTKNxooId7BGxeraK8qXvzKtw== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + +postcss-reduce-transforms@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz#93c12f6a159474aa711d5269923e2383cedcf640" + integrity sha512-a//FjoPeFkRuAguPscTVmRQUODP+f3ke2HqFNgGPwdYnpeC29RZdCBvGRGTsKpMURb/I3p6jdKoBQ2zI+9Q7kA== + dependencies: + cssnano-utils "^2.0.1" + postcss-value-parser "^4.1.0" + +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: + version "6.0.5" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.5.tgz#042d74e137db83e6f294712096cb413f5aa612c4" + integrity sha512-aFYPoYmXbZ1V6HZaSvat08M97A8HqO6Pjz+PiNpw/DhuRrC72XWAdp3hL6wusDCN31sSmcZyMGa2hZEuX+Xfhg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-selector-parser@^6.0.5: + version "6.0.6" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" + integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-sort-media-queries@^3.10.11: + version "3.12.13" + resolved "https://registry.yarnpkg.com/postcss-sort-media-queries/-/postcss-sort-media-queries-3.12.13.tgz#213b1422e7efc29e0c2519b6ab259ff7d50b2156" + integrity sha512-bFbR1+P6HhZWXcT5DVV2pBH5Y2U5daKbFd0j+kcwKdzrxkbmgFu0GhI2JfFUyy5KQIeW+YJGP+vwNDOS5hIn2g== + dependencies: + sort-css-media-queries "2.0.4" + +postcss-svgo@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.2.tgz#bc73c4ea4c5a80fbd4b45e29042c34ceffb9257f" + integrity sha512-YzQuFLZu3U3aheizD+B1joQ94vzPfE6BNUcSYuceNxlVnKKsOtdo6hL9/zyC168Q8EwfLSgaDSalsUGa9f2C0A== + dependencies: + postcss-value-parser "^4.1.0" + svgo "^2.3.0" + +postcss-svgo@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.3.tgz#d945185756e5dfaae07f9edb0d3cae7ff79f9b30" + integrity sha512-41XZUA1wNDAZrQ3XgWREL/M2zSw8LJPvb5ZWivljBsUQAGoEKMYm6okHsTjJxKYI4M75RQEH4KYlEM52VwdXVA== + dependencies: + postcss-value-parser "^4.1.0" + svgo "^2.7.0" + +postcss-unique-selectors@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz#3be5c1d7363352eff838bd62b0b07a0abad43bfc" + integrity sha512-gwi1NhHV4FMmPn+qwBNuot1sG1t2OmacLQ/AX29lzyggnjd+MnVD5uqQmpXO3J17KGL2WAxQruj1qTd3H0gG/w== + dependencies: + alphanum-sort "^1.0.2" + postcss-selector-parser "^6.0.5" + uniqs "^2.0.0" + +postcss-unique-selectors@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.2.tgz#5d6893daf534ae52626708e0d62250890108c0c1" + integrity sha512-w3zBVlrtZm7loQWRPVC0yjUwwpty7OM6DnEHkxcSQXO1bMS3RJ+JUS5LFMSDZHJcvGsRwhZinCWVqn8Kej4EDA== + dependencies: + alphanum-sort "^1.0.2" + postcss-selector-parser "^6.0.5" + +postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + +postcss-zindex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-5.0.1.tgz#c585724beb69d356af8c7e68847b28d6298ece03" + integrity sha512-nwgtJJys+XmmSGoYCcgkf/VczP8Mp/0OfSv3v0+fw0uABY4yxw+eFs0Xp9nAZHIKnS5j+e9ywQ+RD+ONyvl5pA== + +"postcss@5 - 7": + version "7.0.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + +postcss@^8.2.10, postcss@^8.3.5: + version "8.3.9" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.9.tgz#98754caa06c4ee9eb59cc48bd073bb6bd3437c31" + integrity sha512-f/ZFyAKh9Dnqytx5X62jgjhhzttjZS7hMsohcI7HEI5tjELX/HxCy3EFhsRxyzGvrzFF+82XPvCS8T9TFleVJw== + dependencies: + nanoid "^3.1.28" + picocolors "^0.2.1" + source-map-js "^0.6.2" + +postcss@^8.2.15, postcss@^8.3.11: + version "8.4.4" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.4.tgz#d53d4ec6a75fd62557a66bb41978bf47ff0c2869" + integrity sha512-joU6fBsN6EIer28Lj6GDFoC/5yOZzLCfn0zHAn/MYXI7aPt4m4hK5KC5ovEZXy+lnCjmYIbQWngvju2ddyEr8Q== + dependencies: + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^1.0.1" + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +pretty-error@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6" + integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== + dependencies: + lodash "^4.17.20" + renderkid "^3.0.0" + +pretty-time@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e" + integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA== + +prism-react-renderer@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.2.1.tgz#392460acf63540960e5e3caa699d851264e99b89" + integrity sha512-w23ch4f75V1Tnz8DajsYKvY5lF7H1+WvzvLUcF0paFxkTHSp42RS0H5CttdN2Q8RR3DRGZ9v5xD/h3n8C8kGmg== + +prismjs@^1.23.0: + version "1.25.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756" + integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + +prompts@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.0.tgz#4aa5de0723a231d1ee9121c40fdf663df73f61d7" + integrity sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +prompts@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +prop-types@^15.5.0, prop-types@^15.6.2, prop-types@^15.7.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + +property-information@^5.0.0, property-information@^5.3.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" + integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== + dependencies: + xtend "^4.0.0" + +proxy-addr@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +pupa@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" + integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== + dependencies: + escape-goat "^2.0.0" + +pure-color@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e" + integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4= + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-base16-styling@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c" + integrity sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw= + dependencies: + base16 "^1.0.0" + lodash.curry "^4.0.1" + lodash.flow "^3.3.0" + pure-color "^1.2.0" + +react-dev-utils@^11.0.1: + version "11.0.4" + resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-11.0.4.tgz#a7ccb60257a1ca2e0efe7a83e38e6700d17aa37a" + integrity sha512-dx0LvIGHcOPtKbeiSUM4jqpBl3TcY7CDjZdfOIcKeznE7BWr9dg0iPG90G5yfVQ+p/rGNMXdbfStvzQZEVEi4A== + dependencies: + "@babel/code-frame" "7.10.4" + address "1.1.2" + browserslist "4.14.2" + chalk "2.4.2" + cross-spawn "7.0.3" + detect-port-alt "1.1.6" + escape-string-regexp "2.0.0" + filesize "6.1.0" + find-up "4.1.0" + fork-ts-checker-webpack-plugin "4.1.6" + global-modules "2.0.0" + globby "11.0.1" + gzip-size "5.1.1" + immer "8.0.1" + is-root "2.1.0" + loader-utils "2.0.0" + open "^7.0.2" + pkg-up "3.1.0" + prompts "2.4.0" + react-error-overlay "^6.0.9" + recursive-readdir "2.2.2" + shell-quote "1.7.2" + strip-ansi "6.0.0" + text-table "0.2.0" + +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + +react-error-overlay@^6.0.9: + version "6.0.9" + resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" + integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew== + +react-fast-compare@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" + integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== + +react-helmet@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726" + integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw== + dependencies: + object-assign "^4.1.1" + prop-types "^15.7.2" + react-fast-compare "^3.1.1" + react-side-effect "^2.1.0" + +react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-json-view@^1.21.3: + version "1.21.3" + resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.21.3.tgz#f184209ee8f1bf374fb0c41b0813cff54549c475" + integrity sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw== + dependencies: + flux "^4.0.1" + react-base16-styling "^0.6.0" + react-lifecycles-compat "^3.0.4" + react-textarea-autosize "^8.3.2" + +react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-loadable-ssr-addon-v5-slorber@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz#2cdc91e8a744ffdf9e3556caabeb6e4278689883" + integrity sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A== + dependencies: + "@babel/runtime" "^7.10.3" + +react-loadable@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/react-loadable/-/react-loadable-5.5.0.tgz#582251679d3da86c32aae2c8e689c59f1196d8c4" + integrity sha512-C8Aui0ZpMd4KokxRdVAm2bQtI03k2RMRNzOB+IipV3yxFTSVICv7WoUr5L9ALB5BmKO1iHgZtWM8EvYG83otdg== + dependencies: + prop-types "^15.5.0" + +react-router-config@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/react-router-config/-/react-router-config-5.1.1.tgz#0f4263d1a80c6b2dc7b9c1902c9526478194a988" + integrity sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg== + dependencies: + "@babel/runtime" "^7.1.2" + +react-router-dom@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" + integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + loose-envify "^1.3.1" + prop-types "^15.6.2" + react-router "5.2.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router@5.2.0, react-router@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" + integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.4.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-side-effect@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.1.tgz#66c5701c3e7560ab4822a4ee2742dee215d72eb3" + integrity sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ== + +react-textarea-autosize@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.2.tgz#4f9374d357b0a6f6469956726722549124a1b2db" + integrity sha512-JrMWVgQSaExQByP3ggI1eA8zF4mF0+ddVuX7acUeK2V7bmrpjVOY72vmLz2IXFJSAXoY3D80nEzrn0GWajWK3Q== + dependencies: + "@babel/runtime" "^7.10.2" + use-composed-ref "^1.0.0" + use-latest "^1.0.0" + +react@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +readable-stream@^2.0.1, readable-stream@^2.0.2: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6, readable-stream@^3.1.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +reading-time@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/reading-time/-/reading-time-1.5.0.tgz#d2a7f1b6057cb2e169beaf87113cc3411b5bc5bb" + integrity sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg== + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +recursive-readdir@2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" + integrity sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg== + dependencies: + minimatch "3.0.4" + +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4: + version "0.13.7" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" + integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== + +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexp.prototype.flags@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +regexpu-core@^4.7.1: + version "4.7.1" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" + integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.2.0" + regjsgen "^0.5.1" + regjsparser "^0.6.4" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.2.0" + +registry-auth-token@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" + integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== + dependencies: + rc "^1.2.8" + +registry-url@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" + integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== + dependencies: + rc "^1.2.8" + +regjsgen@^0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== + +regjsparser@^0.6.4: + version "0.6.9" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6" + integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ== + dependencies: + jsesc "~0.5.0" + +rehype-parse@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/rehype-parse/-/rehype-parse-6.0.2.tgz#aeb3fdd68085f9f796f1d3137ae2b85a98406964" + integrity sha512-0S3CpvpTAgGmnz8kiCyFLGuW5yA4OQhyNTm/nwPopZ7+PI11WnGl1TTWTGv/2hPEe/g2jRLlhVVSsoDH8waRug== + dependencies: + hast-util-from-parse5 "^5.0.0" + parse5 "^5.0.0" + xtend "^4.0.0" + +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + +remark-admonitions@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/remark-admonitions/-/remark-admonitions-1.2.1.tgz#87caa1a442aa7b4c0cafa04798ed58a342307870" + integrity sha512-Ji6p68VDvD+H1oS95Fdx9Ar5WA2wcDA4kwrrhVU7fGctC6+d3uiMICu7w7/2Xld+lnU7/gi+432+rRbup5S8ow== + dependencies: + rehype-parse "^6.0.2" + unified "^8.4.2" + unist-util-visit "^2.0.1" + +remark-emoji@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/remark-emoji/-/remark-emoji-2.2.0.tgz#1c702090a1525da5b80e15a8f963ef2c8236cac7" + integrity sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w== + dependencies: + emoticon "^3.2.0" + node-emoji "^1.10.0" + unist-util-visit "^2.0.3" + +remark-footnotes@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/remark-footnotes/-/remark-footnotes-2.0.0.tgz#9001c4c2ffebba55695d2dd80ffb8b82f7e6303f" + integrity sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ== + +remark-mdx@1.6.22: + version "1.6.22" + resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-1.6.22.tgz#06a8dab07dcfdd57f3373af7f86bd0e992108bbd" + integrity sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ== + dependencies: + "@babel/core" "7.12.9" + "@babel/helper-plugin-utils" "7.10.4" + "@babel/plugin-proposal-object-rest-spread" "7.12.1" + "@babel/plugin-syntax-jsx" "7.12.1" + "@mdx-js/util" "1.6.22" + is-alphabetical "1.0.4" + remark-parse "8.0.3" + unified "9.2.0" + +remark-parse@8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-8.0.3.tgz#9c62aa3b35b79a486454c690472906075f40c7e1" + integrity sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q== + dependencies: + ccount "^1.0.0" + collapse-white-space "^1.0.2" + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + is-word-character "^1.0.0" + markdown-escapes "^1.0.0" + parse-entities "^2.0.0" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + trim "0.0.1" + trim-trailing-lines "^1.0.0" + unherit "^1.0.4" + unist-util-remove-position "^2.0.0" + vfile-location "^3.0.0" + xtend "^4.0.1" + +remark-squeeze-paragraphs@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz#76eb0e085295131c84748c8e43810159c5653ead" + integrity sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw== + dependencies: + mdast-squeeze-paragraphs "^4.0.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +renderkid@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" + integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg== + dependencies: + css-select "^4.1.3" + dom-converter "^0.2.0" + htmlparser2 "^6.1.0" + lodash "^4.17.21" + strip-ansi "^6.0.1" + +repeat-element@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== + +repeat-string@^1.5.4, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +"require-like@>= 0.1.1": + version "0.1.2" + resolved "https://registry.yarnpkg.com/require-like/-/require-like-0.1.2.tgz#ad6f30c13becd797010c468afa775c0c0a6b47fa" + integrity sha1-rW8wwTvs15cBDEaK+ndcDAprR/o= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-pathname@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" + integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.1.6: + version "1.21.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f" + integrity sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA== + dependencies: + is-core-module "^2.8.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^1.14.2, resolve@^1.3.2: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rtl-detect@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/rtl-detect/-/rtl-detect-1.0.4.tgz#40ae0ea7302a150b96bc75af7d749607392ecac6" + integrity sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ== + +rtlcss@^3.1.2: + version "3.5.0" + resolved "https://registry.yarnpkg.com/rtlcss/-/rtlcss-3.5.0.tgz#c9eb91269827a102bac7ae3115dd5d049de636c3" + integrity sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A== + dependencies: + find-up "^5.0.0" + picocolors "^1.0.0" + postcss "^8.3.11" + strip-json-comments "^3.1.1" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^6.6.3: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@^1.2.4, sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +schema-utils@^2.6.5: + version "2.7.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== + dependencies: + "@types/json-schema" "^7.0.5" + ajv "^6.12.4" + ajv-keywords "^3.5.2" + +schema-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.0.0.tgz#67502f6aa2b66a2d4032b4279a2944978a0913ef" + integrity sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA== + dependencies: + "@types/json-schema" "^7.0.6" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" + integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.8.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.0.0" + +section-matter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" + integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA== + dependencies: + extend-shallow "^2.0.1" + kind-of "^6.0.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= + +selfsigned@^1.10.8: + version "1.10.11" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.11.tgz#24929cd906fe0f44b6d01fb23999a739537acbe9" + integrity sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA== + dependencies: + node-forge "^0.10.0" + +semver-diff@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" + integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== + dependencies: + semver "^6.3.0" + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.4, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serialize-javascript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +serve-handler@^6.1.3: + version "6.1.3" + resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.3.tgz#1bf8c5ae138712af55c758477533b9117f6435e8" + integrity sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w== + dependencies: + bytes "3.0.0" + content-disposition "0.5.2" + fast-url-parser "1.1.3" + mime-types "2.1.18" + minimatch "3.0.4" + path-is-inside "1.0.2" + path-to-regexp "2.2.1" + range-parser "1.2.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" + integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + +shelljs@^0.8.4: + version "0.8.5" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" + integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^3.0.0: + version "3.0.6" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== + +signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +sirv@^1.0.7: + version "1.0.11" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.11.tgz#81c19a29202048507d6ec0d8ba8910fda52eb5a4" + integrity sha512-SR36i3/LSWja7AJNRBz4fF/Xjpn7lQFI30tZ434dIy+bitLYSP+ZEenHg36i23V2SGEz+kqjksg0uOGZ5LPiqg== + dependencies: + "@polka/url" "^1.0.0-next.9" + mime "^2.3.1" + totalist "^1.0.0" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +sitemap@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/sitemap/-/sitemap-7.0.0.tgz#022bef4df8cba42e38e1fe77039f234cab0372b6" + integrity sha512-Ud0jrRQO2k7fEtPAM+cQkBKoMvxQyPKNXKDLn8tRVHxRCsdDQ2JZvw+aZ5IRYYQVAV9iGxEar6boTwZzev+x3g== + dependencies: + "@types/node" "^15.0.1" + "@types/sax" "^1.2.1" + arg "^5.0.0" + sax "^1.2.4" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sockjs-client@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.2.tgz#4bc48c2da9ce4769f19dc723396b50f5c12330a3" + integrity sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ== + dependencies: + debug "^3.2.6" + eventsource "^1.0.7" + faye-websocket "^0.11.3" + inherits "^2.0.4" + json3 "^3.3.3" + url-parse "^1.5.3" + +sockjs@^0.3.21: + version "0.3.21" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.21.tgz#b34ffb98e796930b60a0cfa11904d6a339a7d417" + integrity sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw== + dependencies: + faye-websocket "^0.11.3" + uuid "^3.4.0" + websocket-driver "^0.7.4" + +sort-css-media-queries@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/sort-css-media-queries/-/sort-css-media-queries-2.0.4.tgz#b2badfa519cb4a938acbc6d3aaa913d4949dc908" + integrity sha512-PAIsEK/XupCQwitjv7XxoMvYhT7EAfyzI3hsy/MyDgTvc+Ft55ctdkctJLOy6cQejaIC+zjpUL4djFVm2ivOOw== + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-js@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" + integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== + +source-map-js@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf" + integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA== + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@~0.5.12: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@~0.5.20: + version "0.5.20" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + +source-map@^0.5.0, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@~0.7.2: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +space-separated-tokens@^1.0.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" + integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +state-toggle@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" + integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ== + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +std-env@^2.2.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-2.3.0.tgz#66d4a4a4d5224242ed8e43f5d65cfa9095216eee" + integrity sha512-4qT5B45+Kjef2Z6pE0BkskzsH0GO7GrND0wGlTM1ioUe3v0dGYx9ZJH0Aro/YyA8fqQ5EyIKDRjZojJYMFTflw== + dependencies: + ci-info "^3.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +stringify-object@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" + integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== + dependencies: + get-own-enumerable-property-symbols "^3.0.0" + is-obj "^1.0.1" + is-regexp "^1.0.0" + +strip-ansi@6.0.0, strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" + integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +style-to-object@0.3.0, style-to-object@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46" + integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA== + dependencies: + inline-style-parser "0.1.1" + +stylehacks@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.0.1.tgz#323ec554198520986806388c7fdaebc38d2c06fb" + integrity sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA== + dependencies: + browserslist "^4.16.0" + postcss-selector-parser "^6.0.4" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +svg-parser@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" + integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== + +svgo@^1.2.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== + dependencies: + chalk "^2.4.1" + coa "^2.0.2" + css-select "^2.0.0" + css-select-base-adapter "^0.1.1" + css-tree "1.0.0-alpha.37" + csso "^4.0.2" + js-yaml "^3.13.1" + mkdirp "~0.5.1" + object.values "^1.1.0" + sax "~1.2.4" + stable "^0.1.8" + unquote "~1.1.1" + util.promisify "~1.0.0" + +svgo@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.3.0.tgz#6b3af81d0cbd1e19c83f5f63cec2cb98c70b5373" + integrity sha512-fz4IKjNO6HDPgIQxu4IxwtubtbSfGEAJUq/IXyTPIkGhWck/faiiwfkvsB8LnBkKLvSoyNNIY6d13lZprJMc9Q== + dependencies: + "@trysound/sax" "0.1.1" + chalk "^4.1.0" + commander "^7.1.0" + css-select "^3.1.2" + css-tree "^1.1.2" + csso "^4.2.0" + stable "^0.1.8" + +svgo@^2.7.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" + integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^4.1.3" + css-tree "^1.1.3" + csso "^4.2.0" + picocolors "^1.0.0" + stable "^0.1.8" + +tapable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b" + integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw== + +terser-webpack-plugin@^5.1.3: + version "5.2.4" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz#ad1be7639b1cbe3ea49fab995cbe7224b31747a1" + integrity sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA== + dependencies: + jest-worker "^27.0.6" + p-limit "^3.1.0" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + terser "^5.7.2" + +terser@^4.6.3: + version "4.8.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" + integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +terser@^5.7.2: + version "5.9.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.9.0.tgz#47d6e629a522963240f2b55fcaa3c99083d2c351" + integrity sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.20" + +text-table@0.2.0, text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + +tiny-invariant@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" + integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== + +tiny-warning@^1.0.0, tiny-warning@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +totalist@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" + integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== + +trim-trailing-lines@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz#bd4abbec7cc880462f10b2c8b5ce1d8d1ec7c2c0" + integrity sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ== + +trim@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" + integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= + +trough@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" + integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== + +ts-essentials@^2.0.3: + version "2.0.12" + resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-2.0.12.tgz#c9303f3d74f75fa7528c3d49b80e089ab09d8745" + integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w== + +tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +ua-parser-js@^0.7.18: + version "0.7.28" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31" + integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g== + +unbox-primitive@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +unherit@^1.0.4: + version "1.1.3" + resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" + integrity sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ== + dependencies: + inherits "^2.0.0" + xtend "^4.0.0" + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" + integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== + +unified@9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.0.tgz#67a62c627c40589edebbf60f53edfd4d822027f8" + integrity sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg== + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-buffer "^2.0.0" + is-plain-obj "^2.0.0" + trough "^1.0.0" + vfile "^4.0.0" + +unified@^8.4.2: + version "8.4.2" + resolved "https://registry.yarnpkg.com/unified/-/unified-8.4.2.tgz#13ad58b4a437faa2751a4a4c6a16f680c500fff1" + integrity sha512-JCrmN13jI4+h9UAyKEoGcDZV+i1E7BLFuG7OsaDvTXI5P0qhHX+vZO/kOhz9jn8HGENDKbwSeB0nVOg4gVStGA== + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-plain-obj "^2.0.0" + trough "^1.0.0" + vfile "^4.0.0" + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= + +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + +unist-builder@2.0.3, unist-builder@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436" + integrity sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw== + +unist-util-generated@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.6.tgz#5ab51f689e2992a472beb1b35f2ce7ff2f324d4b" + integrity sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg== + +unist-util-is@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" + integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== + +unist-util-position@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.1.0.tgz#1c42ee6301f8d52f47d14f62bbdb796571fa2d47" + integrity sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA== + +unist-util-remove-position@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz#5d19ca79fdba712301999b2b73553ca8f3b352cc" + integrity sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA== + dependencies: + unist-util-visit "^2.0.0" + +unist-util-remove@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unist-util-remove/-/unist-util-remove-2.1.0.tgz#b0b4738aa7ee445c402fda9328d604a02d010588" + integrity sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q== + dependencies: + unist-util-is "^4.0.0" + +unist-util-stringify-position@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" + integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== + dependencies: + "@types/unist" "^2.0.2" + +unist-util-visit-parents@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz#65a6ce698f78a6b0f56aa0e88f13801886cdaef6" + integrity sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^4.0.0" + +unist-util-visit@2.0.3, unist-util-visit@^2.0.0, unist-util-visit@^2.0.1, unist-util-visit@^2.0.2, unist-util-visit@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.3.tgz#c3703893146df47203bb8a9795af47d7b971208c" + integrity sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^4.0.0" + unist-util-visit-parents "^3.0.0" + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +update-notifier@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-5.1.0.tgz#4ab0d7c7f36a231dd7316cf7729313f0214d9ad9" + integrity sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw== + dependencies: + boxen "^5.0.0" + chalk "^4.1.0" + configstore "^5.0.1" + has-yarn "^2.1.0" + import-lazy "^2.1.0" + is-ci "^2.0.0" + is-installed-globally "^0.4.0" + is-npm "^5.0.0" + is-yarn-global "^0.3.0" + latest-version "^5.1.0" + pupa "^2.1.1" + semver "^7.3.4" + semver-diff "^3.1.1" + xdg-basedir "^4.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-loader@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2" + integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== + dependencies: + loader-utils "^2.0.0" + mime-types "^2.1.27" + schema-utils "^3.0.0" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + +url-parse@^1.4.3, url-parse@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" + integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use-composed-ref@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.1.0.tgz#9220e4e94a97b7b02d7d27eaeab0b37034438bbc" + integrity sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg== + dependencies: + ts-essentials "^2.0.3" + +use-isomorphic-layout-effect@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz#7bb6589170cd2987a152042f9084f9effb75c225" + integrity sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ== + +use-latest@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.0.tgz#a44f6572b8288e0972ec411bdd0840ada366f232" + integrity sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw== + dependencies: + use-isomorphic-layout-effect "^1.0.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util.promisify@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= + +utility-types@^3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b" + integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2, uuid@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +value-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" + integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +vendors@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" + integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== + +vfile-location@^3.0.0, vfile-location@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.2.0.tgz#d8e41fbcbd406063669ebf6c33d56ae8721d0f3c" + integrity sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA== + +vfile-message@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" + integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^2.0.0" + +vfile@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624" + integrity sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA== + dependencies: + "@types/unist" "^2.0.0" + is-buffer "^2.0.0" + unist-util-stringify-position "^2.0.0" + vfile-message "^2.0.0" + +wait-on@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-5.3.0.tgz#584e17d4b3fe7b46ac2b9f8e5e102c005c2776c7" + integrity sha512-DwrHrnTK+/0QFaB9a8Ol5Lna3k7WvUR4jzSKmz0YaPBpuN2sACyiPVKVfj6ejnjcajAcvn3wlbTyMIn9AZouOg== + dependencies: + axios "^0.21.1" + joi "^17.3.0" + lodash "^4.17.21" + minimist "^1.2.5" + rxjs "^6.6.3" + +watchpack@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" + integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +web-namespaces@^1.0.0, web-namespaces@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" + integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== + +webpack-bundle-analyzer@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.2.tgz#39898cf6200178240910d629705f0f3493f7d666" + integrity sha512-PIagMYhlEzFfhMYOzs5gFT55DkUdkyrJi/SxJp8EF3YMWhS+T9vvs2EoTetpk5qb6VsCq02eXTlRDOydRhDFAQ== + dependencies: + acorn "^8.0.4" + acorn-walk "^8.0.0" + chalk "^4.1.0" + commander "^6.2.0" + gzip-size "^6.0.0" + lodash "^4.17.20" + opener "^1.5.2" + sirv "^1.0.7" + ws "^7.3.1" + +webpack-dev-middleware@^3.7.2: + version "3.7.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" + integrity sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.4" + mkdirp "^0.5.1" + range-parser "^1.2.1" + webpack-log "^2.0.0" + +webpack-dev-server@^3.11.2: + version "3.11.3" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.3.tgz#8c86b9d2812bf135d3c9bce6f07b718e30f7c3d3" + integrity sha512-3x31rjbEQWKMNzacUZRE6wXvUFuGpH7vr0lIEbYpMAG9BOxi0928QU1BBswOAP3kg3H1O4hiS+sq4YyAn6ANnA== + dependencies: + ansi-html-community "0.0.8" + bonjour "^3.5.0" + chokidar "^2.1.8" + compression "^1.7.4" + connect-history-api-fallback "^1.6.0" + debug "^4.1.1" + del "^4.1.1" + express "^4.17.1" + html-entities "^1.3.1" + http-proxy-middleware "0.19.1" + import-local "^2.0.0" + internal-ip "^4.3.0" + ip "^1.1.5" + is-absolute-url "^3.0.3" + killable "^1.0.1" + loglevel "^1.6.8" + opn "^5.5.0" + p-retry "^3.0.1" + portfinder "^1.0.26" + schema-utils "^1.0.0" + selfsigned "^1.10.8" + semver "^6.3.0" + serve-index "^1.9.1" + sockjs "^0.3.21" + sockjs-client "^1.5.0" + spdy "^4.0.2" + strip-ansi "^3.0.1" + supports-color "^6.1.0" + url "^0.11.0" + webpack-dev-middleware "^3.7.2" + webpack-log "^2.0.0" + ws "^6.2.1" + yargs "^13.3.2" + +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-merge@^5.8.0: + version "5.8.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" + integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + +webpack-sources@^1.1.0, webpack-sources@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack-sources@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.2.tgz#d88e3741833efec57c4c789b6010db9977545260" + integrity sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw== + +webpack@^5.40.0: + version "5.65.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.65.0.tgz#ed2891d9145ba1f0d318e4ea4f89c3fa18e6f9be" + integrity sha512-Q5or2o6EKs7+oKmJo7LaqZaMOlDWQse9Tm5l1WAfU/ujLGN5Pb0SqGeVkN/4bpPmEqEP5RnVhiqsOtWtUVwGRw== + dependencies: + "@types/eslint-scope" "^3.7.0" + "@types/estree" "^0.0.50" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.4.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.8.3" + es-module-lexer "^0.9.0" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.4" + json-parse-better-errors "^1.0.2" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.3.1" + webpack-sources "^3.2.2" + +webpackbar@^5.0.0-3: + version "5.0.0-3" + resolved "https://registry.yarnpkg.com/webpackbar/-/webpackbar-5.0.0-3.tgz#f4f96c8fb13001b2bb1348252db4c980ab93aaac" + integrity sha512-viW6KCYjMb0NPoDrw2jAmLXU2dEOhRrtku28KmOfeE1vxbfwCYuTbTaMhnkrCZLFAFyY9Q49Z/jzYO80Dw5b8g== + dependencies: + ansi-escapes "^4.3.1" + chalk "^4.1.0" + consola "^2.15.0" + figures "^3.2.0" + pretty-time "^1.1.0" + std-env "^2.2.1" + text-table "^0.2.0" + wrap-ansi "^7.0.0" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== + dependencies: + string-width "^4.0.0" + +wildcard@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" + integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== + +worker-rpc@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5" + integrity sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg== + dependencies: + microevent.ts "~0.1.1" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" + integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== + dependencies: + async-limiter "~1.0.0" + +ws@^7.3.1: + version "7.4.5" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.5.tgz#a484dd851e9beb6fdb420027e3885e8ce48986c1" + integrity sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g== + +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + +xml-js@^1.6.11: + version "1.6.11" + resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" + integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== + dependencies: + sax "^1.2.4" + +xtend@^4.0.0, xtend@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^1.10.0, yaml@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@^13.3.2: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zwitch@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" + integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw== diff --git a/OpenRefine/extensions/database/.eclipse-pmd b/OpenRefine/extensions/database/.eclipse-pmd new file mode 100644 index 000000000..4a705f215 --- /dev/null +++ b/OpenRefine/extensions/database/.eclipse-pmd @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/OpenRefine/extensions/database/.eslintrc.json b/OpenRefine/extensions/database/.eslintrc.json new file mode 100644 index 000000000..d15f78754 --- /dev/null +++ b/OpenRefine/extensions/database/.eslintrc.json @@ -0,0 +1,28 @@ +{ + "env": { + "browser": true, + "es6": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "indent": [ + "error", + 4 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "double" + ], + "semi": [ + "error", + "always" + ] + } +} \ No newline at end of file diff --git a/OpenRefine/extensions/database/.travis.yml b/OpenRefine/extensions/database/.travis.yml new file mode 100644 index 000000000..800ed8b08 --- /dev/null +++ b/OpenRefine/extensions/database/.travis.yml @@ -0,0 +1,24 @@ +language: java + +jdk: + - oraclejdk8 + +addons: + mariadb: '10.0' + +services: + - mysql + - postgresql + +before_install: + + - mysql -u root -e 'CREATE DATABASE test_db;' + - mysql -u root test_db < test/conf/travis-mysql.sql + + - psql -c 'CREATE DATABASE test_db;' -U postgres + - psql -U postgres test_db < test/conf/travis-pgsql.sql + + +script: + - ant test + diff --git a/OpenRefine/extensions/database/README.md b/OpenRefine/extensions/database/README.md new file mode 100644 index 000000000..0dd07734c --- /dev/null +++ b/OpenRefine/extensions/database/README.md @@ -0,0 +1,9 @@ +This project is an OpenRefine extension for importing database data using JDBC. +For exporting to a database, other code can be found under folder `OpenRefine/main/src/com/google/refine/exporters/sql` + +## Adding support for other database vendors + +1. You'll want to register an additional Database Service: https://github.com/OpenRefine/OpenRefine/blob/master/extensions/database/src/com/google/refine/extension/database/DatabaseService.java +2. Provide the connection and service classes, look at the PostgreSQL one or MySQL one as examples: https://github.com/OpenRefine/OpenRefine/tree/master/extensions/database/src/com/google/refine/extension/database +3. Then wire up the interface with defaults as desired: https://github.com/OpenRefine/OpenRefine/blob/master/extensions/database/module/scripts/index/database-source-ui.js#L93 +4. Add drivers manually to the classpath, or update the pom file to provide them as dependencies as other DB libraries are done: https://github.com/OpenRefine/OpenRefine/blob/master/extensions/database/pom.xml diff --git a/OpenRefine/extensions/database/licenses/jdbc-client.LICENSE.txt b/OpenRefine/extensions/database/licenses/jdbc-client.LICENSE.txt new file mode 100644 index 000000000..a14b06b91 --- /dev/null +++ b/OpenRefine/extensions/database/licenses/jdbc-client.LICENSE.txt @@ -0,0 +1,188 @@ +Copyright 2006 Google + + 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. + + 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. \ No newline at end of file diff --git a/OpenRefine/extensions/database/module/MOD-INF/.gitignore b/OpenRefine/extensions/database/module/MOD-INF/.gitignore new file mode 100644 index 000000000..840e7d312 --- /dev/null +++ b/OpenRefine/extensions/database/module/MOD-INF/.gitignore @@ -0,0 +1 @@ +/classes/ diff --git a/OpenRefine/extensions/database/module/MOD-INF/controller.js b/OpenRefine/extensions/database/module/MOD-INF/controller.js new file mode 100644 index 000000000..959745b5a --- /dev/null +++ b/OpenRefine/extensions/database/module/MOD-INF/controller.js @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Controller for JDBC Database extension. + * + * This is run in the Butterfly (ie Refine) server context using the Rhino + * Javascript interpreter. + */ + +var html = "text/html"; +var encoding = "UTF-8"; +var version = "0.1"; +var ClientSideResourceManager = Packages.com.google.refine.ClientSideResourceManager; + +var logger = Packages.org.slf4j.LoggerFactory.getLogger("database-extension"), +File = Packages.java.io.File, +refineServlet = Packages.com.google.refine.RefineServlet; + +/* + * Register our custom commands. + */ +function registerCommands() { + + logger.trace("Registering Database Extension Commands......"); + var RS = Packages.com.google.refine.RefineServlet; + RS.registerCommand(module, "test-connect", Packages.com.google.refine.extension.database.cmd.TestConnectCommand()); + RS.registerCommand(module, "connect", Packages.com.google.refine.extension.database.cmd.ConnectCommand()); + RS.registerCommand(module, "saved-connection", Packages.com.google.refine.extension.database.cmd.SavedConnectionCommand()); + RS.registerCommand(module, "execute-query", Packages.com.google.refine.extension.database.cmd.ExecuteQueryCommand()); + RS.registerCommand(module, "test-query", Packages.com.google.refine.extension.database.cmd.TestQueryCommand()); + logger.trace("Database Extension Command Registration done!!"); +} + +function registerOperations() { +} + +function registerFunctions() { +} + + +/* + * Function invoked to initialize the extension. + */ +function init() { + + logger.trace("Initializing OpenRefine Database Extension..."); + logger.trace("Database Extension Mount point " + module.getMountPoint()); + + registerCommands(); + registerOperations(); + registerFunctions(); + + + // Register importer and exporter + var IM = Packages.com.google.refine.importing.ImportingManager; + + IM.registerController( + module, + "database-import-controller", + new Packages.com.google.refine.extension.database.DatabaseImportController() + ); + + + // Script files to inject into /index page + ClientSideResourceManager.addPaths( + "index/scripts", + module, + [ + "scripts/index/jquery.contextMenu.min.js", + "scripts/index/jquery.ui.position.min.js", + "scripts/database-extension.js", + "scripts/index/database-import-controller.js", + "scripts/index/database-source-ui.js" + ] + ); + // Style files to inject into /index page + ClientSideResourceManager.addPaths( + "index/styles", + module, + [ + "styles/jquery.contextMenu.css", + "styles/pure.css", + "styles/bootstrap.css", + "styles/database-import.less" + + ] + ); + + // Script files to inject into /project page + ClientSideResourceManager.addPaths( + "project/scripts", + module, + [ + "scripts/database-extension.js", + "scripts/project/database-exporters.js" + ] + ); +} + +/* + * Function invoked to handle each request in a custom way. + */ +function process(path, request, response) { + + + var method = request.getMethod(); + + logger.trace('receiving request for ' + path); + + if (path == "/" || path == "") { + var context = {}; + context.version = version; + send(request, response, "index.vt", context); + } +} + +function send(request, response, template, context) { + butterfly.sendTextFromTemplate(request, response, context, template, encoding, html); +} diff --git a/OpenRefine/extensions/database/module/MOD-INF/dbextension.properties b/OpenRefine/extensions/database/module/MOD-INF/dbextension.properties new file mode 100644 index 000000000..db482f687 --- /dev/null +++ b/OpenRefine/extensions/database/module/MOD-INF/dbextension.properties @@ -0,0 +1,3 @@ +# Batch size for import data +preview.batchSize = 100 +create.batchSize = 1000 diff --git a/OpenRefine/extensions/database/module/MOD-INF/module.properties b/OpenRefine/extensions/database/module/MOD-INF/module.properties new file mode 100644 index 000000000..2b0cef961 --- /dev/null +++ b/OpenRefine/extensions/database/module/MOD-INF/module.properties @@ -0,0 +1,7 @@ +name = database +description = Database importer/exporter for OpenRefine +templating.macros = macros.vm +requires = core + +# Use our custom class for a module implementation. +module-impl = com.google.refine.extension.database.DatabaseModuleImpl diff --git a/OpenRefine/extensions/database/module/images/fonts/glyphicons-halflings-regular.eot b/OpenRefine/extensions/database/module/images/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000000000000000000000000000000000000..b93a4953fff68df523aa7656497ee339d6026d64 GIT binary patch literal 20127 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenRefine/extensions/database/module/images/fonts/glyphicons-halflings-regular.ttf b/OpenRefine/extensions/database/module/images/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1413fc609ab6f21774de0cb7e01360095584f65b GIT binary patch literal 45404 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 G`u_lkUM?>H literal 0 HcmV?d00001 diff --git a/OpenRefine/extensions/database/module/images/fonts/glyphicons-halflings-regular.woff2 b/OpenRefine/extensions/database/module/images/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..64539b54c3751a6d9adb44c8e3a45ba5a73b77f0 GIT binary patch literal 18028 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 literal 0 HcmV?d00001 diff --git a/OpenRefine/extensions/database/module/images/more-option-horiz-16.png b/OpenRefine/extensions/database/module/images/more-option-horiz-16.png new file mode 100644 index 0000000000000000000000000000000000000000..0620d0a571c292088f1cefbcd6ab16a409eb6a54 GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ zaI}ChBX2miYKPfl0g7d?L7JY!>$gJ4as zr0}W--aRjuHOjir(i55fVEKdJ54OuhMm$qYH~)F5^3S33x96lwiyU`Sxs(mGg~8L+ K&t;ucLK6TPK1x>r literal 0 HcmV?d00001 diff --git a/OpenRefine/extensions/database/module/images/more_option-vert-16.png b/OpenRefine/extensions/database/module/images/more_option-vert-16.png new file mode 100644 index 0000000000000000000000000000000000000000..fa41b4f3b3abd7d5769c085d8e5740fb8458b41f GIT binary patch literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf66p}rHd>I(3)EF2VS{N990fib~ zFff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W>XMsm#F#`j)FbFd;%$g$s z6b$inaSYKopPaBj??F<;sSPcS!rPhZ+x|PeXpL@UI4su|%Tpt=^H9%0k^Nun6-*AT zJs_g-cltqw`I2rwmU1#FwmI{#H_TJDU$8?$%-~G&g9Uki7#Y+m1eSPB-gX6OK7*&L KpUXO@geCyE@k6-) literal 0 HcmV?d00001 diff --git a/OpenRefine/extensions/database/module/index.vt b/OpenRefine/extensions/database/module/index.vt new file mode 100644 index 000000000..147cb507b --- /dev/null +++ b/OpenRefine/extensions/database/module/index.vt @@ -0,0 +1,20 @@ +#* + * Access this page at the URL /extension/database/ + *# + + + OpenRefine Database Extension v$version + + +

OpenRefine DATABASE Extension v$version

+

by Tony Opara

+

The JDBC extension allows OpenRefine to read + (and write, soon) data from JDBC compatible databases(MySQL, PostgreSQL, MariaDB). +

+

Known Limitations

+
    +
  • No write support
  • + +
+ + \ No newline at end of file diff --git a/OpenRefine/extensions/database/module/langs/translation-bn.json b/OpenRefine/extensions/database/module/langs/translation-bn.json new file mode 100644 index 000000000..97fc6d466 --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-bn.json @@ -0,0 +1,4 @@ +{ + "database-import/preparing": "ফলাফল তৈরি করা হচà§à¦›à§‡â€¦", + "database-import/creating": "পà§à¦°à¦•à¦²à§à¦ª তৈরি হচà§à¦›à§‡â€¦" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-cs.json b/OpenRefine/extensions/database/module/langs/translation-cs.json new file mode 100644 index 000000000..11f3ec52b --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-cs.json @@ -0,0 +1,64 @@ +{ + "database-source/databasePasswordPlaceholder": "Zadejte heslo do databáze", + "database-parsing/ignore": "řádek/řádky/řádků na zaÄátku souboru", + "database-parsing/ignore-first": "Ignorovat první(ch)", + "database-source/alert-db-port-invalid-character": "Chyba v oznaÄení portu databáze: neplatný znak na vstupu. Povolené znaky: Äíslice.", + "database-source/alert-db-user-invalid-character": "Chyba v názvu uživatele databáze: neplatný znak na vstupu. Povolené znaky: písmena a Äíslice", + "database-source/alert-db-host-invalid-character": "Chyba v názvu hostitele databáze: neplatný znak na vstupu. Povolené znaky: písmena a Äíslice", + "database-source/alert-conn-name-invalid-character": "Chyba v názvu pÅ™ipojení: neplatný znak na vstupu. Povolené znaky: [a-zA-Z0-9._-]", + "database-parsing/store-row": "Uložit prázdné řádky", + "database-parsing/store-cell": "Uložit prádné buňky jako null", + "database-parsing/limit": "řádek/řádky/řádků dat", + "database-parsing/limit-next": "Nahrát nejvýše", + "database-parsing/discard": "řádek/řádky/řádků dat", + "database-parsing/discard-next": "Vynechat poÄáteÄní(ch)", + "database-parsing/parse": "řádek/řádky jako hlaviÄky sloupců", + "database-parsing/parse-next": "Analyzuj další(ch)", + "database-parsing/preview-button": "Aktualizuj náhled", + "database-parsing/option": "Možnosti", + "database-parsing/worksheet": "Pracovní listy", + "database-parsing/updating-preview": "Aktualizace náhledu…", + "database-parsing/create-proj": "VytvoÅ™i projekt »", + "database-parsing/proj-name": "Názevt projektu", + "database-parsing/conf-pars": "Nastavit možnosti parsování", + "database-parsing/start-over": "« ZaÄít znovu", + "database-source/savedConnectionSpan": "Uložená pÅ™ipojení", + "database-source/new-connection-legend": "Editor nového pÅ™ipojení", + "database-source/newConnectionButtonDiv": "Nové pÅ™ipojení", + "database-source/databaseConnectButton": "PÅ™ipojit", + "database-source/databaseSaveButton": "Uložit", + "database-source/databaseTestButton": "Otestovat", + "database-source/connectionNameDefaultValue": "Nazev_noveho_pripojeni", + "database-source/databaseSchemaPlaceholder": "Zadejte výchozí schéma databáze", + "database-source/databaseFileNamePlaceholder": "Zadejte plnou cestu k databázovému souboru", + "database-source/databaseNamePlaceholder": "Zadejte název databáze", + "database-source/databaseUserPlaceholder": "Zadejte uživatele databáze", + "database-source/databasePortPlaceholder": "Zadejte port databáze, napÅ™. 3306", + "database-source/databaseHostPlaceholder": "Zadejte doménu nebo IP adresu databázového serveru", + "database-source/connectionNamePlaceholder": "Zadejte nový název pÅ™ipojení", + "database-source/databaseSchemaLabel": "Schéma:", + "database-source/databaseFileNameLabel": "Databázový soubor:", + "database-source/databaseNameLabel": "Název databáze:", + "database-source/databasePasswordLabel": "Heslo:", + "database-source/databaseUserLabel": "Uživatel:", + "database-source/databasePortLabel": "Port:", + "database-source/databaseHostLabel": "Hostitel:", + "database-source/databaseTypeLabel": "Typ:", + "database-source/connectionNameLabel": "Název:", + "database-source/alert-connection-edit": "PÅ™ipojení bylo upraveno", + "database-source/form-validation-failure": "Nová podpoba pÅ™ipojení není platná!", + "database-source/alert-invalid-query-select": "Dotaz musí zaÄínat klíÄovým slovem SELECT", + "database-source/alert-invalid-query-keyword": "Dotaz nemůže obsahovat klíÄové slovo pro manipulaci s daty:", + "database-source/alert-query": "Musíte zadat validní dotaz", + "database-source/alert-initial-database": "Musíte urÄit výchozí databázi", + "database-source/alert-connection-name": "Musíte urÄit název pÅ™ipojení", + "database-source/alert-password": "Musíte urÄit heslo pro databázi", + "database-source/alert-user": "Musíte urÄit uživatele databáze", + "database-source/alert-port": "Musíte urÄit port u databáze", + "database-source/alert-host": "Musíte urÄit hostitele databáze", + "database-import/creating": "Vytváření projektu…", + "database-import/checking": "Kontrola dotazu…", + "database-import/preparing": "Příprava výsledků…", + "database-import/title": "Databázové servery", + "database-import/importer-name": "Databáze" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-en.json b/OpenRefine/extensions/database/module/langs/translation-en.json new file mode 100644 index 000000000..d72ffb805 --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-en.json @@ -0,0 +1,66 @@ +{ + "database-import/importer-name": "Database", + "database-import/title": "Database Servers", + "database-import/preparing": "Preparing result …", + "database-import/checking": "Validating query …", + "database-import/creating": "Creating project …", + "database-source/alert-host": "You must specify a database host", + "database-source/alert-port": "You must specify a database port", + "database-source/alert-user": "You must specify a database user", + "database-source/alert-password": "You must specify a database password", + "database-source/alert-connection-name": "You must specify a connection name", + "database-source/alert-initial-database": "You must specify an initial database", + "database-source/alert-query": "You must specify a valid query", + "database-source/alert-invalid-query-keyword": "Query cannot contain data manipulation keyword:", + "database-source/alert-invalid-query-select": "Query must start with SELECT Keyword", + "database-source/form-validation-failure": "New connection form invalid!", + "database-source/alert-connection-edit": "Connection edited", + "database-source/connectionNameLabel": "Name:", + "database-source/databaseTypeLabel": "Type:", + "database-source/databaseHostLabel": "Host:", + "database-source/databasePortLabel": "Port:", + "database-source/databaseUserLabel": "User:", + "database-source/databasePasswordLabel": "Password:", + "database-source/databaseNameLabel": "Database name:", + "database-source/databaseFileNameLabel": "Database file:", + "database-source/databaseSchemaLabel": "Schema:", + "database-source/connectionNamePlaceholder": "Enter a new Connection Name", + "database-source/databaseHostPlaceholder": "Enter the database server domain or IP", + "database-source/databasePortPlaceholder": "Enter the database port e.g. 3306", + "database-source/databaseUserPlaceholder": "Enter the database user", + "database-source/databasePasswordPlaceholder": "Enter the database password", + "database-source/databaseNamePlaceholder": "Enter the name of the database", + "database-source/databaseFileNamePlaceholder": "Enter the full path to the database file", + "database-source/databaseSchemaPlaceholder": "Enter the initial schema of the database", + "database-source/connectionNameDefaultValue": "New_Connection_Name", + "database-source/databaseTestButton": "Test", + "database-source/databaseSaveButton": "Save", + "database-source/databaseConnectButton": "Connect", + "database-source/newConnectionButtonDiv": "New connection", + "database-source/new-connection-legend":"New Connection Editor", + "database-source/savedConnectionSpan": "Saved connections", + "database-parsing/start-over": "« Start over", + "database-parsing/conf-pars": "Configure parsing options", + "database-parsing/proj-name": "Project name", + "database-parsing/create-proj": "Create Project »", + "database-parsing/updating-preview": "Updating preview …", + "database-parsing/worksheet": "Worksheets", + "database-parsing/option": "Options", + "database-parsing/preview-button": "Update preview", + "database-parsing/disable-auto-preview": "Disable auto preview", + "database-parsing/ignore-first": "Ignore first", + "database-parsing/ignore": "line(s) at beginning of file", + "database-parsing/parse-next": "Parse next", + "database-parsing/parse": "line(s) as column headers", + "database-parsing/discard-next": "Discard initial", + "database-parsing/discard": "row(s) of data", + "database-parsing/limit-next": "Load at most", + "database-parsing/limit": "row(s) of data", + "database-parsing/store-row": "Store blank rows", + "database-parsing/store-cell": "Store blank cells as nulls", + "database-source/alert-conn-name-invalid-character": "Connection Name Input Error: Illegal Character in Input. Only [a-zA-Z0-9._-] Allowed", + "database-source/alert-db-host-invalid-character": "Database Host Error: Illegal Character in Input. Only Alphanumeric characters allowed", + "database-source/alert-db-user-invalid-character": "Database User Error: Illegal Character in Input. Only Alphanumeric characters allowed", + "database-source/alert-db-port-invalid-character": "Database Port Error: Illegal Character in Input. Only Numeric values allowed." + +} diff --git a/OpenRefine/extensions/database/module/langs/translation-en_GB.json b/OpenRefine/extensions/database/module/langs/translation-en_GB.json new file mode 100644 index 000000000..bd0cfebbb --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-en_GB.json @@ -0,0 +1,53 @@ +{ + "database-source/alert-db-port-invalid-character": "Database Port Error: Illegal Character in Input. Only Numeric values allowed.", + "database-source/alert-db-user-invalid-character": "Database User Error: Illegal Character in Input. Only Alphanumeric characters allowed", + "database-source/alert-db-host-invalid-character": "Database Host Error: Illegal Character in Input. Only Alphanumeric characters allowed", + "database-source/alert-conn-name-invalid-character": "Connection Name Input Error: Illegal Character in Input. Only [a-zA-Z0-9._-] Allowed", + "database-parsing/store-cell": "Store blank cells as nulls", + "database-parsing/store-row": "Store blank rows", + "database-parsing/limit": "row(s) of data", + "database-parsing/limit-next": "Load at most", + "database-parsing/discard": "row(s) of data", + "database-parsing/discard-next": "Discard initial", + "database-parsing/parse": "line(s) as column headers", + "database-parsing/parse-next": "Parse next", + "database-parsing/ignore": "line(s) at beginning of file", + "database-parsing/ignore-first": "Ignore first", + "database-parsing/preview-button": "Update preview", + "database-parsing/option": "Options", + "database-parsing/worksheet": "Worksheets", + "database-parsing/updating-preview": "Updating preview …", + "database-parsing/create-proj": "Create Project »", + "database-parsing/proj-name": "Project name", + "database-parsing/conf-pars": "Configure parsing options", + "database-parsing/start-over": "« Start over", + "database-source/savedConnectionSpan": "Saved connections", + "database-source/newConnectionButtonDiv": "New connection", + "database-source/databaseConnectButton": "Connect", + "database-source/databaseSaveButton": "Save", + "database-source/databaseTestButton": "Test", + "database-source/databaseSchemaLabel": "Schema:", + "database-source/databaseNameLabel": "Database:", + "database-source/databaseFileNameLabel": "Database file:", + "database-source/databasePasswordLabel": "Password:", + "database-source/databaseUserLabel": "User:", + "database-source/databasePortLabel": "Port:", + "database-source/databaseHostLabel": "Host:", + "database-source/databaseTypeLabel": "Type:", + "database-source/connectionNameLabel": "Name:", + "database-source/alert-connection-edit": "Connection edited", + "database-source/form-validation-failure": "New connection form invalid!", + "database-source/alert-invalid-query-select": "Query must start with SELECT Keyword", + "database-source/alert-invalid-query-keyword": "Query cannot contain data manipulation keyword:", + "database-source/alert-connection-name": "You must specify a connection name", + "database-source/alert-query": "You must specify a valid query", + "database-source/alert-initial-database": "You must specify an initial database", + "database-source/alert-password": "You must specify a database password", + "database-source/alert-user": "You must specify a database user", + "database-source/alert-port": "You must specify a database port", + "database-source/alert-host": "You must specify a database host", + "database-import/creating": "Creating project …", + "database-import/checking": "Validating query …", + "database-import/preparing": "Preparing result …", + "database-import/title": "Database Servers" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-eu.json b/OpenRefine/extensions/database/module/langs/translation-eu.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-eu.json @@ -0,0 +1 @@ +{} diff --git a/OpenRefine/extensions/database/module/langs/translation-fr.json b/OpenRefine/extensions/database/module/langs/translation-fr.json new file mode 100644 index 000000000..e64f8eb1e --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-fr.json @@ -0,0 +1,65 @@ +{ + "database-import/importer-name": "Base de données", + "database-import/title": "Serveurs de base de données", + "database-import/preparing": "Préparation du résultat…", + "database-import/checking": "Validation de la requête…", + "database-import/creating": "Création du projet…", + "database-source/alert-host": "Vous devez spécifier un hôte de base de données", + "database-source/alert-port": "Vous devez spécifier un port de base de données", + "database-source/alert-user": "Vous devez spécifier un utilisateur de base de données", + "database-source/alert-password": "Vous devez spécifier un mot de passe de base de données", + "database-source/alert-connection-name": "Vous devez spécifier un nom de connexion", + "database-source/alert-initial-database": "Vous devez spécifier une base de données initiale", + "database-source/alert-query": "Vous devez spécifier une requête valide", + "database-source/alert-invalid-query-keyword": "La requête ne peut pas contenir ce mot clé destiné à manipuler la base de données :", + "database-source/alert-invalid-query-select": "La requête doit débuter par le mot-clé SELECT", + "database-source/form-validation-failure": "Le nouveau formulaire de connexion est invalide !", + "database-source/alert-connection-edit": "La connexion a été éditée avec succès", + "database-source/connectionNameLabel": "Nom :", + "database-source/databaseTypeLabel": "Type :", + "database-source/databaseHostLabel": "Hôte :", + "database-source/databasePortLabel": "Port :", + "database-source/databaseUserLabel": "Utilisateur :", + "database-source/databasePasswordLabel": "Mot de passe :", + "database-source/databaseNameLabel": "Base de données :", + "database-source/databaseFileNameLabel": "Fichier de données :", + "database-source/databaseSchemaLabel": "Schéma :", + "database-source/connectionNamePlaceholder": "Entrez le nom de la connexion", + "database-source/databaseHostPlaceholder": "Entrez l’adresse de l’hôte de la base de données", + "database-source/databasePortPlaceholder": "Entrez le port de la base de données par exemple 3306", + "database-source/databaseUserPlaceholder": "Entrez l’utilisateur de la base de données", + "database-source/databasePasswordPlaceholder": "Entrez le mot de passe d’utilisateur", + "database-source/databaseNamePlaceholder": "Entrez le nom de la base de données", + "database-source/databaseFileNamePlaceholder": "Entrez le chemin du fichier base de données", + "database-source/databaseSchemaPlaceholder": "Entrez le schéma initial de la base de données", + "database-source/connectionNameDefaultValue": "Nom_nouvelle_connexion", + "database-source/databaseTestButton": "Test", + "database-source/databaseSaveButton": "Enregistrer", + "database-source/databaseConnectButton": "Connexion", + "database-source/newConnectionButtonDiv": "Nouvelle connexion", + "database-source/new-connection-legend": "Éditeur de nouvelle connexion", + "database-source/savedConnectionSpan": "Connexions enregistrées", + "database-parsing/start-over": "« Recommencer", + "database-parsing/conf-pars": "Configurer les options d'analyse syntaxique (parsing)", + "database-parsing/proj-name": "Nom du projet", + "database-parsing/create-proj": "Créer un projet »", + "database-parsing/updating-preview": "Mise à jour de l'aperçu…", + "database-parsing/worksheet": "Feuilles de calcul", + "database-parsing/option": "Options", + "database-parsing/preview-button": "Mise Ã  jour de l'aperçu", + "database-parsing/ignore-first": "Ignorer la/les", + "database-parsing/ignore": "première(s) ligne(s) au début du fichier", + "database-parsing/parse-next": "Analyser (parse) la/les", + "database-parsing/parse": "ligne(s) suivante(s) comme des entêtes de colonnes", + "database-parsing/discard-next": "Omettre la/les", + "database-parsing/discard": "première(s) ligne(s) de données", + "database-parsing/limit-next": "Charger au plus", + "database-parsing/limit": "ligne(s) de données", + "database-parsing/store-row": "Stocker les lignes vides", + "database-parsing/store-cell": "Enregistrer les cellules vides comme des valeurs nulles", + "database-source/alert-db-port-invalid-character": "Erreur de port de base de données : caractère illégal en entrée. Seules les valeurs numériques sont autorisées.", + "database-source/alert-db-user-invalid-character": "Erreur de l'utilisateur de la base de données : caractère illégal en entrée. Seuls les caractères alphanumériques sont autorisés", + "database-source/alert-db-host-invalid-character": "Erreur de l'hôte de la base de données : caractère non autorisé en entrée. Seuls les caractères alphanumériques sont autorisés", + "database-source/alert-conn-name-invalid-character": "Erreur de saisie du nom de connexion : caractère non autorisé en entrée. Uniquement [a-zA-Z0-9 ._-] autorisé", + "database-parsing/disable-auto-preview": "Désactiver l'aperçu automatique" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-he.json b/OpenRefine/extensions/database/module/langs/translation-he.json new file mode 100644 index 000000000..76f5ff07f --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-he.json @@ -0,0 +1,65 @@ +{ + "database-parsing/limit": "שורות × ×ª×•× ×™× ×œ×›×œ היותר", + "database-parsing/limit-next": "לטעון", + "database-parsing/discard": "שורות ×”× ×ª×•× ×™× ×”×¨×שונות", + "database-parsing/discard-next": "התעלמות מ־", + "database-parsing/parse": "השורות הב×ות ככותרות העמודות", + "database-parsing/parse-next": "לעבד ×ת", + "database-parsing/ignore": "השורות הר×שונות בתחילת הקובץ", + "database-parsing/ignore-first": "התעלמות מ־", + "database-source/alert-db-port-invalid-character": "שגי×ת פתחת מסד נתוני×: תו שגוי בקלט. מותר רק ספרות.", + "database-source/alert-db-user-invalid-character": "שגי×ת משתמש מסד נתוני×: תו שגוי בקלט. מותר רק ×ª×•×•×™× ×לפ×× ×•×ž×¨×™×™× ×œ×˜×™× ×™×™×", + "database-source/alert-db-host-invalid-character": "שגי×ת מ×רח מסד נתוני×: תו שגוי בקלט. מותר רק ×ª×•×•×™× ×לפ×× ×•×ž×¨×™×™× ×œ×˜×™× ×™×™×", + "database-source/alert-conn-name-invalid-character": "שגי×ת קלט ×©× ×—×™×‘×•×¨: תו שגוי בקלט. מותר רק [a-zA-Z0-9._-‎]", + "database-parsing/store-cell": "ל×חסן ת××™× ×¨×™×§×™× ×›Ö¾null (ריק)", + "database-parsing/store-row": "ל×חסן שורות ריקות", + "database-parsing/preview-button": "עדכון תצוגה מקדימה", + "database-parsing/option": "×פשרויות", + "database-parsing/worksheet": "גיליונות עבודה", + "database-parsing/updating-preview": "התצוגה המקדימה מעודכנת…", + "database-parsing/create-proj": "יצירת ×ž×™×–× «", + "database-parsing/proj-name": "×©× ×”×ž×™×–×", + "database-parsing/conf-pars": "הגדרת ×פשרויות פענוח", + "database-parsing/start-over": "» להתחיל מחדש", + "database-source/savedConnectionSpan": "×—×™×‘×•×¨×™× ×©× ×©×ž×¨×•", + "database-source/new-connection-legend": "עורך ×—×™×‘×•×¨×™× ×—×“×©×™×", + "database-source/newConnectionButtonDiv": "חיבור חדש", + "database-source/databaseConnectButton": "התחברות", + "database-source/databaseSaveButton": "שמירה", + "database-source/databaseTestButton": "בדיקה", + "database-source/connectionNameDefaultValue": "ש×_חיבור_חדש", + "database-source/databaseSchemaPlaceholder": "× × ×œ×ž×œ× ×ת הסכמה הר×שונית של מסד הנתוני×", + "database-source/databaseFileNamePlaceholder": "× × ×œ×ž×œ× ×ת הנתיב ×”×ž×œ× ×œ×§×•×‘×¥ מסד הנתוני×", + "database-source/databaseNamePlaceholder": "× × ×œ×ž×œ× ×ת ×©× ×ž×¡×“ הנתוני×", + "database-source/databasePasswordPlaceholder": "× × ×œ×ž×œ× ×ת ססמת מסד הנתוני×", + "database-source/databaseUserPlaceholder": "× × ×œ×ž×œ× ×ת משתמש מסד הנתוני×", + "database-source/databasePortPlaceholder": "× × ×œ×ž×œ× ×ת פתחת מסד הנתוני×, למשל: 3306", + "database-source/databaseHostPlaceholder": "× × ×œ×ž×œ× ×ת ×”×©× ×ו ×”Ö¾IP של מסד הנתוני×", + "database-source/connectionNamePlaceholder": "× × ×œ×ž×œ× ×©× ×—×“×© לחיבור", + "database-source/databaseSchemaLabel": "סכמה:", + "database-source/databaseFileNameLabel": "קובץ מסד נתוני×:", + "database-source/databaseNameLabel": "×©× ×ž×¡×“ הנתוני×:", + "database-source/databasePasswordLabel": "ססמה:", + "database-source/databaseUserLabel": "משתמש:", + "database-source/databasePortLabel": "פתחה:", + "database-source/databaseHostLabel": "מ×רח:", + "database-source/databaseTypeLabel": "סוג:", + "database-source/connectionNameLabel": "ש×:", + "database-source/alert-connection-edit": "החיבור נערך", + "database-source/form-validation-failure": "טופס החיבור החדש שגוי!", + "database-source/alert-invalid-query-select": "ש×ילתה חייבת להתחיל במילת המפתח SELECT (בחירה)", + "database-source/alert-invalid-query-keyword": "הש×ילתה ×œ× ×™×›×•×œ×” להכיל מילת מפתח שמשנה נתוני×:", + "database-source/alert-query": "עליך לציין ש×ילתה תקפה", + "database-source/alert-initial-database": "עליך לציין מסד × ×ª×•× ×™× ×¨×שוני", + "database-source/alert-connection-name": "עליך לציין ×©× ×œ×—×™×‘×•×¨", + "database-source/alert-password": "עליך לציין ססמה למסד הנתוני×", + "database-source/alert-user": "עליך לציין משתמש למסד הנתוני×", + "database-source/alert-port": "עליך לציין פתחה למסד הנתוני×", + "database-source/alert-host": "עליך לציין מ×רח למסד הנתוני×", + "database-import/creating": "×”×ž×™×–× × ×•×¦×¨â€¦", + "database-import/checking": "הש×ילתה מתוקפת…", + "database-import/preparing": "התוצ×ות בהכנות…", + "database-import/title": "שרתי מסדי נתוני×", + "database-import/importer-name": "מסד נתוני×", + "database-parsing/disable-auto-preview": "השבתת תצוגה מקדימה ×וטומטית" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-id.json b/OpenRefine/extensions/database/module/langs/translation-id.json new file mode 100644 index 000000000..e77b35231 --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-id.json @@ -0,0 +1,64 @@ +{ + "database-source/alert-db-port-invalid-character": "Error Port Basis Data: Karakter Ilegal pada input. Hanya boleh nilai numerik.", + "database-source/alert-db-user-invalid-character": "Error Pengguna Basis Data: Karakter Ilegal pada input. Hanya boleh karakter alfanumerik", + "database-source/alert-db-host-invalid-character": "Error Host Basis Data: Karakter Ilegal pada input. Hanya boleh karakter alfanumerik", + "database-source/alert-conn-name-invalid-character": "Error Masukkan Nama Koneksi: Karakter Ilegal pada input. Hanya Boleh [a-zA-Z0-9._-]", + "database-parsing/store-cell": "Simpan cell kosong sebagai null", + "database-parsing/store-row": "Simpan baris kosong", + "database-parsing/limit": "baris data", + "database-parsing/limit-next": "Muat paling banyak", + "database-parsing/discard": "baris data", + "database-parsing/discard-next": "Buang awalan", + "database-parsing/parse": "baris sebagai header kolom", + "database-parsing/parse-next": "Uraikan berikutnya", + "database-parsing/ignore": "baris di awal berkas", + "database-parsing/ignore-first": "Abaikan dahulu", + "database-parsing/preview-button": "Pratinjau Pembaruan", + "database-parsing/option": "Pilihan", + "database-parsing/worksheet": "Lembar kerja", + "database-parsing/updating-preview": "Pratinjau pembaruan …", + "database-parsing/create-proj": "Buat Proyek»", + "database-parsing/proj-name": "Nama proyek", + "database-parsing/conf-pars": "Mengkonfigurasi pilihan parsing", + "database-parsing/start-over": "Mulai lagi", + "database-source/savedConnectionSpan": "Koneksi tersimpan", + "database-source/new-connection-legend": "Editor Koneksi Baru", + "database-source/newConnectionButtonDiv": "Koneksi baru", + "database-source/databaseConnectButton": "Hubungkan", + "database-source/databaseSaveButton": "Simpan", + "database-source/databaseTestButton": "Tes", + "database-source/connectionNameDefaultValue": "Nama_Konseksi_Baru", + "database-source/databaseSchemaPlaceholder": "Masukkan skema awal basis data", + "database-source/databaseFileNamePlaceholder": "Masukkan path lengkap berkas basis data", + "database-source/databaseNamePlaceholder": "Masukkan nama basis data", + "database-source/databasePasswordPlaceholder": "Masukkan password basis data", + "database-source/databaseUserPlaceholder": "Masukkan pengguna basis data", + "database-source/databasePortPlaceholder": "Masukkan port basis data, misal: 3306", + "database-source/databaseHostPlaceholder": "Masukkan domain server basis data atau IP", + "database-source/connectionNamePlaceholder": "Masukkan sebuah Nama Koneksi baru", + "database-source/databaseSchemaLabel": "Skema:", + "database-source/databaseFileNameLabel": "Berkas basis data:", + "database-source/databaseNameLabel": "Nama basis data:", + "database-source/databasePasswordLabel": "Password:", + "database-source/databaseUserLabel": "Pengguna:", + "database-source/databasePortLabel": "Port:", + "database-source/databaseHostLabel": "Host:", + "database-source/databaseTypeLabel": "Tipe:", + "database-source/connectionNameLabel": "Nama:", + "database-source/alert-connection-edit": "Koneksi diubah", + "database-source/form-validation-failure": "Form koneksi baru tidak valid!", + "database-source/alert-invalid-query-select": "Kueri harus dimulai dengan kata kunci SELECT", + "database-source/alert-invalid-query-keyword": "Kueri tidak bisa mengandung kata kunci manipulasi data:", + "database-source/alert-query": "Anda harus menentukan sebuah kueri yang valid", + "database-source/alert-initial-database": "Anda harus menentukan basis data awal", + "database-source/alert-connection-name": "Anda harus membuat nama koneksi", + "database-source/alert-password": "Anda harus menetukan password basis data", + "database-source/alert-user": "Anda harus menentukan pengguna basis data", + "database-source/alert-port": "Anda harus menentukan sebuah port basis data", + "database-source/alert-host": "Anda harus menentukan sebuah host basis data", + "database-import/preparing": "Menyiapkan hasil …", + "database-import/creating": "Membuat proyek …", + "database-import/checking": "Memvalidasi kueri …", + "database-import/title": "Server Basis Data", + "database-import/importer-name": "Basis Data" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-it.json b/OpenRefine/extensions/database/module/langs/translation-it.json new file mode 100644 index 000000000..f327b98de --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-it.json @@ -0,0 +1,64 @@ +{ + "database-import/title": "Server del database", + "database-import/preparing": "Risultato in preparazione…", + "database-import/checking": "Validazione query…", + "database-import/creating": "Creazione progetto…", + "database-source/alert-host": "È necessario specificare un host per il database", + "database-source/alert-port": "È necessario specificare una porta di connessione al database", + "database-source/alert-user": "È necessario specificare un utente per la connessione al database", + "database-source/alert-password": "È necessario specificare una password per la connessione al database", + "database-source/alert-connection-name": "È necessario impostare un nome alla connessione", + "database-source/alert-initial-database": "È necessario specificare un database iniziale", + "database-source/alert-query": "È necessario impostare una query valida", + "database-source/alert-invalid-query-keyword": "La query non può contenere keyword di manipolazione dati:", + "database-source/alert-invalid-query-select": "La query deve iniziare con la keyword SELECT", + "database-source/alert-connection-edit": "Connessione modificata", + "database-source/connectionNameLabel": "Nome:", + "database-source/databaseTypeLabel": "Tipo:", + "database-source/databaseHostLabel": "Host:", + "database-source/databasePortLabel": "Porta:", + "database-source/databaseUserLabel": "Utente:", + "database-source/databasePasswordLabel": "Password:", + "database-source/databaseNameLabel": "Database:", + "database-source/databaseFileNameLabel": "Database file:", + "database-source/databaseSchemaLabel": "Schema:", + "database-source/databaseTestButton": "Test", + "database-source/databaseSaveButton": "Salva", + "database-source/databaseConnectButton": "Connetti", + "database-source/newConnectionButtonDiv": "Nuova connessione", + "database-source/savedConnectionSpan": "Connessioni salvate", + "database-parsing/start-over": "« Riparti da capo", + "database-parsing/conf-pars": "Configura impostazioni di parsing", + "database-parsing/proj-name": "Nome progetto", + "database-parsing/create-proj": "Crea progetto »", + "database-parsing/updating-preview": "Aggiornamento anteprima…", + "database-parsing/worksheet": "Fogli di lavoro", + "database-parsing/option": "Opzioni", + "database-parsing/preview-button": "Aggiorna anteprima", + "database-parsing/ignore-first": "Ignora le prime", + "database-parsing/ignore": "righe dall'inizio del file", + "database-parsing/parse-next": "Usa le successive", + "database-parsing/parse": "linee come nomi delle colonne", + "database-parsing/discard-next": "Scarta le prime", + "database-parsing/discard": "righe di dati", + "database-parsing/limit-next": "Carica al massimo", + "database-parsing/limit": "righe di dati", + "database-parsing/store-row": "Salva righe vuote", + "database-parsing/store-cell": "Salva celle vuote come null", + "database-source/form-validation-failure": "Nuova forma di connessione non valida!", + "database-source/alert-conn-name-invalid-character": "Errore di input del nome di connessione: carattere non valido nell'input. Sono consentiti solo i caratteri [a-zA-z-0-9._-]", + "database-source/alert-db-host-invalid-character": "Errore dell'host del database: carattere non valido nell'input. Sono consentiti solo caratteri alfanumerici", + "database-source/alert-db-user-invalid-character": "Errore utente del database: carattere non valido nell'input. Sono consentiti solo caratteri alfanumerici", + "database-source/alert-db-port-invalid-character": "Errore porta database: carattere non valido nell'input. Sono consentiti solo valori numerici.", + "database-source/new-connection-legend": "Editor della nuova connessione", + "database-source/connectionNameDefaultValue": "Nome_nuova_connessione", + "database-source/databaseSchemaPlaceholder": "Indica lo schema iniziale del database", + "database-source/databaseFileNamePlaceholder": "Indica il percorso completo del file del database", + "database-source/databaseNamePlaceholder": "Indica il nome del database", + "database-source/databasePasswordPlaceholder": "Indica la password del database", + "database-source/databaseUserPlaceholder": "Indica il nome dell'utente del database", + "database-source/databasePortPlaceholder": "Indica il nome della porta del database, es. 3306", + "database-source/databaseHostPlaceholder": "Indica il nome del dominio o l'IP del server del database", + "database-source/connectionNamePlaceholder": "Indica il nome della nuova connessione", + "database-import/importer-name": "Database" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-jp.json b/OpenRefine/extensions/database/module/langs/translation-jp.json new file mode 100644 index 000000000..41d3e910b --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-jp.json @@ -0,0 +1,64 @@ +{ + "database-import/title": "データベースサーãƒãƒ¼", + "database-import/preparing": "準備ã—ã¦ã„ã¾ã™â€¦", + "database-import/checking": "クエリーをãƒã‚§ãƒƒã‚¯ã—ã¦ã„ã¾ã™â€¦", + "database-import/creating": "プロジェクトを作æˆä¸­â€¦", + "database-source/alert-host": "database hostを指定ã—ã¦ãã ã•ã„", + "database-source/alert-port": "database portを指定ã—ã¦ãã ã•ã„", + "database-source/alert-user": "database userを指定ã—ã¦ãã ã•ã„", + "database-source/alert-password": "database passwordを指定ã—ã¦ãã ã•ã„", + "database-source/alert-connection-name": "connection nameを指定ã—ã¦ãã ã•ã„", + "database-source/alert-initial-database": "最åˆã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’指定ã—ã¦ãã ã•ã„", + "database-source/alert-query": "有効ãªã‚¯ã‚¨ãƒªãƒ¼ã‚’設定ã—ã¦ãã ã•ã„", + "database-source/alert-invalid-query-keyword": "クエリーã«ãƒ‡ãƒ¼ã‚¿æ“作語ãŒã‚ã‚Šã¾ã™:", + "database-source/alert-invalid-query-select": "クエリーã¯SELECTã§å§‹ã¾ã‚Šã¾ã™", + "database-source/form-validation-failure": "接続フォームãŒç„¡åŠ¹ã§ã™!", + "database-source/alert-connection-edit": "接続ã®è¨­å®šã«æˆåŠŸã—ã¾ã—ãŸ", + "database-source/connectionNameLabel": "接続先:", + "database-source/databaseTypeLabel": "タイプ:", + "database-source/databaseHostLabel": "ホスト:", + "database-source/databasePortLabel": "ãƒãƒ¼ãƒˆç•ªå·:", + "database-source/databaseUserLabel": "ユーザーå:", + "database-source/databasePasswordLabel": "パスワード:", + "database-source/databaseNameLabel": "データベースå:", + "database-source/databaseFileNameLabel": "データベースファイル:", + "database-source/databaseSchemaLabel": "スキーマ :", + "database-source/databaseTestButton": "テスト", + "database-source/databaseSaveButton": "ä¿å­˜", + "database-source/databaseConnectButton": "接続", + "database-source/newConnectionButtonDiv": "æ–°ã—ã„接続", + "database-source/savedConnectionSpan": "ä¿å­˜æ¸ˆã¿æŽ¥ç¶š", + "database-parsing/start-over": "« ã‚„ã‚Šç›´ã—", + "database-parsing/conf-pars": "パースオプションã®è¨­å®š", + "database-parsing/proj-name": "プロジェクト å", + "database-parsing/create-proj": "ãƒ—ãƒ­ã‚¸ã‚§ã‚¯ãƒˆã‚’ä½œæˆ »", + "database-parsing/updating-preview": "プレビューを更新中…", + "database-parsing/worksheet": "シートå", + "database-parsing/option": "オプション", + "database-parsing/preview-button": "プレビュー æ›´æ–°", + "database-parsing/ignore-first": "最åˆã®", + "database-parsing/ignore": "行を無視", + "database-parsing/parse-next": "ãã®æ¬¡ã®", + "database-parsing/parse": "行をカラムåã¨ã—ã¦è§£é‡ˆ", + "database-parsing/discard-next": "最åˆã®", + "database-parsing/discard": "行分を破棄", + "database-parsing/limit-next": "最大ã§", + "database-parsing/limit": "行を読ã¿è¾¼ã‚€", + "database-parsing/store-row": "空白行をä¿å­˜", + "database-parsing/store-cell": "空白行をnullã¨ã—ã¦ä¿å­˜", + "database-source/alert-conn-name-invalid-character": "接続åエラー( [a-zA-Z0-9._-] ã®ã¿ä½¿ç”¨ã§ãã¾ã™ï¼‰", + "database-source/alert-db-host-invalid-character": "データベースホストåエラー(記å·ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“)", + "database-source/alert-db-user-invalid-character": "ユーザーåエラー(記å·ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“)", + "database-source/alert-db-port-invalid-character": "ãƒãƒ¼ãƒˆç•ªå·ã‚¨ãƒ©ãƒ¼ï¼ˆåŠè§’æ•°å­—ã®ã¿å¯èƒ½ï¼‰", + "database-source/connectionNameDefaultValue": "æ–°è¦æŽ¥ç¶šå", + "database-source/databaseSchemaPlaceholder": "データベースã®åˆæœŸã‚¹ã‚­ãƒ¼ãƒžã‚’入力ã—ã¦ãã ã•ã„", + "database-source/databaseFileNamePlaceholder": "データベースファイルã¸ã®ãƒ•ãƒ«ãƒ‘スを入力ã—ã¦ãã ã•ã„", + "database-source/databaseNamePlaceholder": "データベースåを入力ã—ã¦ãã ã•ã„", + "database-source/databasePasswordPlaceholder": "パスワードを入力ã—ã¦ãã ã•ã„", + "database-source/databaseUserPlaceholder": "ユーザーåを入力ã—ã¦ãã ã•ã„", + "database-source/databasePortPlaceholder": "ãƒãƒ¼ãƒˆç•ªå·ã‚’入力ã—ã¦ãã ã•ã„(例: 3306)", + "database-source/databaseHostPlaceholder": "データベースã®ãƒ‰ãƒ¡ã‚¤ãƒ³åã‹IPアドレスを入力ã—ã¦ãã ã•ã„", + "database-source/connectionNamePlaceholder": "æ–°è¦æŽ¥ç¶šåを入力ã—ã¦ãã ã•ã„", + "database-source/new-connection-legend": "æ–°è¦æŽ¥ç¶šã‚¨ãƒ‡ã‚£ã‚¿", + "database-import/importer-name": "データベース" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-ko.json b/OpenRefine/extensions/database/module/langs/translation-ko.json new file mode 100644 index 000000000..52b227021 --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-ko.json @@ -0,0 +1,49 @@ +{ + "database-import/title": "ë°ì´í„°ë² ì´ìŠ¤ 서버들", + "database-import/preparing": "결과를 준비중 …", + "database-import/checking": "쿼리를 검토중 …", + "database-import/creating": "프로ì íŠ¸ ìƒì„±ì¤‘ …", + "database-source/alert-host": "í•˜ë‚˜ì˜ ë°ì´í„°ë² ì´ìŠ¤ 호스트를 지정해야합니다", + "database-source/alert-port": "í•˜ë‚˜ì˜ ë°ì´í„°ë² ì´ìŠ¤ í¬íŠ¸ë¥¼ 지정해야합니다", + "database-source/alert-user": "ë°ì´í„°ë² ì´ìŠ¤ 사용ìžë¥¼ 지정해야합니다", + "database-source/alert-password": "ë°ì´í„°ë² ì´ìŠ¤ 비밀번호를 지정해야합니다", + "database-source/alert-connection-name": "ì ‘ì†ì´ë¦„ì„ ì§€ì •í•´ì•¼ 합니다", + "database-source/alert-initial-database": "초기 ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 지정해야 합니다", + "database-source/alert-query": "유효한 쿼리를 지정해야 합니다", + "database-source/alert-invalid-query-keyword": "쿼리는 ë°ì´í„° ì¡°ìž‘ 키워드를 í¬í•¨í•  수 없습니다:", + "database-source/alert-invalid-query-select": "쿼리는 SELECT 키워드로 시작해야 합니다", + "database-source/form-validation-failure": "ì‹ ê·œ ì ‘ì†ì´ 유효하지 않습니다!", + "database-source/alert-connection-edit": "ì ‘ì†ì´ 성공ì ìœ¼ë¡œ 편집ë˜ì—ˆìŠµë‹ˆë‹¤", + "database-source/connectionNameLabel": "ì´ë¦„:", + "database-source/databaseTypeLabel": "타입:", + "database-source/databaseHostLabel": "호스트:", + "database-source/databasePortLabel": "í¬íŠ¸:", + "database-source/databaseUserLabel": "사용ìž:", + "database-source/databasePasswordLabel": "비밀번호:", + "database-source/databaseNameLabel": "ë°ì´í„°ë² ì´ìŠ¤:", + "database-source/databaseFileNameLabel": "ë°ì´í„°ë² ì´ìŠ¤:", + "database-source/databaseSchemaLabel": "스키마:", + "database-source/databaseTestButton": "테스트", + "database-source/databaseSaveButton": "저장", + "database-source/databaseConnectButton": "ì ‘ì†", + "database-source/newConnectionButtonDiv": "ì‹ ê·œ ì ‘ì†", + "database-source/savedConnectionSpan": "ì €ìž¥ëœ ì ‘ì†", + "database-parsing/start-over": "« 다시 시작", + "database-parsing/conf-pars": "파싱 옵션 설정", + "database-parsing/proj-name": "프로ì íŠ¸ ì´ë¦„", + "database-parsing/create-proj": "프로ì íŠ¸ ìƒì„± »", + "database-parsing/updating-preview": "미리보기를 ì—…ë°ì´íŠ¸ì¤‘ …", + "database-parsing/worksheet": "워í¬ì‹œíŠ¸", + "database-parsing/option": "옵션", + "database-parsing/preview-button": "미리보기 ì—…ë°ì´íŠ¸", + "database-parsing/ignore-first": "처ìŒì„ 무시", + "database-parsing/ignore": "íŒŒì¼ ì‹œìž‘ì‹œ ë¼ì¸(들)", + "database-parsing/parse-next": "다ìŒì„ 파싱", + "database-parsing/parse": "컬럼 í—¤ë” ë¼ì¸(들)", + "database-parsing/discard-next": "ì´ˆê¸°ê°’ì„ ë²„ë¦¬ì„¸ìš”", + "database-parsing/discard": "ë°ì´í„° 줄수", + "database-parsing/limit-next": "최대한 로드하세요", + "database-parsing/limit": "ë°ì´í„° 줄수", + "database-parsing/store-row": "빈 ì¤„ì„ ì €ìž¥í•˜ì„¸ìš”", + "database-parsing/store-cell": "빈 ì…€ì„ null ë¡œ 저장하세요" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-ml.json b/OpenRefine/extensions/database/module/langs/translation-ml.json new file mode 100644 index 000000000..570ec34d8 --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-ml.json @@ -0,0 +1,15 @@ +{ + "database-source/databaseSaveButton": "സേവൠചെയàµà´¯àµà´•", + "database-source/databaseTestButton": "പരീകàµà´·à´£à´‚", + "database-source/databaseNamePlaceholder": "ഡാറàµà´±à´¾à´¬àµ‡à´¸à´¿à´¨àµà´±àµ† പേരൠചേർകàµà´•àµà´•", + "database-source/databaseNameLabel": "ഡാറàµà´±à´¾à´¬àµ‡à´¸à´¿à´¨àµà´±àµ† പേരàµ:", + "database-source/databasePasswordLabel": "രഹസàµà´¯à´µà´¾à´•àµà´•àµ:", + "database-source/databasePortLabel": "പോർടàµà´Ÿàµ:", + "database-source/databaseTypeLabel": "തരം:", + "database-source/connectionNameLabel": "പേരàµ:", + "database-import/title": "ഡാറàµà´±à´¾à´¬àµ‡à´¸àµ സെർവറàµà´•àµ¾", + "database-import/importer-name": "ഡാറàµà´±à´¾à´¬àµ‡à´¸àµ", + "database-parsing/start-over": "« ആദàµà´¯à´‚ à´®àµà´¤àµ½ à´¤àµà´Ÿà´™àµà´™àµà´•", + "database-source/databaseHostLabel": "ഹോസàµà´±àµà´±àµ:", + "database-import/preparing": "ഫലം തയàµà´¯à´¾à´±à´¾à´•àµà´•àµà´¨àµà´¨àµâ€¦" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-nb_NO.json b/OpenRefine/extensions/database/module/langs/translation-nb_NO.json new file mode 100644 index 000000000..70ebdfce4 --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-nb_NO.json @@ -0,0 +1,51 @@ +{ + "database-import/title": "Databasetjenere", + "database-import/preparing": "Forbereder resultat …", + "database-import/checking": "Validerer spørring …", + "database-import/creating": "Oppretter prosjekt …", + "database-source/alert-host": "Du mÃ¥ angi en databasevert", + "database-source/alert-port": "Du mÃ¥ angi en databaseport", + "database-source/alert-user": "Du mÃ¥ angi en databasebruker", + "database-source/alert-password": "Du mÃ¥ angi et databasepassord", + "database-source/alert-connection-name": "Du mÃ¥ angi et tilkoblingsnavn", + "database-source/alert-initial-database": "Du mÃ¥ angi en initiell database", + "database-source/alert-query": "Du mÃ¥ angi en gyldig spørring", + "database-source/alert-invalid-query-select": "Spørringen mÃ¥ starte med nøkkelordet SELECT", + "database-source/alert-connection-edit": "Tilkobling redigert", + "database-source/connectionNameLabel": "Navn:", + "database-source/databaseTypeLabel": "Type:", + "database-source/databaseHostLabel": "Vert:", + "database-source/databasePortLabel": "Port:", + "database-source/databaseUserLabel": "Bruker:", + "database-source/databasePasswordLabel": "Passord:", + "database-source/databaseNameLabel": "Database:", + "database-source/databaseFileNameLabel": "Database file:", + "database-source/databaseSchemaLabel": "Skjema:", + "database-source/databaseTestButton": "Test", + "database-source/databaseSaveButton": "Lagre", + "database-source/databaseConnectButton": "Koble til", + "database-source/newConnectionButtonDiv": "Ny tilkobling", + "database-source/savedConnectionSpan": "Lagrede tilkoblinger", + "database-parsing/start-over": "« Begynn pÃ¥ nytt", + "database-parsing/conf-pars": "Sett opp tolkningsinnstillinger", + "database-parsing/proj-name": "Prosjektnavn", + "database-parsing/create-proj": "Opprett prosjekt »", + "database-parsing/updating-preview": "Oppdaterer forhÃ¥ndsvisning …", + "database-parsing/option": "Innstillinger", + "database-parsing/preview-button": "Oppdater forhÃ¥ndsvisning", + "database-parsing/ignore-first": "Ignorer første", + "database-parsing/ignore": "linje(r) i begynnelsen av fila", + "database-parsing/parse-next": "Tolk neste", + "database-parsing/parse": "linje(r) som kolonneoverskrifter", + "database-parsing/discard-next": "Forkast de første", + "database-parsing/discard": "raden(e) med data", + "database-parsing/limit-next": "Last maksimalt", + "database-parsing/limit": "rad(er) med data", + "database-parsing/store-row": "Lagre blanke rader", + "database-parsing/store-cell": "Lagre blanke celler som null", + "database-source/alert-invalid-query-keyword": "Spørring kan ikke inneholde datamanipuleringsnøkkelord:", + "database-source/form-validation-failure": "Nytt tilkoblingsskjema ugyldig!", + "database-parsing/worksheet": "Regneark", + "database-source/databaseHostPlaceholder": "Skriv inn databasetjener eller IP", + "database-source/connectionNamePlaceholder": "Skriv inn nytt tilkoblingsnavn" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-pl.json b/OpenRefine/extensions/database/module/langs/translation-pl.json new file mode 100644 index 000000000..51e6a21a3 --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-pl.json @@ -0,0 +1,64 @@ +{ + "database-source/newConnectionButtonDiv": "Nowe poÅ‚Ä…czenie", + "database-source/databaseConnectButton": "PoÅ‚Ä…cz", + "database-source/databaseSaveButton": "Zapisz", + "database-source/databaseNameLabel": "Nazwa Bazy danych:", + "database-source/databasePasswordLabel": "HasÅ‚o:", + "database-source/databaseUserLabel": "Użytkownik:", + "database-source/databaseTypeLabel": "Typ:", + "database-source/connectionNameLabel": "Nazwa:", + "database-import/creating": "Tworzenie projektu …", + "database-import/preparing": "Przygotowanie wyników …", + "database-import/title": "Serwis bazy danych", + "database-import/importer-name": "Baza danych", + "database-parsing/store-cell": "Zachowaj puste komórki jako null", + "database-parsing/store-row": "Zachowaj puste wiersze", + "database-parsing/limit": "Wiersz(e) danych", + "database-parsing/discard": "Wiersz(e) danych", + "database-parsing/parse-next": "Analizuj nastÄ™pne", + "database-parsing/ignore": "linia(e) na poczÄ…tku pliku", + "database-parsing/preview-button": "Aktualizuj podglÄ…d", + "database-parsing/create-proj": "Utwórz projekt »", + "database-parsing/proj-name": "Nazwa projektu", + "database-parsing/conf-pars": "Skonfiguruj opcje analizowania", + "database-parsing/start-over": "« Zacznij od nowa", + "database-parsing/discard-next": "Odrzuć poczÄ…tkowe", + "database-parsing/parse": "Wiersz(e) jako nagłówki kolumn", + "database-parsing/limit-next": "ZaÅ‚aduj co najwyżej", + "database-source/alert-db-user-invalid-character": "BÅ‚Ä…d użytkownika bazy danych. Wprowadzono zabronione znaki. Dozwolone jedynie znaki alfanumeryczne", + "database-source/new-connection-legend": "Edytor nowego poÅ‚Ä…czenia", + "database-source/databaseSchemaPlaceholder": "Wprowadź poczÄ…tkowy schemat bazy danych", + "database-source/alert-db-port-invalid-character": "BÅ‚Ä…d portu bazy danych: Wprowadzono zabronione znaki. Dozwolone jedynie cyfry.", + "database-source/alert-db-host-invalid-character": "BÅ‚Ä…d hosta bazy danych: Wprowadzono zabronione znaki. Dozwolone jedynie znaki alfanumeryczne", + "database-source/alert-conn-name-invalid-character": "BÅ‚Ä…d wprowadzenia nazwy poÅ‚Ä…czenia: Wprowadzono zabronione znaki. Dozwolone tylko [a-zA-Z0-9._-]", + "database-source/alert-invalid-query-keyword": "Kwerenda nie może zawierać sÅ‚owa kluczowego manipulacji danymi:", + "database-source/alert-query": "Musisz okreÅ›lić prawidÅ‚owe zapytanie", + "database-source/alert-initial-database": "Musisz okreÅ›lić poczÄ…tkowÄ… bazÄ™ danych", + "database-source/form-validation-failure": "BÅ‚Ä™dna nowa forma poÅ‚Ä…czenia!", + "database-source/alert-host": "Musisz okreÅ›lić host bazy danych", + "database-source/alert-port": "Musisz okreÅ›lić numer portu bazy danych", + "database-source/alert-password": "Musisz okreÅ›lić hasÅ‚o bazy danych", + "database-source/alert-invalid-query-select": "Zapytanie musi zaczynać siÄ™ od sÅ‚owa SELECT", + "database-source/alert-user": "Musisz okreÅ›lić użytkownika bazy danych", + "database-source/databaseTestButton": "Testuj", + "database-source/savedConnectionSpan": "Zapisane poÅ‚Ä…czenia", + "database-parsing/updating-preview": "Aktualizacja podglÄ…du…", + "database-source/connectionNameDefaultValue": "Nowa_nazwa_poÅ‚Ä…czenia", + "database-source/databasePasswordPlaceholder": "Wprowadź hasÅ‚o bazy danych", + "database-source/databaseUserPlaceholder": "Wprowadź nazwÄ™ użytkownika bazy danych", + "database-source/databaseFileNameLabel": "Plik bazy danych:", + "database-source/alert-connection-edit": "PoÅ‚Ä…czenie zedytowane", + "database-source/databasePortPlaceholder": "Wprowadź numer portu bazy danych np. 3306", + "database-source/databaseHostPlaceholder": "Wprowadź domenÄ™ serwera bazy danych lub IP", + "database-source/connectionNamePlaceholder": "Wprowadź nowÄ… nazwÄ™ poÅ‚Ä…czenia", + "database-source/databaseSchemaLabel": "Schemat:", + "database-source/databaseFileNamePlaceholder": "Wprowadź peÅ‚nÄ… Å›cieżkÄ™ do pliku bazy danych", + "database-source/databaseNamePlaceholder": "Wprowadź nazwÄ™ bazy danych", + "database-source/databasePortLabel": "Port:", + "database-source/databaseHostLabel": "Host:", + "database-import/checking": "Walidacja zapytania …", + "database-parsing/option": "Opcje", + "database-parsing/ignore-first": "Ignoruj pierwsze", + "database-parsing/worksheet": "Arkusze", + "database-source/alert-connection-name": "Musisz okreÅ›lić nazwÄ™ poÅ‚Ä…czenia" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-pt.json b/OpenRefine/extensions/database/module/langs/translation-pt.json new file mode 100644 index 000000000..b8a115473 --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-pt.json @@ -0,0 +1,64 @@ +{ + "database-source/alert-initial-database": "Deve definir um banco de dados inicial", + "database-source/databaseTypeLabel": "Tipo:", + "database-source/alert-host": "Deve definir um host de banco de dados", + "database-source/databasePortLabel": "Porta:", + "database-source/databasePasswordLabel": "Palavra-passe:", + "database-source/databaseSchemaLabel": "Esquema:", + "database-source/databaseTestButton": "Teste", + "database-source/databaseNamePlaceholder": "Digite o nome do banco de dados", + "database-parsing/updating-preview": "Atualizando pré-visualização …", + "database-source/newConnectionButtonDiv": "Nova conexão", + "database-parsing/store-row": "Carregar linhas em branco", + "database-parsing/start-over": "« Recomeçar", + "database-parsing/discard": "linhas(s) de dados", + "database-source/databaseUserPlaceholder": "Digite o utilizador de banco de dados", + "database-parsing/limit": "linhas(s) de dados", + "database-source/alert-db-port-invalid-character": "Erro de porta de banco de dados: caractere ilegal na entrada. Apenas valores numéricos são permitidos.", + "database-parsing/proj-name": "Nome do projeto", + "database-source/alert-query": "Deve definir uma consulta válida", + "database-source/databaseConnectButton": "Conectar", + "database-parsing/limit-next": "Carregar ao menos", + "database-source/connectionNameDefaultValue": "Novo_nome_de_conexão", + "database-parsing/conf-pars": "Configurar opções de análise", + "database-source/databasePortPlaceholder": "Digite a porta do banco de dados, p.e.x 3306", + "database-source/savedConnectionSpan": "Conexões salvas", + "database-source/alert-invalid-query-select": "A consulta deve começar com a palavra-chave SELECT", + "database-source/alert-conn-name-invalid-character": "Erro de entrada de nome de conexão: caractere ilegal na entrada. Apenas [a-zA-Z0-9._-] são permitidos", + "database-import/preparing": "Preparando resultado …", + "database-source/new-connection-legend": "Novo editor de conexão", + "database-source/databaseUserLabel": "Utilizador:", + "database-source/alert-db-host-invalid-character": "Erro de host de banco de dados: caractere ilegal na entrada. Apenas caracteres alfanuméricos são permitidos", + "database-source/databaseSchemaPlaceholder": "Digite o esquema inicial do banco de dados", + "database-parsing/discard-next": "Descartar primeira(s)", + "database-source/databaseNameLabel": "Nome do banco de dados:", + "database-source/alert-port": "Deve definir uma porta de banco de dados", + "database-source/alert-invalid-query-keyword": "A consulta não pode conter palavra-chave de manipulação de dados:", + "database-source/databasePasswordPlaceholder": "Digite a palavra-passe do banco de dados", + "database-source/connectionNamePlaceholder": "Digite um novo nome de conexão", + "database-source/databaseFileNamePlaceholder": "Digite o caminho completo do ficheiro de banco de dados", + "database-parsing/preview-button": "Atualizar Pré-visualização", + "database-source/databaseFileNameLabel": "Ficheiro do banco de dados:", + "database-source/alert-connection-name": "Deve definir um nome de conexão", + "database-import/checking": "Validando consulta …", + "database-source/alert-db-user-invalid-character": "Erro de utilizador de banco de dados: caractere ilegal na entrada. Apenas caracteres alfanuméricos são permitidos", + "database-source/form-validation-failure": "Formulário de nova conexão inválido!", + "database-import/creating": "Criando projeto …", + "database-source/alert-connection-edit": "Conexão editada", + "database-source/databaseHostPlaceholder": "Digite o domínio ou IP do servidor de banco de dados", + "database-parsing/create-proj": "Criar Projeto »", + "database-source/alert-password": "Deve definir uma palavra-passe de banco de dados", + "database-parsing/ignore-first": "Ignorar primeira(s)", + "database-parsing/parse-next": "Analisar próximo", + "database-source/connectionNameLabel": "Nome:", + "database-parsing/option": "Opções", + "database-parsing/worksheet": "Planilhas", + "database-parsing/parse": "linha(s) como nomes das colunas", + "database-parsing/store-cell": "Carregar células em branco como nulas", + "database-source/alert-user": "Deve definir um utilizador de banco de dados", + "database-source/databaseHostLabel": "Host:", + "database-import/title": "Servidores de banco de dados", + "database-source/databaseSaveButton": "Gravar", + "database-parsing/ignore": "linhas(s) no começo do ficheiro", + "database-import/importer-name": "Banco de dados" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-pt_BR.json b/OpenRefine/extensions/database/module/langs/translation-pt_BR.json new file mode 100644 index 000000000..b11fd33ac --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-pt_BR.json @@ -0,0 +1,63 @@ +{ + "database-source/databaseNamePlaceholder": "Digite o nome do banco de dados", + "database-source/alert-db-port-invalid-character": "Erro de porta de banco de dados: caractere ilegal na entrada. Apenas valores numéricos são permitidos.", + "database-source/alert-db-user-invalid-character": "Erro de usuário de banco de dados: caractere ilegal na entrada. Apenas caracteres alfanuméricos são permitidos", + "database-source/alert-db-host-invalid-character": "Erro de host de banco de dados: caractere ilegal na entrada. Apenas caracteres alfanuméricos são permitidos", + "database-source/alert-conn-name-invalid-character": "Erro de entrada de nome de conexão: caractere ilegal na entrada. Apenas [a-zA-Z0-9._-] são permitidos", + "database-parsing/store-cell": "Carregar células em branco como nulas", + "database-parsing/store-row": "Carregar linhas em branco", + "database-parsing/limit": "linhas(s) de dados", + "database-parsing/limit-next": "Carregar ao menos", + "database-parsing/discard": "linhas(s) de dados", + "database-parsing/discard-next": "Descartar primeira(s)", + "database-parsing/parse": "linha(s) como nomes das colunas", + "database-parsing/parse-next": "Analisar próximo", + "database-parsing/ignore": "linhas(s) no começo do arquivo", + "database-parsing/create-proj": "Criar Projeto »", + "database-parsing/ignore-first": "Ignorar primeira(s)", + "database-parsing/preview-button": "Atualizar Pré-visualização", + "database-parsing/option": "Opções", + "database-parsing/worksheet": "Planilhas", + "database-parsing/updating-preview": "Atualizando pré-visualização …", + "database-parsing/proj-name": "Nome do projeto", + "database-parsing/conf-pars": "Configurar opções de análise", + "database-parsing/start-over": "« Recomeçar", + "database-source/savedConnectionSpan": "Conexões salvas", + "database-source/newConnectionButtonDiv": "Nova conexão", + "database-source/databaseConnectButton": "Conectar", + "database-source/databaseSaveButton": "Salvar", + "database-source/databaseTestButton": "Teste", + "database-source/connectionNameDefaultValue": "Novo_nome_de_conexão", + "database-source/databaseSchemaPlaceholder": "Digite o esquema inicial do banco de dados", + "database-source/databaseFileNamePlaceholder": "Digite o caminho completo do arquivo de banco de dados", + "database-source/databasePasswordPlaceholder": "Digite a senha do banco de dados", + "database-source/databaseUserPlaceholder": "Digite o usuário de banco de dados", + "database-source/databasePortPlaceholder": "Digite a porta do banco de dados, p.e.x 3306", + "database-source/databaseHostPlaceholder": "Digite o domínio ou IP do servidor de banco de dados", + "database-source/connectionNamePlaceholder": "Digite um novo nome de conexão", + "database-source/databaseSchemaLabel": "Esquema:", + "database-source/databaseFileNameLabel": "Arquivo do banco de dados:", + "database-source/databaseNameLabel": "Nome do banco de dados:", + "database-source/databasePasswordLabel": "Senha:", + "database-source/databaseUserLabel": "Usuário:", + "database-source/databasePortLabel": "Porta:", + "database-source/databaseHostLabel": "Host:", + "database-source/databaseTypeLabel": "Tipo:", + "database-source/connectionNameLabel": "Nome:", + "database-source/alert-connection-edit": "Conexão editada", + "database-source/form-validation-failure": "Formulário de nova conexão inválido!", + "database-source/alert-invalid-query-select": "A consulta deve começar com a palavra-chave SELECT", + "database-source/alert-invalid-query-keyword": "A consulta não pode conter palavra-chave de manipulação de dados:", + "database-source/alert-query": "Você deve definir uma consulta válida", + "database-source/alert-initial-database": "Você deve definir um banco de dados inicial", + "database-source/alert-connection-name": "Você deve definir um nome de conexão", + "database-source/alert-password": "Você deve definir uma senha de banco de dados", + "database-source/alert-port": "Você deve definir uma porta de banco de dados", + "database-source/alert-host": "Você deve definir um host de banco de dados", + "database-source/alert-user": "Você deve definir um usuário de banco de dados", + "database-import/creating": "Criando projeto …", + "database-import/checking": "Validando consulta …", + "database-import/preparing": "Preparando resultado …", + "database-import/title": "Servidores de banco de dados", + "database-source/new-connection-legend": "Novo editor de conexão" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-sv.json b/OpenRefine/extensions/database/module/langs/translation-sv.json new file mode 100644 index 000000000..7f2f3738c --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-sv.json @@ -0,0 +1,59 @@ +{ + "database-import/title": "Databasservrar", + "database-import/preparing": "Förbereder resultat …", + "database-import/checking": "Validerar frÃ¥ga …", + "database-import/creating": "Skapar projekt …", + "database-source/alert-host": "Du mÃ¥ste ange en värd för databasen", + "database-source/alert-port": "Du mÃ¥ste ange en port för databasen", + "database-source/alert-user": "Du mÃ¥ste ange en användare för databasen", + "database-source/alert-password": "Du mÃ¥ste ange ett lösenord för databasen", + "database-source/alert-connection-name": "Du mÃ¥ste ange ett anslutningsnamn", + "database-source/alert-initial-database": "Du mÃ¥ste ange en första databas", + "database-source/alert-query": "Du mÃ¥ste ange en giltig frÃ¥ga", + "database-source/alert-invalid-query-keyword": "FrÃ¥ga kan inte innehÃ¥lla nyckelord för datamanipulering:", + "database-source/alert-invalid-query-select": "FrÃ¥gan mÃ¥ste börja med nyckelordet SELECT", + "database-source/form-validation-failure": "Ny anslutningsform är ogiltig!", + "database-source/alert-connection-edit": "Anslutning redigerad", + "database-source/connectionNameLabel": "Namn:", + "database-source/databaseTypeLabel": "Typ:", + "database-source/databaseHostLabel": "Värd:", + "database-source/databasePortLabel": "Port:", + "database-source/databaseUserLabel": "Användare:", + "database-source/databasePasswordLabel": "Lösenord:", + "database-source/databaseNameLabel": "Databas:", + "database-source/databaseFileNameLabel": "Databas file:", + "database-source/databaseSchemaLabel": "Schema:", + "database-source/databaseTestButton": "Test", + "database-source/databaseSaveButton": "Spara", + "database-source/databaseConnectButton": "Anslut", + "database-source/newConnectionButtonDiv": "Ny anslutning", + "database-source/savedConnectionSpan": "Sparade anslutningar", + "database-parsing/start-over": "« Börja om", + "database-parsing/conf-pars": "Konfigurera parsningsalternativ", + "database-parsing/proj-name": "Projektnamn", + "database-parsing/create-proj": "Skapa projekt »", + "database-parsing/updating-preview": "Uppdaterar förhandsgranskning …", + "database-parsing/worksheet": "kalkylblad", + "database-parsing/option": "Inställningar", + "database-parsing/preview-button": "Uppdatera förhandsgranskning", + "database-parsing/ignore-first": "Ignorera första", + "database-parsing/ignore": "rad(er) i början av filen", + "database-parsing/parse-next": "Tolka nästa", + "database-parsing/parse": "rad(er) som kolumnrubriker", + "database-parsing/discard-next": "Släng första", + "database-parsing/discard": "rad(er) av data", + "database-parsing/limit-next": "Ladda max", + "database-parsing/limit": "rad(er) med data", + "database-parsing/store-row": "Spara tomma rader", + "database-parsing/store-cell": "Spara tomma celler som nullvärden", + "database-source/connectionNameDefaultValue": "Nytt namn pÃ¥ kopplingen", + "database-source/databaseSchemaPlaceholder": "Mata in det initiala databas-schemat", + "database-source/databaseFileNamePlaceholder": "Mata in databasfilens fullständiga adress", + "database-source/databaseNamePlaceholder": "Mata in databasens namn", + "database-source/databasePasswordPlaceholder": "Mata in databas lösenord", + "database-source/databaseUserPlaceholder": "Mata in databas användarnamn", + "database-source/databasePortPlaceholder": "Mata in databas-port, ex.vis 3306", + "database-source/databaseHostPlaceholder": "Mata in databas-domän eller IP-adress", + "database-source/connectionNamePlaceholder": "Mata in ett nytt namn pÃ¥ kopplingen", + "database-import/importer-name": "Databas" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-tr.json b/OpenRefine/extensions/database/module/langs/translation-tr.json new file mode 100644 index 000000000..f17804c1c --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-tr.json @@ -0,0 +1,65 @@ +{ + "database-import/title": "Veri Tabanı Sunucuları", + "database-import/preparing": "Sonuç hazırlanıyor…", + "database-import/checking": "Sorgu doÄŸrulanıyor…", + "database-import/creating": "Proje oluÅŸturuluyor…", + "database-source/alert-db-port-invalid-character": "Veri Tabanı BaÄŸlantı Noktası Hatası: GiriÅŸte Geçersiz Karakter. Yalnızca rakamlara izin verilir.", + "database-source/alert-db-user-invalid-character": "Veri Tabanı Kullanıcısı Hatası: GiriÅŸte Geçersiz Karakter. Yalnızca harflere ve rakamlara izin verilir", + "database-source/connectionNameDefaultValue": "Yeni_Baglanti_Adi", + "database-source/alert-db-host-invalid-character": "Veri Tabanı Sunucusu Hatası: GiriÅŸte Geçersiz Karakter. Yalnızca harflere ve rakamlara izin verilir", + "database-source/alert-conn-name-invalid-character": "BaÄŸlantı Adı GiriÅŸ Hatası: GiriÅŸte Geçersiz Karakter. Yalnızca [a-zA-Z0-9._-] Karakterlerine Ä°zin Verilir", + "database-parsing/store-cell": "BoÅŸ hücreleri boÅŸ (null) olarak kaydet", + "database-parsing/store-row": "BoÅŸ satırları kaydet", + "database-parsing/limit": "veri satırı", + "database-parsing/limit-next": "Yükle, en fazla", + "database-parsing/discard": "veri satırını", + "database-parsing/parse": "satırı, sütun baÅŸlığı olarak", + "database-parsing/ignore": "satırı, dosyanın başındaki", + "database-parsing/discard-next": "At, ilk", + "database-parsing/parse-next": "Ayrıştır, sonraki", + "database-parsing/ignore-first": "Yok say, ilk", + "database-parsing/preview-button": "Ön izlemeyi güncelle", + "database-parsing/option": "Seçenekler", + "database-parsing/worksheet": "Çalışma sayfaları", + "database-parsing/updating-preview": "Ön izleme güncelleniyor…", + "database-parsing/create-proj": "Proje OluÅŸtur »", + "database-parsing/proj-name": "Proje adı", + "database-parsing/conf-pars": "Ayrıştırma seçeneklerini yapılandır", + "database-parsing/start-over": "« BaÅŸtan baÅŸla", + "database-source/savedConnectionSpan": "Kaydedilen baÄŸlantılar", + "database-source/new-connection-legend": "Yeni BaÄŸlantı Düzenleyici", + "database-source/newConnectionButtonDiv": "Yeni baÄŸlantı", + "database-source/databaseConnectButton": "BaÄŸlan", + "database-source/databaseSaveButton": "Kaydet", + "database-source/databaseTestButton": "Test et", + "database-source/databaseSchemaPlaceholder": "Veri tabanının baÅŸlangıç ÅŸemasını girin", + "database-source/databaseFileNamePlaceholder": "Veri tabanı dosyasının tam yolunu girin", + "database-source/databaseNamePlaceholder": "Veri tabanının adını girin", + "database-source/databasePasswordPlaceholder": "Veri tabanı parolasını girin", + "database-source/databaseUserPlaceholder": "Veri tabanı kullanıcısını girin", + "database-source/databasePortPlaceholder": "Veri tabanı baÄŸlantı noktasını girin, örn. 3306", + "database-source/databaseHostPlaceholder": "Veri tabanı sunucusu etki alanını veya IP adresini girin", + "database-source/connectionNamePlaceholder": "Yeni bir baÄŸlantı adı girin", + "database-source/databaseSchemaLabel": "Åžema:", + "database-source/databaseFileNameLabel": "Veri tabanı dosyası:", + "database-source/databaseNameLabel": "Veri tabanı adı:", + "database-source/databasePasswordLabel": "Parola:", + "database-source/databaseUserLabel": "Kullanıcı:", + "database-source/databasePortLabel": "BaÄŸlantı noktası:", + "database-source/databaseHostLabel": "Sunucu:", + "database-source/databaseTypeLabel": "Tür:", + "database-source/connectionNameLabel": "Ad:", + "database-source/alert-connection-edit": "BaÄŸlantı düzenlendi", + "database-source/form-validation-failure": "Yeni baÄŸlantı formu geçersiz!", + "database-source/alert-invalid-query-select": "Sorgu, SELECT anahtar sözcüğüyle baÅŸlamalıdır", + "database-source/alert-invalid-query-keyword": "Sorgu, veri iÅŸleme anahtar sözcüğü içeremez:", + "database-source/alert-query": "Geçerli bir sorgu belirtmelisiniz", + "database-source/alert-initial-database": "Bir baÅŸlangıç veri tabanı belirtmelisiniz", + "database-source/alert-connection-name": "Bir baÄŸlantı adı belirtmelisiniz", + "database-source/alert-password": "Bir veri tabanı parolası belirtmelisiniz", + "database-source/alert-user": "Bir veri tabanı kullanıcısı belirtmelisiniz", + "database-source/alert-port": "Bir veri tabanı baÄŸlantı noktası belirtmelisiniz", + "database-source/alert-host": "Bir veri tabanı sunucusu belirtmelisiniz", + "database-import/importer-name": "Veri tabanı", + "database-parsing/disable-auto-preview": "Otomatik ön izlemeyi devre dışı bırak" +} diff --git a/OpenRefine/extensions/database/module/langs/translation-zh_Hans.json b/OpenRefine/extensions/database/module/langs/translation-zh_Hans.json new file mode 100644 index 000000000..887e2f9fe --- /dev/null +++ b/OpenRefine/extensions/database/module/langs/translation-zh_Hans.json @@ -0,0 +1,21 @@ +{ + "database-import/title": "æ•°æ®åº“æœåŠ¡å™¨", + "database-import/preparing": "正在准备返回结果…", + "database-import/checking": "正在验è¯æŸ¥è¯¢â€¦", + "database-import/creating": "创建项目…", + "database-source/alert-host": "你必须指定一个数æ®åº“主机", + "database-source/alert-port": "你必须指定一个数æ®åº“端å£", + "database-source/alert-user": "你必须指定一个数æ®åº“用户", + "database-source/alert-password": "你必须设定一个数æ®åº“密ç ", + "database-source/alert-connection-name": "你必须指定一个连接å称", + "database-source/alert-initial-database": "你必须指定一个åˆå§‹æ•°æ®åº“", + "database-source/alert-query": "你必须指定一个有效的查询", + "database-source/alert-invalid-query-keyword": "任何数æ®åº“查询语å¥å‡ä¸èƒ½å¤ŸåŒ…å«æ•°æ®æ“作关键字:", + "database-source/alert-invalid-query-select": "查询语å¥å¿…须从 SELECT 关键字开始", + "database-source/form-validation-failure": "无效的新建连接表ï¼", + "database-source/alert-connection-edit": "连接已编辑", + "database-source/connectionNameLabel": "å称:", + "database-source/databaseTypeLabel": "类型:", + "database-source/databaseHostLabel": "主机:", + "database-source/databasePortLabel": "端å£ï¼š" +} diff --git a/OpenRefine/extensions/database/module/macros.vm b/OpenRefine/extensions/database/module/macros.vm new file mode 100644 index 000000000..18a83bfce --- /dev/null +++ b/OpenRefine/extensions/database/module/macros.vm @@ -0,0 +1,14 @@ +#* + This file contains common velocity macros used in all .vt files. + For Velocity documentation, see: + + http://velocity.apache.org/engine/releases/velocity-1.5/user-guide.html +*# + +#macro( makeAList $list ) +
    + #foreach($item in $list) +
  • $item
  • + #end +
+#end \ No newline at end of file diff --git a/OpenRefine/extensions/database/module/scripts/database-extension.js b/OpenRefine/extensions/database/module/scripts/database-extension.js new file mode 100644 index 000000000..db871124e --- /dev/null +++ b/OpenRefine/extensions/database/module/scripts/database-extension.js @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +var DatabaseExtension = {}; + +DatabaseExtension.currentConnection = {}; + +DatabaseExtension.handleSavedConnectionClicked = function(menuKey, connectionName) { + var jdbcConnectionInfo = {}; + jdbcConnectionInfo.connectionName = connectionName; + + if(menuKey === "edit"){ + DatabaseExtension.handleEditConnectionClicked(connectionName); + + }else if(menuKey === "delete"){ + DatabaseExtension.handleDeleteConnectionClicked(connectionName); + + }else if(menuKey === "connect"){ + DatabaseExtension.handleConnectClicked(connectionName); + } + +}; + + +DatabaseExtension.handleConnectClicked = function(connectionName) { + + $.get( + "command/database/saved-connection" + '?' + $.param({"connectionName": connectionName}), + null, + + function(savedDatabaseConfig) { + + if(savedDatabaseConfig){ + + var savedConfig = savedDatabaseConfig.savedConnections[0]; + var databaseConfig = {}; + databaseConfig.connectionName = savedConfig.connectionName; + databaseConfig.databaseType = savedConfig.databaseType; + databaseConfig.databaseServer = savedConfig.databaseHost; + databaseConfig.databasePort = savedConfig.databasePort; + databaseConfig.databaseUser = savedConfig.databaseUser; + databaseConfig.databasePassword = savedConfig.databasePassword; + databaseConfig.initialDatabase = savedConfig.databaseName; + databaseConfig.initialSchema = savedConfig.databaseSchema; + + Refine.postCSRF( + "command/database/connect", + databaseConfig, + + function(databaseInfo) { + + if(databaseInfo){ + DatabaseExtension.currentConnection.databaseInfo; + $( "#currentConnectionNameInput" ).val(databaseConfig.connectionName); + $( "#currentDatabaseTypeInput" ).val(databaseConfig.databaseType); + $( "#currentDatabaseUserInput" ).val(databaseConfig.databaseUser); + $( "#currentDatabasePasswordInput" ).val(databaseConfig.databasePassword); + $( "#currentDatabaseHostInput" ).val(databaseConfig.databaseServer); + $( "#currentDatabasePortInput" ).val(databaseConfig.databasePort); + $( "#currentInitialDatabaseInput" ).val(databaseConfig.initialDatabase); + + var connectionParam = "Connection[" + databaseConfig.connectionName + "] :: " + + "jdbc:" + + databaseConfig.databaseType + "://" + + databaseConfig.databaseServer + ":" + + databaseConfig.databasePort + "/" + + databaseConfig.initialDatabase; + + $( "#connectionParameterSpan" ).text(connectionParam); + $( "#newConnectionDiv" ).hide(); + $( "#sqlEditorDiv" ).show(); + + }else{ + window.alert("Unable to establish connection to database"); + } + + }, + "json", + function( jqXhr, textStatus, errorThrown ){ + alert( textStatus + ':' + errorThrown ); + }); + + } + + }, + "json" + ); +}; + +DatabaseExtension.handleDeleteConnectionClicked = function(connectionName) { + $.ajax({ + url: 'command/database/saved-connection' + '?' + $.param({"connectionName": connectionName}), + type: 'DELETE', + contentType:'application/json', + data: null, + success: function(settings) { + if(settings){ + + $( "#menuListUl" ).empty(); + var items = []; + $.each(settings.savedConnections,function(index,savedConnection){ + items.push('
'); + }) + + $( "#menuListUl" ).append(items.join('')); + } + } + }).fail(function( jqXhr, textStatus, errorThrown ){ + alert( textStatus + ':' + errorThrown ); + }); +} + +DatabaseExtension.handleEditConnectionClicked = function(connectionName) { + $.get( + "command/database/saved-connection" + '?' + $.param({ "connectionName": connectionName }), + null, + function(savedDatabaseConfig) { + if (savedDatabaseConfig) { + var savedConfig = savedDatabaseConfig.savedConnections[0]; + + $( "#connectionName" ).val(savedConfig.connectionName); + $( "select#databaseTypeSelect" ).val(savedConfig.databaseType); + Refine.DatabaseSourceUI.prototype._updateDatabaseType(savedConfig.databaseType); + + $( "#databaseHost" ).val(savedConfig.databaseHost); + $( "#databasePort" ).val(savedConfig.databasePort); + $( "#databaseUser" ).val(savedConfig.databaseUser); + $( "#databasePassword" ).val(savedConfig.databasePassword); + $( "#initialDatabase" ).val(savedConfig.databaseName); + $( "#initialSchema" ).val(savedConfig.databaseSchema); + $( "#newConnectionControlDiv" ).hide(); + $( "#editConnectionControlDiv" ).show(); + $( "#newConnectionDiv" ).show(); + $('#sqlEditorDiv').hide(); + $("#connectionName").attr('readonly', 'readonly'); + } + }, + "json" + ); +} diff --git a/OpenRefine/extensions/database/module/scripts/index/database-import-controller.js b/OpenRefine/extensions/database/module/scripts/index/database-import-controller.js new file mode 100644 index 000000000..42b2779db --- /dev/null +++ b/OpenRefine/extensions/database/module/scripts/index/database-import-controller.js @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +//Internationalization init +var lang = navigator.language.split("-")[0] + || navigator.userLanguage.split("-")[0]; +var dictionary = ""; +$.ajax({ + url : "command/core/load-language?", + type : "POST", + async : false, + data : { + module : "database", + }, + success : function(data) { + dictionary = data['dictionary']; + lang = data['lang']; + } +}); +$.i18n().load(dictionary, lang); +// End internationalization + +Refine.DatabaseImportController = function(createProjectUI) { + this._createProjectUI = createProjectUI; + + this._parsingPanel = createProjectUI.addCustomPanel(); + + createProjectUI.addSourceSelectionUI({ + label: $.i18n('database-import/importer-name'), + id: "database-source", + ui: new Refine.DatabaseSourceUI(this) + }); + +}; +Refine.CreateProjectUI.controllers.push(Refine.DatabaseImportController); + +Refine.DatabaseImportController.prototype.startImportingDocument = function(queryInfo) { + var dismiss = DialogSystem.showBusy($.i18n('database-import/preparing')); + //alert(queryInfo.query); + var self = this; + + Refine.postCSRF( + "command/core/create-importing-job", + null, + function(data) { + Refine.wrapCSRF(function(token) { + $.post( + "command/core/importing-controller?" + $.param({ + "controller": "database/database-import-controller", + "subCommand": "initialize-parser-ui", + "csrf_token": token + }), + queryInfo, + + function(data2) { + dismiss(); + + if (data2.status == 'ok') { + self._queryInfo = queryInfo; + self._jobID = data.jobID; + self._options = data2.options; + + self._showParsingPanel(); + + } else { + alert(data2.message); + } + }, + "json" + ); + }); + }, + "json" + ); +}; + +Refine.DatabaseImportController.prototype.getOptions = function() { + var options = { + + }; + + var parseIntDefault = function(s, def) { + try { + var n = parseInt(s); + if (!isNaN(n)) { + return n; + } + } catch (e) { + // Ignore + } + return def; + }; + + + if (this._parsingPanelElmts.skipCheckbox[0].checked) { + options.skipDataLines = parseIntDefault(this._parsingPanelElmts.skipInput[0].value, 0); + } else { + options.skipDataLines = 0; + } + if (this._parsingPanelElmts.limitCheckbox[0].checked) { + options.limit = parseIntDefault(this._parsingPanelElmts.limitInput[0].value, -1); + } else { + options.limit = -1; + } + options.storeBlankRows = this._parsingPanelElmts.storeBlankRowsCheckbox[0].checked; + options.storeBlankCellsAsNulls = this._parsingPanelElmts.storeBlankCellsAsNullsCheckbox[0].checked; + + options.disableAutoPreview = this._parsingPanelElmts.disableAutoPreviewCheckbox[0].checked; + + return options; +}; + +Refine.DatabaseImportController.prototype._showParsingPanel = function() { + var self = this; + + this._parsingPanel.unbind().empty().html( + DOM.loadHTML("database",'scripts/index/database-parsing-panel.html')); + + this._parsingPanelElmts = DOM.bind(this._parsingPanel); + + this._parsingPanelElmts.startOverButton.html($.i18n('database-parsing/start-over')); + this._parsingPanelElmts.database_conf_pars.html($.i18n('database-parsing/conf-pars')); + this._parsingPanelElmts.database_proj_name.html($.i18n('database-parsing/proj-name')); + this._parsingPanelElmts.createProjectButton.html($.i18n('database-parsing/create-proj')); + this._parsingPanelElmts.database_options.html($.i18n('database-parsing/option')); + this._parsingPanelElmts.previewButton.html($.i18n('database-parsing/preview-button')); + this._parsingPanelElmts.database_updating.html($.i18n('database-parsing/updating-preview')); + this._parsingPanelElmts.database_discard_next.html($.i18n('database-parsing/discard-next')); + this._parsingPanelElmts.database_discard.html($.i18n('database-parsing/discard')); + this._parsingPanelElmts.database_limit_next.html($.i18n('database-parsing/limit-next')); + this._parsingPanelElmts.database_limit.html($.i18n('database-parsing/limit')); + this._parsingPanelElmts.database_store_row.html($.i18n('database-parsing/store-row')); + this._parsingPanelElmts.database_store_cell.html($.i18n('database-parsing/store-cell')); + this._parsingPanelElmts.database_disable_auto_preview.text($.i18n('database-parsing/disable-auto-preview')); + + if (this._parsingPanelResizer) { + $(window).unbind('resize', this._parsingPanelResizer); + } + + this._parsingPanelResizer = function() { + var elmts = self._parsingPanelElmts; + var width = self._parsingPanel.width(); + var height = self._parsingPanel.height(); + var headerHeight = elmts.wizardHeader.outerHeight(true); + var controlPanelHeight = 250; + + elmts.dataPanel + .css("left", "0px") + .css("top", headerHeight + "px") + .css("width", (width - DOM.getHPaddings(elmts.dataPanel)) + "px") + .css("height", (height - headerHeight - controlPanelHeight - DOM.getVPaddings(elmts.dataPanel)) + "px"); + elmts.progressPanel + .css("left", "0px") + .css("top", headerHeight + "px") + .css("width", (width - DOM.getHPaddings(elmts.progressPanel)) + "px") + .css("height", (height - headerHeight - controlPanelHeight - DOM.getVPaddings(elmts.progressPanel)) + "px"); + + elmts.controlPanel + .css("left", "0px") + .css("top", (height - controlPanelHeight) + "px") + .css("width", (width - DOM.getHPaddings(elmts.controlPanel)) + "px") + .css("height", (controlPanelHeight - DOM.getVPaddings(elmts.controlPanel)) + "px"); + }; + + $(window).resize(this._parsingPanelResizer); + this._parsingPanelResizer(); + + this._parsingPanelElmts.startOverButton.click(function() { + // explicitly cancel the import job + Refine.CreateProjectUI.cancelImportingJob(self._jobID); + + delete self._jobID; + delete self._options; + + self._createProjectUI.showSourceSelectionPanel(); + }); + + this._parsingPanelElmts.createProjectButton.click(function() { self._createProject(); }); + this._parsingPanelElmts.previewButton.click(function() { self._updatePreview(); }); + //alert("datetime::" + $.now()); + //this._parsingPanelElmts.projectNameInput[0].value = this._queryInfo.connectionName + "_" + this._queryInfo.databaseUser + "_" + $.now(); + this._parsingPanelElmts.projectNameInput[0].value = this._queryInfo.databaseServer + "_" + this._queryInfo.initialDatabase + "_" + $.now(); + + + if (this._options.limit > 0) { + this._parsingPanelElmts.limitCheckbox.prop("checked", true); + this._parsingPanelElmts.limitInput[0].value = this._options.limit.toString(); + } + if (this._options.skipDataLines > 0) { + this._parsingPanelElmts.skipCheckbox.prop("checked", true); + this._parsingPanelElmts.skipInput.value[0].value = this._options.skipDataLines.toString(); + } + if (this._options.storeBlankRows) { + this._parsingPanelElmts.storeBlankRowsCheckbox.prop("checked", true); + } + if (this._options.storeBlankCellsAsNulls) { + this._parsingPanelElmts.storeBlankCellsAsNullsCheckbox.prop("checked", true); + } + + if (this._options.disableAutoPreview) { + this._parsingPanelElmts.disableAutoPreviewCheckbox.prop('checked', true); + } + + // If disableAutoPreviewCheckbox is not checked, we will schedule an automatic update + var onChange = function() { + if (!self._parsingPanelElmts.disableAutoPreviewCheckbox[0].checked) + { + self._scheduleUpdatePreview(); + } + }; + this._parsingPanel.find("input").bind("change", onChange); + this._parsingPanel.find("select").bind("change", onChange); + + this._createProjectUI.showCustomPanel(this._parsingPanel); + this._updatePreview(); +}; + +Refine.DatabaseImportController.prototype._scheduleUpdatePreview = function() { + if (this._timerID != null) { + window.clearTimeout(this._timerID); + this._timerID = null; + } + + var self = this; + this._timerID = window.setTimeout(function() { + self._timerID = null; + self._updatePreview(); + }, 500); // 0.5 second + }; + +Refine.DatabaseImportController.prototype._updatePreview = function() { + var self = this; + // alert("query::" + this._queryInfo.query); + this._parsingPanelElmts.dataPanel.hide(); + this._parsingPanelElmts.progressPanel.show(); + this._queryInfo.options = JSON.stringify(this.getOptions()); + //alert("options:" + this._queryInfo.options); + + Refine.wrapCSRF(function(token) { + $.post( + "command/core/importing-controller?" + $.param({ + "controller": "database/database-import-controller", + "jobID": self._jobID, + "subCommand": "parse-preview", + "csrf_token": token + }), + + self._queryInfo, + + function(result) { + if (result.status == "ok") { + self._getPreviewData(function(projectData) { + self._parsingPanelElmts.progressPanel.hide(); + self._parsingPanelElmts.dataPanel.show(); + + new Refine.PreviewTable(projectData, self._parsingPanelElmts.dataPanel.unbind().empty()); + }); + } else { + + alert('Errors:\n' + (result.message) ? result.message : Refine.CreateProjectUI.composeErrorMessage(job)); + self._parsingPanelElmts.progressPanel.hide(); + + Refine.CreateProjectUI.cancelImportingJob(self._jobID); + + delete self._jobID; + delete self._options; + + self._createProjectUI.showSourceSelectionPanel(); + + + } + }, + "json" + ); + }); + }; + +Refine.DatabaseImportController.prototype._getPreviewData = function(callback, numRows) { + var self = this; + var result = {}; + + $.post( + "command/core/get-models?" + $.param({ "importingJobID" : this._jobID }), + null, + function(data) { + for (var n in data) { + if (data.hasOwnProperty(n)) { + result[n] = data[n]; + } + } + + $.post( + "command/core/get-rows?" + $.param({ + "importingJobID" : self._jobID, + "start" : 0, + "limit" : numRows || 100 // More than we parse for preview anyway + }), + null, + function(data) { + result.rowModel = data; + callback(result); + }, + "jsonp" + ); + }, + "json" + ); +}; + +Refine.DatabaseImportController.prototype._createProject = function() { + var projectName = $.trim(this._parsingPanelElmts.projectNameInput[0].value); + if (projectName.length == 0) { + window.alert("Please name the project."); + this._parsingPanelElmts.projectNameInput.focus(); + return; + } + + var self = this; + var options = this.getOptions(); + options.projectName = projectName; + + this._queryInfo.options = JSON.stringify(options); + Refine.wrapCSRF(function(token) { + $.post( + "command/core/importing-controller?" + $.param({ + "controller": "database/database-import-controller", + "jobID": self._jobID, + "subCommand": "create-project", + "csrf_token": token + }), + self._queryInfo, + function(o) { + if (o.status == 'error') { + alert(o.message); + } else { + var start = new Date(); + var timerID = window.setInterval( + function() { + self._createProjectUI.pollImportJob( + start, + self._jobID, + timerID, + function(job) { + return "projectID" in job.config; + }, + function(jobID, job) { + //alert("jobID::" + jobID + " job :" + job); + window.clearInterval(timerID); + Refine.CreateProjectUI.cancelImportingJob(jobID); + document.location = "project?project=" + job.config.projectID; + }, + function(job) { + alert(Refine.CreateProjectUI.composeErrorMessage(job)); + } + ); + }, + 1000 + ); + self._createProjectUI.showImportProgressPanel($.i18n('database-import/creating'), function() { + // stop the timed polling + window.clearInterval(timerID); + + // explicitly cancel the import job + Refine.CreateProjectUI.cancelImportingJob(jobID); + + self._createProjectUI.showSourceSelectionPanel(); + }); + } + }, + "json" + ); + }); +}; \ No newline at end of file diff --git a/OpenRefine/extensions/database/module/scripts/index/database-import-form.html b/OpenRefine/extensions/database/module/scripts/index/database-import-form.html new file mode 100644 index 000000000..cac9556e3 --- /dev/null +++ b/OpenRefine/extensions/database/module/scripts/index/database-import-form.html @@ -0,0 +1,142 @@ +
+ +
+ +
+
+
+
+
+ +
+ Saved Connections + +
+ +
+
+ +
+ +
+ + +
+
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + + +
+ + + +
+
+ + + + + +
+ + + +
+ +
+ +
+ + +
+ \ No newline at end of file diff --git a/OpenRefine/extensions/database/module/scripts/index/database-parsing-panel.html b/OpenRefine/extensions/database/module/scripts/index/database-parsing-panel.html new file mode 100644 index 000000000..b909a158e --- /dev/null +++ b/OpenRefine/extensions/database/module/scripts/index/database-parsing-panel.html @@ -0,0 +1,58 @@ +
+
+ + + + + + + + +
+
+
+
+
+ + +
+
+
+ + + + + + + + + + + + +
  +
+
+ + + + + + + + + + + + + + + + +
+
+
+
+
+
+
\ No newline at end of file diff --git a/OpenRefine/extensions/database/module/scripts/index/database-source-ui.js b/OpenRefine/extensions/database/module/scripts/index/database-source-ui.js new file mode 100644 index 000000000..f34be3f2d --- /dev/null +++ b/OpenRefine/extensions/database/module/scripts/index/database-source-ui.js @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +$(function(){ + $.contextMenu({ + selector: '.context-menu-one', + trigger: 'left', + build: function($trigger, e) { + + return { + callback: function(key, options) { + var m = "clicked: " + key; + DatabaseExtension.handleSavedConnectionClicked(key, $(this).text()); + + }, + + items: { + "edit": {name: " Edit "}, + "sep0": "", + "delete": {name: " Delete "}, + "sep1": "---------", + "connect": {name: " Connect "}, + "dummy": {name: "", icon: ""} + } + }; + } + }); +}); + +Refine.DatabaseSourceUI = function(controller) { + this._controller = controller; +}; + +Refine.DatabaseSourceUI.prototype.attachUI = function(body) { + this._body = body; + + this._body.html(DOM.loadHTML("database", "scripts/index/database-import-form.html")); + this._elmts = DOM.bind(this._body); + var self = this; + + self._defaultDatabaseHost = "localhost"; + self._defaultDatabaseType = $( "select#databaseTypeSelect" ).val(); + if (self._defaultDatabaseType == "") { self._defaultDatabaseType = "mysql"; } + + $('#database-title').text($.i18n('database-import/title')); + $('#new-connection-legend').text($.i18n('database-source/new-connection-legend')); + $('#connectionNameLabel').html($.i18n('database-source/connectionNameLabel')); + $('#databaseTypeLabel').html($.i18n('database-source/databaseTypeLabel')); + $('#databaseHostLabel').text($.i18n('database-source/databaseHostLabel')); + $('#databasePortLabel').text($.i18n('database-source/databasePortLabel')); + $('#databaseUserLabel').text($.i18n('database-source/databaseUserLabel')); + $('#databasePasswordLabel').text($.i18n('database-source/databasePasswordLabel')); + $('#databaseNameLabel').text($.i18n('database-source/databaseNameLabel')); + $('#databaseSchemaLabel').text($.i18n('database-source/databaseSchemaLabel')); + $('#databaseTestButton').text($.i18n('database-source/databaseTestButton')); + $('#databaseSaveButton').text($.i18n('database-source/databaseSaveButton')); + $('#databaseConnectButton').text($.i18n('database-source/databaseConnectButton')); + $('#newConnectionButtonDiv').text($.i18n('database-source/newConnectionButtonDiv')); + $('#savedConnectionSpan').text($.i18n('database-source/savedConnectionSpan')); + + $('input#connectionName').attr('placeholder', $.i18n('database-source/connectionNamePlaceholder')); + $('input#databaseHost').attr('placeholder', $.i18n('database-source/databaseHostPlaceholder')); + $('input#databasePort').attr('placeholder', $.i18n('database-source/databasePortPlaceholder')); + $('input#databaseUser').attr('placeholder', $.i18n('database-source/databaseUserPlaceholder')); + $('input#databasePassword').attr('placeholder', $.i18n('database-source/databasePasswordPlaceholder')); + $('input#initialDatabase').attr('placeholder', $.i18n('database-source/databaseNamePlaceholder')); + $('input#initialSchema').attr('placeholder', $.i18n('database-source/databaseSchemaPlaceholder')); + + $('input#connectionName').val($.i18n('database-source/connectionNameDefaultValue')); + + this._elmts.newConnectionButton.click(function(evt) { + self._resetDatabaseImportForm(); + $( "#newConnectionDiv" ).show(); + $( "#sqlEditorDiv" ).hide(); + // self._body.find('.newConnectionDiv').show(); + // self._body.find('.sqlEditorDiv').hide(); + }); + + this._elmts.databaseTypeSelect.change(function(event) { + var type = $( "select#databaseTypeSelect" ).val(); + + self._updateDatabaseType(type); + }); + + var defaultDatabase = $( "select#databaseTypeSelect" ).val(); + self._updateDatabaseType(defaultDatabase); + + this._elmts.testDatabaseButton.click(function(evt) { + + if(self._validateNewConnectionForm() === true){ + self._testDatabaseConnect(self._getConnectionInfo()); + } + + }); + + this._elmts.databaseConnectButton.click(function(evt) { + + if(self._validateNewConnectionForm() === true){ + self._connect(self._getConnectionInfo()); + } + + + }); + + this._elmts.saveConnectionButton.click(function(evt) { + + if(self._validateNewConnectionForm() == true){ + var connectionNameInput = $.trim(self._elmts.connectionNameInput[0].value); + if (connectionNameInput.length === 0) { + window.alert($.i18n('database-source/alert-connection-name')); + } else{ + self._saveConnection(self._getConnectionInfo()); + } + + } + + }); + + this._elmts.executeQueryButton.click(function(evt) { + var jdbcQueryInfo = {}; + jdbcQueryInfo.connectionName = $( "#currentConnectionNameInput" ).val(); + jdbcQueryInfo.databaseType = $( "#currentDatabaseTypeInput" ).val(); + jdbcQueryInfo.databaseServer = $( "#currentDatabaseHostInput" ).val(); + jdbcQueryInfo.databasePort = $( "#currentDatabasePortInput" ).val(); + jdbcQueryInfo.databaseUser = $( "#currentDatabaseUserInput" ).val(); + jdbcQueryInfo.databasePassword = $( "#currentDatabasePasswordInput" ).val(); + jdbcQueryInfo.initialDatabase = $( "#currentInitialDatabaseInput" ).val(); + jdbcQueryInfo.query = $.trim($( "#queryTextArea" ).val()); + + if(self.validateQuery(jdbcQueryInfo.query)) { + self._executeQuery(jdbcQueryInfo); + } + + + }); + + + + this._elmts.editConnectionButton.click(function(evt) { + + if(self._validateNewConnectionForm() == true){ + var connectionNameInput = $.trim(self._elmts.connectionNameInput[0].value); + if (connectionNameInput.length === 0) { + window.alert($.i18n('database-source/alert-connection-name')); + } else{ + self._editConnection(self._getConnectionInfo()); + } + + } + + }); + + this._elmts.cancelEditConnectionButton.click(function(evt) { + self._resetDatabaseImportForm(); + + }); + + //load saved connections from settings file in user home directory + self._loadSavedConnections(); + +};//end Refine.createUI + + +Refine.DatabaseSourceUI.prototype.focus = function() { +}; + +Refine.DatabaseSourceUI.prototype.validateQuery = function(query) { + //alert("query::" + query); + if(!query || query.length <= 0 ) { + window.alert($.i18n('database-source/alert-query')); + return false; + } + + var allCapsQuery = query.toUpperCase(); + + if(allCapsQuery.indexOf('DROP') > -1){ + window.alert($.i18n('database-source/alert-invalid-query-keyword') + " DROP"); + return false; + }else if(allCapsQuery.indexOf('TRUNCATE') > -1){ + window.alert($.i18n('database-source/alert-invalid-query-keyword') + " TRUNCATE"); + return false; + }else if(allCapsQuery.indexOf('DELETE') > -1){ + window.alert($.i18n('database-source/alert-invalid-query-keyword') + " DELETE"); + return false; + }else if(allCapsQuery.indexOf('ROLLBACK') > -1){ + window.alert($.i18n('database-source/alert-invalid-query-keyword') + " ROLLBACK"); + return false; + }else if(allCapsQuery.indexOf('SHUTDOWN') > -1){ + window.alert($.i18n('database-source/alert-invalid-query-keyword') + " SHUTDOWN"); + return false; + }else if(allCapsQuery.indexOf('INSERT') > -1){ + window.alert($.i18n('database-source/alert-invalid-query-keyword') + " INSERT"); + return false; + }else if(allCapsQuery.indexOf('ALTER') > -1){ + window.alert($.i18n('database-source/alert-invalid-query-keyword') + " ALTER"); + return false; + }else if(allCapsQuery.indexOf('UPDATE') > -1){ + window.alert($.i18n('database-source/alert-invalid-query-keyword') + " UPDATE"); + return false; + } + + if(!allCapsQuery.startsWith('SELECT')) { + window.alert($.i18n('database-source/alert-invalid-query-select')); + return false; + } + + return true; +}; + +Refine.DatabaseSourceUI.prototype._updateDatabaseType = function(databaseType) { + if(databaseType === "postgresql") { + $( "#databaseUser" ).val("postgres"); + $( "#databasePort" ).val("5432"); + + } else if(databaseType === "mysql") { + $( "#databaseUser" ).val("root"); + $( "#databasePort" ).val("3306"); + + } else if(databaseType === "mariadb") { + $( "#databaseUser" ).val("root"); + $( "#databasePort" ).val("3306"); + + } else if(databaseType === "sqlite") { + $( "#databaseUser" ).val("na"); + $( "#databasePort" ).val("0"); + $( "#databaseHost" ).val("na"); + + } else { + $( "#databaseUser" ).val("root"); + $( "#databasePort" ).val("3306"); + databaseType = "mysql"; + } + + $("div.pure-control-group.dbtype-options").hide(); + $("div.pure-control-group.dbtype-options.dbt-"+databaseType).show(); + + if (databaseType == "sqlite") { + $('#databaseNameLabel').text($.i18n('database-source/databaseFileNameLabel')); + $('input#initialDatabase').attr('placeholder', $.i18n('database-source/databaseFileNamePlaceholder')); + + } else { + $('#databaseNameLabel').text($.i18n('database-source/databaseNameLabel')); + $('input#initialDatabase').attr('placeholder', $.i18n('database-source/databaseNamePlaceholder')); + } +}; + +Refine.DatabaseSourceUI.prototype._editConnection = function(connectionInfo) { + //alert("database user:" + connectionInfo.databaseUser); + var self = this; + $.ajax({ + url: 'command/database/saved-connection', + type: 'PUT', + contentType:'application/x-www-form-urlencoded', + data: connectionInfo, + success: function(settings) { + if(settings){ + $( "#menuListUl" ).empty(); + var menuList = $('#menuListUl'); + var items = []; + $.each(settings.savedConnections,function(index,savedConnection){ + + var li = $('
  • ').appendTo(menuList); + var a = $('').appendTo(li); + $('').text(savedConnection.connectionName) + .appendTo(a); + $(' ').appendTo(a); + }) + + $( "#menuListUl" ).append(items.join('')); + window.alert($.i18n('database-source/alert-connection-edit')); + } + } + }).fail(function( jqXhr, textStatus, errorThrown ){ + alert( textStatus + ':' + errorThrown ); + }); + +}; + +Refine.DatabaseSourceUI.prototype._executeQuery = function(jdbcQueryInfo) { + var self = this; + //remove start line + + var dismiss = DialogSystem.showBusy($.i18n('database-import/checking')); + + Refine.postCSRF( + "command/database/test-query", + jdbcQueryInfo, + function(jdbcConnectionResult) { + + dismiss(); + self._controller.startImportingDocument(jdbcQueryInfo); + + }, + "json", + function( jqXhr, textStatus, errorThrown ){ + + dismiss(); + alert( textStatus + ':' + errorThrown ); + }); + +} + +Refine.DatabaseSourceUI.prototype._saveConnection = function(jdbcConnectionInfo) { + var self = this; + Refine.postCSRF( + "command/database/saved-connection", + jdbcConnectionInfo, + function(settings) { + if(settings){ + + self._elmts.menuListUl.empty(); + var items = []; + $.each(settings.savedConnections,function(index,savedConnection){ + + items.push('
  • ' + + '' + savedConnection.connectionName + '' + + '
  • '); + }) + + self._elmts.menuListUl.append(items.join('')); + } + + }, + "json", + function( jqXhr, textStatus, errorThrown ){ + alert( textStatus + ':' + errorThrown ); + }); + +}; + +Refine.DatabaseSourceUI.prototype._loadSavedConnections = function() { + var self = this; + $.get( + "command/database/saved-connection", + null, + function(settings) { + if(settings){ + + self._elmts.menuListUl.empty(); + + var items = []; + $.each(settings.savedConnections,function(index,savedConnection){ + + items.push('
  • ' + + '' + savedConnection.connectionName + '' + + '
  • '); + + }) + + self._elmts.menuListUl.append(items.join('')); + + } + + }, + "json" + ); + +}; + +Refine.DatabaseSourceUI.prototype._testDatabaseConnect = function(jdbcConnectionInfo) { + + var self = this; + Refine.postCSRF( + "command/database/test-connect", + jdbcConnectionInfo, + function(jdbcConnectionResult) { + if(jdbcConnectionResult && jdbcConnectionResult.connectionResult == true){ + window.alert("Test Connection Succeeded!"); + }else{ + window.alert("Unable to establish connection to database"); + } + + }, + "json", + function( jqXhr, textStatus, errorThrown ){ + alert( textStatus + ':' + errorThrown ); + }); +}; + +Refine.DatabaseSourceUI.prototype._connect = function(jdbcConnectionInfo) { + + var self = this; + Refine.postCSRF( + "command/database/connect", + jdbcConnectionInfo, + function(databaseInfo) { + + if(databaseInfo){ + $( "#currentConnectionNameInput" ).val(jdbcConnectionInfo.connectionName); + $( "#currentDatabaseTypeInput" ).val(jdbcConnectionInfo.databaseType); + $( "#currentDatabaseUserInput" ).val(jdbcConnectionInfo.databaseUser); + $( "#currentDatabasePasswordInput" ).val(jdbcConnectionInfo.databasePassword); + $( "#currentDatabaseHostInput" ).val(jdbcConnectionInfo.databaseServer); + $( "#currentDatabasePortInput" ).val(jdbcConnectionInfo.databasePort); + $( "#currentInitialDatabaseInput" ).val(jdbcConnectionInfo.initialDatabase); + + var connectionParam = "Connection :: " + + "jdbc:" + + jdbcConnectionInfo.databaseType + "://" + + jdbcConnectionInfo.databaseServer + ":" + + jdbcConnectionInfo.databasePort + "/" + + jdbcConnectionInfo.initialDatabase; + + + $( "#connectionParameterSpan" ).text(connectionParam); + $( "#newConnectionDiv" ).hide(); + $( "#sqlEditorDiv" ).show(); + + }else{ + window.alert("Unable to establish connection to database"); + return; + } + + }, + "json", + function( jqXhr, textStatus, errorThrown ){ + alert( textStatus + ':' + errorThrown ); + }); + +}; + +Refine.DatabaseSourceUI.prototype._getConnectionInfo = function() { + var self = this; + var jdbcConnectionInfo = {}; + jdbcConnectionInfo.connectionName = $.trim(self._elmts.connectionNameInput[0].value); + jdbcConnectionInfo.databaseType = $.trim(self._elmts.databaseTypeSelect[0].value); + jdbcConnectionInfo.databaseServer = $.trim(self._elmts.databaseHostInput[0].value); + jdbcConnectionInfo.databasePort = $.trim(self._elmts.databasePortInput[0].value); + jdbcConnectionInfo.databaseUser = $.trim(self._elmts.databaseUserInput[0].value); + jdbcConnectionInfo.databasePassword = $.trim(self._elmts.databasePasswordInput[0].value); + jdbcConnectionInfo.initialDatabase = $.trim(self._elmts.initialDatabaseInput[0].value); + jdbcConnectionInfo.initialSchema = $.trim(self._elmts.initialSchemaInput[0].value); + return jdbcConnectionInfo; + +} + + +Refine.DatabaseSourceUI.prototype._validateNewConnectionForm = function() { + + var self = this; + var connectionNameInput = $.trim(self._elmts.connectionNameInput[0].value); + var databaseTypeSelect = $.trim(self._elmts.databaseTypeSelect[0].value); + var databaseHostInput = $.trim(self._elmts.databaseHostInput[0].value); + var databasePortInput = $.trim(self._elmts.databasePortInput[0].value); + var databaseUserInput = $.trim(self._elmts.databaseUserInput[0].value); + var databasePasswordInput = $.trim(self._elmts.databasePasswordInput[0].value); + var initialDatabaseInput = $.trim(self._elmts.initialDatabaseInput[0].value); + var initialSchemaInput = $.trim(self._elmts.initialSchemaInput[0].value); + + var alphaNumRE = /^[a-zA-Z0-9._-]*$/; + var numRE = /^[0-9]*$/; + + var alphaNumConnNameTestResult = alphaNumRE.test(connectionNameInput); + var databaseHostTestResult = alphaNumRE.test(databaseHostInput); + var databasePortTestResult = numRE.test(databasePortInput); + var databaseUserTestResult = alphaNumRE.test(databaseUserInput); + + if(alphaNumConnNameTestResult == false){ + window.alert($.i18n('database-source/alert-conn-name-invalid-character')); + return false; + }else if (databaseHostInput.length === 0) { + window.alert($.i18n('database-source/alert-server')); + return false; + }else if(databasePortInput.length === 0){ + window.alert($.i18n('database-source/alert-port')); + return false; + }else if(databaseUserInput.length === 0){ + window.alert($.i18n('database-source/alert-user')); + return false; + }else if(initialDatabaseInput.length === 0){ + window.alert($.i18n('database-source/alert-initial-database')); + return false; + }else if(databasePortTestResult == false){ + window.alert($.i18n('database-source/alert-db-port-invalid-character')); + return false; + + } + else{ + return true; + + } + + return true; +}; + +Refine.DatabaseSourceUI.prototype._resetDatabaseImportForm = function() { + var self = this; + + $( "#databaseHost" ).val(self._defaultDatabaseHost); + + $('input#connectionName').val($.i18n('database-source/connectionNameDefaultValue')); + $( "select#databaseTypeSelect" ).val(self._defaultDatabaseType); + self._updateDatabaseType(self._defaultDatabaseType); + + $( "#databasePassword" ).val(""); + $( "#initialDatabase" ).val(""); + $( "#initialSchema" ).val(""); + + $( "#editConnectionControlDiv" ).hide(); + $( "#newConnectionControlDiv" ).show(); + $('#connectionName').removeAttr('readonly'); +}; diff --git a/OpenRefine/extensions/database/module/scripts/index/jquery.contextMenu.min.js b/OpenRefine/extensions/database/module/scripts/index/jquery.contextMenu.min.js new file mode 100644 index 000000000..bf6b6169f --- /dev/null +++ b/OpenRefine/extensions/database/module/scripts/index/jquery.contextMenu.min.js @@ -0,0 +1,2 @@ +!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e("object"==typeof exports?require("jquery"):jQuery)}(function(e){"use strict";function t(e){for(var t,n=e.split(/\s+/),a=[],o=0;t=n[o];o++)t=t.charAt(0).toUpperCase(),a.push(t);return a}function n(t){return t.id&&e('label[for="'+t.id+'"]').val()||t.name}function a(t,o,s){return s||(s=0),o.each(function(){var o,i,c=e(this),l=this,r=this.nodeName.toLowerCase();switch("label"===r&&c.find("input, textarea, select").length&&(o=c.text(),r=(l=(c=c.children().first()).get(0)).nodeName.toLowerCase()),r){case"menu":i={name:c.attr("label"),items:{}},s=a(i.items,c.children(),s);break;case"a":case"button":i={name:c.text(),disabled:!!c.attr("disabled"),callback:function(){c.get(0).click()}};break;case"menuitem":case"command":switch(c.attr("type")){case void 0:case"command":case"menuitem":i={name:c.attr("label"),disabled:!!c.attr("disabled"),icon:c.attr("icon"),callback:function(){c.get(0).click()}};break;case"checkbox":i={type:"checkbox",disabled:!!c.attr("disabled"),name:c.attr("label"),selected:!!c.attr("checked")};break;case"radio":i={type:"radio",disabled:!!c.attr("disabled"),name:c.attr("label"),radio:c.attr("radiogroup"),value:c.attr("id"),selected:!!c.attr("checked")};break;default:i=void 0}break;case"hr":i="-------";break;case"input":switch(c.attr("type")){case"text":i={type:"text",name:o||n(l),disabled:!!c.attr("disabled"),value:c.val()};break;case"checkbox":i={type:"checkbox",name:o||n(l),disabled:!!c.attr("disabled"),selected:!!c.attr("checked")};break;case"radio":i={type:"radio",name:o||n(l),disabled:!!c.attr("disabled"),radio:!!c.attr("name"),value:c.val(),selected:!!c.attr("checked")};break;default:i=void 0}break;case"select":i={type:"select",name:o||n(l),disabled:!!c.attr("disabled"),selected:c.val(),options:{}},c.children().each(function(){i.options[this.value]=e(this).text()});break;case"textarea":i={type:"textarea",name:o||n(l),disabled:!!c.attr("disabled"),value:c.val()};break;case"label":break;default:i={type:"html",html:c.clone(!0)}}i&&(t["key"+ ++s]=i)}),s}e.support.htmlMenuitem="HTMLMenuItemElement"in window,e.support.htmlCommand="HTMLCommandElement"in window,e.support.eventSelectstart="onselectstart"in document.documentElement,e.ui&&e.widget||(e.cleanData=function(t){return function(n){var a,o,s;for(s=0;null!=n[s];s++){o=n[s];try{(a=e._data(o,"events"))&&a.remove&&e(o).triggerHandler("remove")}catch(e){}}t(n)}}(e.cleanData));var o=null,s=!1,i=e(window),c=0,l={},r={},u={},d={selector:null,appendTo:null,trigger:"right",autoHide:!1,delay:200,reposition:!0,hideOnSecondTrigger:!1,selectableSubMenu:!1,classNames:{hover:"context-menu-hover",disabled:"context-menu-disabled",visible:"context-menu-visible",notSelectable:"context-menu-not-selectable",icon:"context-menu-icon",iconEdit:"context-menu-icon-edit",iconCut:"context-menu-icon-cut",iconCopy:"context-menu-icon-copy",iconPaste:"context-menu-icon-paste",iconDelete:"context-menu-icon-delete",iconAdd:"context-menu-icon-add",iconQuit:"context-menu-icon-quit",iconLoadingClass:"context-menu-icon-loading"},determinePosition:function(t){if(e.ui&&e.ui.position)t.css("display","block").position({my:"center top",at:"center bottom",of:this,offset:"0 5",collision:"fit"}).css("display","none");else{var n=this.offset();n.top+=this.outerHeight(),n.left+=this.outerWidth()/2-t.outerWidth()/2,t.css(n)}},position:function(e,t,n){var a;if(t||n){if("maintain"===t&&"maintain"===n)a=e.$menu.position();else{var o=e.$menu.offsetParent().offset();a={top:n-o.top,left:t-o.left}}var s=i.scrollTop()+i.height(),c=i.scrollLeft()+i.width(),l=e.$menu.outerHeight(),r=e.$menu.outerWidth();a.top+l>s&&(a.top-=l),a.top<0&&(a.top=0),a.left+r>c&&(a.left-=r),a.left<0&&(a.left=0),e.$menu.css(a)}else e.determinePosition.call(this,e.$menu)},positionSubmenu:function(t){if(void 0!==t)if(e.ui&&e.ui.position)t.css("display","block").position({my:"left top-5",at:"right top",of:this,collision:"flipfit fit"}).css("display","");else{var n={top:-9,left:this.outerWidth()-5};t.css(n)}},zIndex:1,animation:{duration:50,show:"slideDown",hide:"slideUp"},events:{show:e.noop,hide:e.noop,activated:e.noop},callback:null,items:{}},m={timer:null,pageX:null,pageY:null},p=function(e){for(var t=0,n=e;;)if(t=Math.max(t,parseInt(n.css("z-index"),10)||0),!(n=n.parent())||!n.length||"html body".indexOf(n.prop("nodeName").toLowerCase())>-1)break;return t},f={abortevent:function(e){e.preventDefault(),e.stopImmediatePropagation()},contextmenu:function(t){var n=e(this);if("right"===t.data.trigger&&(t.preventDefault(),t.stopImmediatePropagation()),!("right"!==t.data.trigger&&"demand"!==t.data.trigger&&t.originalEvent||!(void 0===t.mouseButton||!t.data||"left"===t.data.trigger&&0===t.mouseButton||"right"===t.data.trigger&&2===t.mouseButton)||n.hasClass("context-menu-active")||n.hasClass("context-menu-disabled"))){if(o=n,t.data.build){var a=t.data.build(o,t);if(!1===a)return;if(t.data=e.extend(!0,{},d,t.data,a||{}),!t.data.items||e.isEmptyObject(t.data.items))throw window.console&&(console.error||console.log).call(console,"No items specified to show in contextMenu"),new Error("No Items specified");t.data.$trigger=o,h.create(t.data)}var s=!1;for(var i in t.data.items)if(t.data.items.hasOwnProperty(i)){(e.isFunction(t.data.items[i].visible)?t.data.items[i].visible.call(e(t.currentTarget),i,t.data):void 0===t.data.items[i]||!t.data.items[i].visible||!0===t.data.items[i].visible)&&(s=!0)}s&&h.show.call(n,t.data,t.pageX,t.pageY)}},click:function(t){t.preventDefault(),t.stopImmediatePropagation(),e(this).trigger(e.Event("contextmenu",{data:t.data,pageX:t.pageX,pageY:t.pageY}))},mousedown:function(t){var n=e(this);o&&o.length&&!o.is(n)&&o.data("contextMenu").$menu.trigger("contextmenu:hide"),2===t.button&&(o=n.data("contextMenuActive",!0))},mouseup:function(t){var n=e(this);n.data("contextMenuActive")&&o&&o.length&&o.is(n)&&!n.hasClass("context-menu-disabled")&&(t.preventDefault(),t.stopImmediatePropagation(),o=n,n.trigger(e.Event("contextmenu",{data:t.data,pageX:t.pageX,pageY:t.pageY}))),n.removeData("contextMenuActive")},mouseenter:function(t){var n=e(this),a=e(t.relatedTarget),s=e(document);a.is(".context-menu-list")||a.closest(".context-menu-list").length||o&&o.length||(m.pageX=t.pageX,m.pageY=t.pageY,m.data=t.data,s.on("mousemove.contextMenuShow",f.mousemove),m.timer=setTimeout(function(){m.timer=null,s.off("mousemove.contextMenuShow"),o=n,n.trigger(e.Event("contextmenu",{data:m.data,pageX:m.pageX,pageY:m.pageY}))},t.data.delay))},mousemove:function(e){m.pageX=e.pageX,m.pageY=e.pageY},mouseleave:function(t){var n=e(t.relatedTarget);if(!n.is(".context-menu-list")&&!n.closest(".context-menu-list").length){try{clearTimeout(m.timer)}catch(t){}m.timer=null}},layerClick:function(t){var n,a,o=e(this).data("contextMenuRoot"),s=t.button,c=t.pageX,l=t.pageY;t.preventDefault(),setTimeout(function(){var r,u="left"===o.trigger&&0===s||"right"===o.trigger&&2===s;if(document.elementFromPoint&&o.$layer){if(o.$layer.hide(),(n=document.elementFromPoint(c-i.scrollLeft(),l-i.scrollTop())).isContentEditable){var d=document.createRange(),m=window.getSelection();d.selectNode(n),d.collapse(!0),m.removeAllRanges(),m.addRange(d)}e(n).trigger(t),o.$layer.show()}if(o.hideOnSecondTrigger&&u&&null!==o.$menu&&void 0!==o.$menu)o.$menu.trigger("contextmenu:hide");else{if(o.reposition&&u)if(document.elementFromPoint){if(o.$trigger.is(n))return void o.position.call(o.$trigger,o,c,l)}else if(a=o.$trigger.offset(),r=e(window),a.top+=r.scrollTop(),a.top<=t.pageY&&(a.left+=r.scrollLeft(),a.left<=t.pageX&&(a.bottom=a.top+o.$trigger.outerHeight(),a.bottom>=t.pageY&&(a.right=a.left+o.$trigger.outerWidth(),a.right>=t.pageX))))return void o.position.call(o.$trigger,o,c,l);n&&u&&o.$trigger.one("contextmenu:hidden",function(){e(n).contextMenu({x:c,y:l,button:s})}),null!==o&&void 0!==o&&null!==o.$menu&&void 0!==o.$menu&&o.$menu.trigger("contextmenu:hide")}},50)},keyStop:function(e,t){t.isInput||e.preventDefault(),e.stopPropagation()},key:function(e){var t={};o&&(t=o.data("contextMenu")||{}),void 0===t.zIndex&&(t.zIndex=0);var n=0,a=function(e){""!==e.style.zIndex?n=e.style.zIndex:null!==e.offsetParent&&void 0!==e.offsetParent?a(e.offsetParent):null!==e.parentElement&&void 0!==e.parentElement&&a(e.parentElement)};if(a(e.target),!(t.$menu&&parseInt(n,10)>parseInt(t.$menu.css("zIndex"),10))){switch(e.keyCode){case 9:case 38:if(f.keyStop(e,t),t.isInput){if(9===e.keyCode&&e.shiftKey)return e.preventDefault(),t.$selected&&t.$selected.find("input, textarea, select").blur(),void(null!==t.$menu&&void 0!==t.$menu&&t.$menu.trigger("prevcommand"));if(38===e.keyCode&&"checkbox"===t.$selected.find("input, textarea, select").prop("type"))return void e.preventDefault()}else if(9!==e.keyCode||e.shiftKey)return void(null!==t.$menu&&void 0!==t.$menu&&t.$menu.trigger("prevcommand"));break;case 40:if(f.keyStop(e,t),!t.isInput)return void(null!==t.$menu&&void 0!==t.$menu&&t.$menu.trigger("nextcommand"));if(9===e.keyCode)return e.preventDefault(),t.$selected&&t.$selected.find("input, textarea, select").blur(),void(null!==t.$menu&&void 0!==t.$menu&&t.$menu.trigger("nextcommand"));if(40===e.keyCode&&"checkbox"===t.$selected.find("input, textarea, select").prop("type"))return void e.preventDefault();break;case 37:if(f.keyStop(e,t),t.isInput||!t.$selected||!t.$selected.length)break;if(!t.$selected.parent().hasClass("context-menu-root")){var s=t.$selected.parent().parent();return t.$selected.trigger("contextmenu:blur"),void(t.$selected=s)}break;case 39:if(f.keyStop(e,t),t.isInput||!t.$selected||!t.$selected.length)break;var i=t.$selected.data("contextMenu")||{};if(i.$menu&&t.$selected.hasClass("context-menu-submenu"))return t.$selected=null,i.$selected=null,void i.$menu.trigger("nextcommand");break;case 35:case 36:return t.$selected&&t.$selected.find("input, textarea, select").length?void 0:((t.$selected&&t.$selected.parent()||t.$menu).children(":not(."+t.classNames.disabled+", ."+t.classNames.notSelectable+")")[36===e.keyCode?"first":"last"]().trigger("contextmenu:focus"),void e.preventDefault());case 13:if(f.keyStop(e,t),t.isInput){if(t.$selected&&!t.$selected.is("textarea, select"))return void e.preventDefault();break}return void(void 0!==t.$selected&&null!==t.$selected&&t.$selected.trigger("mouseup"));case 32:case 33:case 34:return void f.keyStop(e,t);case 27:return f.keyStop(e,t),void(null!==t.$menu&&void 0!==t.$menu&&t.$menu.trigger("contextmenu:hide"));default:var c=String.fromCharCode(e.keyCode).toUpperCase();if(t.accesskeys&&t.accesskeys[c])return void t.accesskeys[c].$node.trigger(t.accesskeys[c].$menu?"contextmenu:focus":"mouseup")}e.stopPropagation(),void 0!==t.$selected&&null!==t.$selected&&t.$selected.trigger(e)}},prevItem:function(t){t.stopPropagation();var n=e(this).data("contextMenu")||{},a=e(this).data("contextMenuRoot")||{};if(n.$selected){var o=n.$selected;(n=n.$selected.parent().data("contextMenu")||{}).$selected=o}for(var s=n.$menu.children(),i=n.$selected&&n.$selected.prev().length?n.$selected.prev():s.last(),c=i;i.hasClass(a.classNames.disabled)||i.hasClass(a.classNames.notSelectable)||i.is(":hidden");)if((i=i.prev().length?i.prev():s.last()).is(c))return;n.$selected&&f.itemMouseleave.call(n.$selected.get(0),t),f.itemMouseenter.call(i.get(0),t);var l=i.find("input, textarea, select");l.length&&l.focus()},nextItem:function(t){t.stopPropagation();var n=e(this).data("contextMenu")||{},a=e(this).data("contextMenuRoot")||{};if(n.$selected){var o=n.$selected;(n=n.$selected.parent().data("contextMenu")||{}).$selected=o}for(var s=n.$menu.children(),i=n.$selected&&n.$selected.next().length?n.$selected.next():s.first(),c=i;i.hasClass(a.classNames.disabled)||i.hasClass(a.classNames.notSelectable)||i.is(":hidden");)if((i=i.next().length?i.next():s.first()).is(c))return;n.$selected&&f.itemMouseleave.call(n.$selected.get(0),t),f.itemMouseenter.call(i.get(0),t);var l=i.find("input, textarea, select");l.length&&l.focus()},focusInput:function(){var t=e(this).closest(".context-menu-item"),n=t.data(),a=n.contextMenu,o=n.contextMenuRoot;o.$selected=a.$selected=t,o.isInput=a.isInput=!0},blurInput:function(){var t=e(this).closest(".context-menu-item").data(),n=t.contextMenu;t.contextMenuRoot.isInput=n.isInput=!1},menuMouseenter:function(){e(this).data().contextMenuRoot.hovering=!0},menuMouseleave:function(t){var n=e(this).data().contextMenuRoot;n.$layer&&n.$layer.is(t.relatedTarget)&&(n.hovering=!1)},itemMouseenter:function(t){var n=e(this),a=n.data(),o=a.contextMenu,s=a.contextMenuRoot;s.hovering=!0,t&&s.$layer&&s.$layer.is(t.relatedTarget)&&(t.preventDefault(),t.stopImmediatePropagation()),(o.$menu?o:s).$menu.children("."+s.classNames.hover).trigger("contextmenu:blur").children(".hover").trigger("contextmenu:blur"),n.hasClass(s.classNames.disabled)||n.hasClass(s.classNames.notSelectable)?o.$selected=null:n.trigger("contextmenu:focus")},itemMouseleave:function(t){var n=e(this),a=n.data(),o=a.contextMenu,s=a.contextMenuRoot;if(s!==o&&s.$layer&&s.$layer.is(t.relatedTarget))return void 0!==s.$selected&&null!==s.$selected&&s.$selected.trigger("contextmenu:blur"),t.preventDefault(),t.stopImmediatePropagation(),void(s.$selected=o.$selected=o.$node);o&&o.$menu&&o.$menu.hasClass("context-menu-visible")||n.trigger("contextmenu:blur")},itemClick:function(t){var n,a=e(this),o=a.data(),s=o.contextMenu,i=o.contextMenuRoot,c=o.contextMenuKey;if(!(!s.items[c]||a.is("."+i.classNames.disabled+", .context-menu-separator, ."+i.classNames.notSelectable)||a.is(".context-menu-submenu")&&!1===i.selectableSubMenu)){if(t.preventDefault(),t.stopImmediatePropagation(),e.isFunction(s.callbacks[c])&&Object.prototype.hasOwnProperty.call(s.callbacks,c))n=s.callbacks[c];else{if(!e.isFunction(i.callback))return;n=i.callback}!1!==n.call(i.$trigger,c,i,t)?i.$menu.trigger("contextmenu:hide"):i.$menu.parent().length&&h.update.call(i.$trigger,i)}},inputClick:function(e){e.stopImmediatePropagation()},hideMenu:function(t,n){var a=e(this).data("contextMenuRoot");h.hide.call(a.$trigger,a,n&&n.force)},focusItem:function(t){t.stopPropagation();var n=e(this),a=n.data(),o=a.contextMenu,s=a.contextMenuRoot;n.hasClass(s.classNames.disabled)||n.hasClass(s.classNames.notSelectable)||(n.addClass([s.classNames.hover,s.classNames.visible].join(" ")).parent().find(".context-menu-item").not(n).removeClass(s.classNames.visible).filter("."+s.classNames.hover).trigger("contextmenu:blur"),o.$selected=s.$selected=n,o&&o.$node&&o.$node.hasClass("context-menu-submenu")&&o.$node.addClass(s.classNames.hover),o.$node&&s.positionSubmenu.call(o.$node,o.$menu))},blurItem:function(t){t.stopPropagation();var n=e(this),a=n.data(),o=a.contextMenu,s=a.contextMenuRoot;o.autoHide&&n.removeClass(s.classNames.visible),n.removeClass(s.classNames.hover),o.$selected=null}},h={show:function(t,n,a){var s=e(this),i={};if(e("#context-menu-layer").trigger("mousedown"),t.$trigger=s,!1!==t.events.show.call(s,t)){if(h.update.call(s,t),t.position.call(s,t,n,a),t.zIndex){var c=t.zIndex;"function"==typeof t.zIndex&&(c=t.zIndex.call(s,t)),i.zIndex=p(s)+c}h.layer.call(t.$menu,t,i.zIndex),t.$menu.find("ul").css("zIndex",i.zIndex+1),t.$menu.css(i)[t.animation.show](t.animation.duration,function(){s.trigger("contextmenu:visible"),h.activated(t),t.events.activated()}),s.data("contextMenu",t).addClass("context-menu-active"),e(document).off("keydown.contextMenu").on("keydown.contextMenu",f.key),t.autoHide&&e(document).on("mousemove.contextMenuAutoHide",function(e){var n=s.offset();n.right=n.left+s.outerWidth(),n.bottom=n.top+s.outerHeight(),!t.$layer||t.hovering||e.pageX>=n.left&&e.pageX<=n.right&&e.pageY>=n.top&&e.pageY<=n.bottom||setTimeout(function(){t.hovering||null===t.$menu||void 0===t.$menu||t.$menu.trigger("contextmenu:hide")},50)})}else o=null},hide:function(t,n){var a=e(this);if(t||(t=a.data("contextMenu")||{}),n||!t.events||!1!==t.events.hide.call(a,t)){if(a.removeData("contextMenu").removeClass("context-menu-active"),t.$layer){setTimeout(function(e){return function(){e.remove()}}(t.$layer),10);try{delete t.$layer}catch(e){t.$layer=null}}o=null,t.$menu.find("."+t.classNames.hover).trigger("contextmenu:blur"),t.$selected=null,t.$menu.find("."+t.classNames.visible).removeClass(t.classNames.visible),e(document).off(".contextMenuAutoHide").off("keydown.contextMenu"),t.$menu&&t.$menu[t.animation.hide](t.animation.duration,function(){t.build&&(t.$menu.remove(),e.each(t,function(e){switch(e){case"ns":case"selector":case"build":case"trigger":return!0;default:t[e]=void 0;try{delete t[e]}catch(e){}return!0}})),setTimeout(function(){a.trigger("contextmenu:hidden")},10)})}},create:function(n,a){function o(t){var n=e("");if(t._accesskey)t._beforeAccesskey&&n.append(document.createTextNode(t._beforeAccesskey)),e("").addClass("context-menu-accesskey").text(t._accesskey).appendTo(n),t._afterAccesskey&&n.append(document.createTextNode(t._afterAccesskey));else if(t.isHtmlName){if(void 0!==t.accesskey)throw new Error("accesskeys are not compatible with HTML names and cannot be used together in the same item");n.html(t.name)}else n.text(t.name);return n}void 0===a&&(a=n),n.$menu=e('
      ').addClass(n.className||"").data({contextMenu:n,contextMenuRoot:a}),e.each(["callbacks","commands","inputs"],function(e,t){n[t]={},a[t]||(a[t]={})}),a.accesskeys||(a.accesskeys={}),e.each(n.items,function(s,i){var c=e('
    • ').addClass(i.className||""),l=null,r=null;if(c.on("click",e.noop),"string"!=typeof i&&"cm_separator"!==i.type||(i={type:"cm_seperator"}),i.$node=c.data({contextMenu:n,contextMenuRoot:a,contextMenuKey:s}),void 0!==i.accesskey)for(var d,m=t(i.accesskey),p=0;d=m[p];p++)if(!a.accesskeys[d]){a.accesskeys[d]=i;var v=i.name.match(new RegExp("^(.*?)("+d+")(.*)$","i"));v&&(i._beforeAccesskey=v[1],i._accesskey=v[2],i._afterAccesskey=v[3]);break}if(i.type&&u[i.type])u[i.type].call(c,i,n,a),e.each([n,a],function(t,a){a.commands[s]=i,!e.isFunction(i.callback)||void 0!==a.callbacks[s]&&void 0!==n.type||(a.callbacks[s]=i.callback)});else{switch("cm_seperator"===i.type?c.addClass("context-menu-separator "+a.classNames.notSelectable):"html"===i.type?c.addClass("context-menu-html "+a.classNames.notSelectable):"sub"===i.type||(i.type?(l=e("").appendTo(c),o(i).appendTo(l),c.addClass("context-menu-input"),n.hasTypes=!0,e.each([n,a],function(e,t){t.commands[s]=i,t.inputs[s]=i})):i.items&&(i.type="sub")),i.type){case"cm_seperator":break;case"text":r=e('').attr("name","context-menu-input-"+s).val(i.value||"").appendTo(l);break;case"textarea":r=e('').attr("name","context-menu-input-"+s).val(i.value||"").appendTo(l),i.height&&r.height(i.height);break;case"checkbox":r=e('').attr("name","context-menu-input-"+s).val(i.value||"").prop("checked",!!i.selected).prependTo(l);break;case"radio":r=e('').attr("name","context-menu-input-"+i.radio).val(i.value||"").prop("checked",!!i.selected).prependTo(l);break;case"select":r=e('').attr("name","context-menu-input-"+s).appendTo(l),i.options&&(e.each(i.options,function(t,n){e("").val(t).text(n).appendTo(r)}),r.val(i.selected));break;case"sub":o(i).appendTo(c),i.appendTo=i.$node,c.data("contextMenu",i).addClass("context-menu-submenu"),i.callback=null,"function"==typeof i.items.then?h.processPromises(i,a,i.items):h.create(i,a);break;case"html":e(i.html).appendTo(c);break;default:e.each([n,a],function(t,a){a.commands[s]=i,!e.isFunction(i.callback)||void 0!==a.callbacks[s]&&void 0!==n.type||(a.callbacks[s]=i.callback)}),o(i).appendTo(c)}i.type&&"sub"!==i.type&&"html"!==i.type&&"cm_seperator"!==i.type&&(r.on("focus",f.focusInput).on("blur",f.blurInput),i.events&&r.on(i.events,n)),i.icon&&(e.isFunction(i.icon)?i._icon=i.icon.call(this,this,c,s,i):"string"==typeof i.icon&&"fa-"===i.icon.substring(0,3)?i._icon=a.classNames.icon+" "+a.classNames.icon+"--fa fa "+i.icon:i._icon=a.classNames.icon+" "+a.classNames.icon+"-"+i.icon,c.addClass(i._icon))}i.$input=r,i.$label=l,c.appendTo(n.$menu),!n.hasTypes&&e.support.eventSelectstart&&c.on("selectstart.disableTextSelect",f.abortevent)}),n.$node||n.$menu.css("display","none").addClass("context-menu-root"),n.$menu.appendTo(n.appendTo||document.body)},resize:function(t,n){var a;t.css({position:"absolute",display:"block"}),t.data("width",(a=t.get(0)).getBoundingClientRect?Math.ceil(a.getBoundingClientRect().width):t.outerWidth()+1),t.css({position:"static",minWidth:"0px",maxWidth:"100000px"}),t.find("> li > ul").each(function(){h.resize(e(this),!0)}),n||t.find("ul").addBack().css({position:"",display:"",minWidth:"",maxWidth:""}).outerWidth(function(){return e(this).data("width")})},update:function(t,n){var a=this;void 0===n&&(n=t,h.resize(t.$menu)),t.$menu.children().each(function(){var o,s=e(this),i=s.data("contextMenuKey"),c=t.items[i],l=e.isFunction(c.disabled)&&c.disabled.call(a,i,n)||!0===c.disabled;if(o=e.isFunction(c.visible)?c.visible.call(a,i,n):void 0===c.visible||!0===c.visible,s[o?"show":"hide"](),s[l?"addClass":"removeClass"](n.classNames.disabled),e.isFunction(c.icon)&&(s.removeClass(c._icon),c._icon=c.icon.call(this,a,s,i,c),s.addClass(c._icon)),c.type)switch(s.find("input, select, textarea").prop("disabled",l),c.type){case"text":case"textarea":c.$input.val(c.value||"");break;case"checkbox":case"radio":c.$input.val(c.value||"").prop("checked",!!c.selected);break;case"select":c.$input.val((0===c.selected?"0":c.selected)||"")}c.$menu&&h.update.call(a,c,n)})},layer:function(t,n){var a=t.$layer=e('
      ').css({height:i.height(),width:i.width(),display:"block",position:"fixed","z-index":n,top:0,left:0,opacity:0,filter:"alpha(opacity=0)","background-color":"#000"}).data("contextMenuRoot",t).insertBefore(this).on("contextmenu",f.abortevent).on("mousedown",f.layerClick);return void 0===document.body.style.maxWidth&&a.css({position:"absolute",height:e(document).height()}),a},processPromises:function(e,t,n){function a(e,t,n){void 0===n?(n={error:{name:"No items and no error item",icon:"context-menu-icon context-menu-icon-quit"}},window.console&&(console.error||console.log).call(console,'When you reject a promise, provide an "items" object, equal to normal sub-menu items')):"string"==typeof n&&(n={error:{name:n}}),o(e,t,n)}function o(e,t,n){void 0!==t.$menu&&t.$menu.is(":visible")&&(e.$node.removeClass(t.classNames.iconLoadingClass),e.items=n,h.create(e,t,!0),h.update(e,t),t.positionSubmenu.call(e.$node,e.$menu))}e.$node.addClass(t.classNames.iconLoadingClass),n.then(function(e,t,n){void 0===n&&a(void 0),o(e,t,n)}.bind(this,e,t),a.bind(this,e,t))},activated:function(t){var n=t.$menu,a=n.offset(),o=e(window).height(),s=e(window).scrollTop(),i=n.height();i>o?n.css({height:o+"px","overflow-x":"hidden","overflow-y":"auto",top:s+"px"}):(a.tops+o)&&n.css({top:"0px"})}};e.fn.contextMenu=function(t){var n=this,a=t;if(this.length>0)if(void 0===t)this.first().trigger("contextmenu");else if(void 0!==t.x&&void 0!==t.y)this.first().trigger(e.Event("contextmenu",{pageX:t.x,pageY:t.y,mouseButton:t.button}));else if("hide"===t){var o=this.first().data("contextMenu")?this.first().data("contextMenu").$menu:null;o&&o.trigger("contextmenu:hide")}else"destroy"===t?e.contextMenu("destroy",{context:this}):e.isPlainObject(t)?(t.context=this,e.contextMenu("create",t)):t?this.removeClass("context-menu-disabled"):t||this.addClass("context-menu-disabled");else e.each(r,function(){this.selector===n.selector&&(a.data=this,e.extend(a.data,{trigger:"demand"}))}),f.contextmenu.call(a.target,a);return this},e.contextMenu=function(t,n){"string"!=typeof t&&(n=t,t="create"),"string"==typeof n?n={selector:n}:void 0===n&&(n={});var a=e.extend(!0,{},d,n||{}),o=e(document),i=o,u=!1;switch(a.context&&a.context.length?(i=e(a.context).first(),a.context=i.get(0),u=!e(a.context).is(document)):a.context=document,t){case"update":if(u)h.update(i);else for(var m in r)r.hasOwnProperty(m)&&h.update(r[m]);break;case"create":if(!a.selector)throw new Error("No selector specified");if(a.selector.match(/.context-menu-(list|item|input)($|\s)/))throw new Error('Cannot bind to selector "'+a.selector+'" as it contains a reserved className');if(!a.build&&(!a.items||e.isEmptyObject(a.items)))throw new Error("No Items specified");if(c++,a.ns=".contextMenu"+c,u||(l[a.selector]=a.ns),r[a.ns]=a,a.trigger||(a.trigger="right"),!s){var p="click"===a.itemClickEvent?"click.contextMenu":"mouseup.contextMenu",v={"contextmenu:focus.contextMenu":f.focusItem,"contextmenu:blur.contextMenu":f.blurItem,"contextmenu.contextMenu":f.abortevent,"mouseenter.contextMenu":f.itemMouseenter,"mouseleave.contextMenu":f.itemMouseleave};v[p]=f.itemClick,o.on({"contextmenu:hide.contextMenu":f.hideMenu,"prevcommand.contextMenu":f.prevItem,"nextcommand.contextMenu":f.nextItem,"contextmenu.contextMenu":f.abortevent,"mouseenter.contextMenu":f.menuMouseenter,"mouseleave.contextMenu":f.menuMouseleave},".context-menu-list").on("mouseup.contextMenu",".context-menu-input",f.inputClick).on(v,".context-menu-item"),s=!0}switch(i.on("contextmenu"+a.ns,a.selector,a,f.contextmenu),u&&i.on("remove"+a.ns,function(){e(this).contextMenu("destroy")}),a.trigger){case"hover":i.on("mouseenter"+a.ns,a.selector,a,f.mouseenter).on("mouseleave"+a.ns,a.selector,a,f.mouseleave);break;case"left":i.on("click"+a.ns,a.selector,a,f.click);break;case"touchstart":i.on("touchstart"+a.ns,a.selector,a,f.click)}a.build||h.create(a);break;case"destroy":var x;if(u){var g=a.context;e.each(r,function(t,n){if(!n)return!0;if(!e(g).is(n.selector))return!0;(x=e(".context-menu-list").filter(":visible")).length&&x.data().contextMenuRoot.$trigger.is(e(n.context).find(n.selector))&&x.trigger("contextmenu:hide",{force:!0});try{r[n.ns].$menu&&r[n.ns].$menu.remove(),delete r[n.ns]}catch(e){r[n.ns]=null}return e(n.context).off(n.ns),!0})}else if(a.selector){if(l[a.selector]){(x=e(".context-menu-list").filter(":visible")).length&&x.data().contextMenuRoot.$trigger.is(a.selector)&&x.trigger("contextmenu:hide",{force:!0});try{r[l[a.selector]].$menu&&r[l[a.selector]].$menu.remove(),delete r[l[a.selector]]}catch(e){r[l[a.selector]]=null}o.off(l[a.selector])}}else o.off(".contextMenu .contextMenuAutoHide"),e.each(r,function(t,n){e(n.context).off(n.ns)}),l={},r={},c=0,s=!1,e("#context-menu-layer, .context-menu-list").remove();break;case"html5":(!e.support.htmlCommand&&!e.support.htmlMenuitem||"boolean"==typeof n&&n)&&e('menu[type="context"]').each(function(){this.id&&e.contextMenu({selector:"[contextmenu="+this.id+"]",items:e.contextMenu.fromMenu(this)})}).css("display","none");break;default:throw new Error('Unknown operation "'+t+'"')}return this},e.contextMenu.setInputValues=function(t,n){void 0===n&&(n={}),e.each(t.inputs,function(e,t){switch(t.type){case"text":case"textarea":t.value=n[e]||"";break;case"checkbox":t.selected=!!n[e];break;case"radio":t.selected=(n[t.radio]||"")===t.value;break;case"select":t.selected=n[e]||""}})},e.contextMenu.getInputValues=function(t,n){return void 0===n&&(n={}),e.each(t.inputs,function(e,t){switch(t.type){case"text":case"textarea":case"select":n[e]=t.$input.val();break;case"checkbox":n[e]=t.$input.prop("checked");break;case"radio":t.$input.prop("checked")&&(n[t.radio]=t.value)}}),n},e.contextMenu.fromMenu=function(t){var n={};return a(n,e(t).children()),n},e.contextMenu.defaults=d,e.contextMenu.types=u,e.contextMenu.handle=f,e.contextMenu.op=h,e.contextMenu.menus=r}); +//# sourceMappingURL=jquery.contextMenu.min.js.map diff --git a/OpenRefine/extensions/database/module/scripts/index/jquery.ui.position.min.js b/OpenRefine/extensions/database/module/scripts/index/jquery.ui.position.min.js new file mode 100644 index 000000000..48d6a99b4 --- /dev/null +++ b/OpenRefine/extensions/database/module/scripts/index/jquery.ui.position.min.js @@ -0,0 +1,6 @@ +/*! jQuery UI - v1.12.1 - 2016-09-16 + * http://jqueryui.com + * Includes: position.js + * Copyright jQuery Foundation and other contributors; Licensed MIT */ + +(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)})(function(t){t.ui=t.ui||{},t.ui.version="1.12.1",function(){function e(t,e,i){return[parseFloat(t[0])*(u.test(t[0])?e/100:1),parseFloat(t[1])*(u.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}var n,o=Math.max,a=Math.abs,r=/left|center|right/,l=/top|center|bottom/,h=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,u=/%$/,d=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("
      "),o=s.children()[0];return t("body").append(s),e=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widthi?"left":e>0?"right":"center",vertical:0>r?"top":s>0?"bottom":"middle"};h>p&&p>a(e+i)&&(u.horizontal="center"),c>f&&f>a(s+r)&&(u.vertical="middle"),u.important=o(a(e),a(i))>o(a(s),a(r))?"horizontal":"vertical",n.using.call(this,t,u)}),l.offset(t.extend(D,{using:r}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,l=n-r,h=r+e.collisionWidth-a-n;e.collisionWidth>a?l>0&&0>=h?(i=t.left+l+e.collisionWidth-a-n,t.left+=l-i):t.left=h>0&&0>=l?n:l>h?n+a-e.collisionWidth:n:l>0?t.left+=l:h>0?t.left-=h:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,l=n-r,h=r+e.collisionHeight-a-n;e.collisionHeight>a?l>0&&0>=h?(i=t.top+l+e.collisionHeight-a-n,t.top+=l-i):t.top=h>0&&0>=l?n:l>h?n+a-e.collisionHeight:n:l>0?t.top+=l:h>0?t.top-=h:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,r=n.width,l=n.isWindow?n.scrollLeft:n.offset.left,h=t.left-e.collisionPosition.marginLeft,c=h-l,u=h+e.collisionWidth-r-l,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-r-o,(0>i||a(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-l,(s>0||u>a(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,r=n.height,l=n.isWindow?n.scrollTop:n.offset.top,h=t.top-e.collisionPosition.marginTop,c=h-l,u=h+e.collisionHeight-r-l,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,g=-2*e.offset[1];0>c?(s=t.top+p+f+g+e.collisionHeight-r-o,(0>s||a(c)>s)&&(t.top+=p+f+g)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+g-l,(i>0||u>a(i))&&(t.top+=p+f+g))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}}}(),t.ui.position}); \ No newline at end of file diff --git a/OpenRefine/extensions/database/module/scripts/project/database-exporters.js b/OpenRefine/extensions/database/module/scripts/project/database-exporters.js new file mode 100644 index 000000000..5f11b3e5b --- /dev/null +++ b/OpenRefine/extensions/database/module/scripts/project/database-exporters.js @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +var dictionary = ""; +$.ajax({ + url : "command/core/load-language?", + type : "POST", + async : false, + data : { + module : "database", + + }, + success : function(data) { + dictionary = data['dictionary']; + lang = data['lang']; + } +}); +$.i18n().load(dictionary, lang); +// End internationalization + +(function() { + +})(); diff --git a/OpenRefine/extensions/database/module/styles/bootstrap.css b/OpenRefine/extensions/database/module/styles/bootstrap.css new file mode 100644 index 000000000..39e2a1597 --- /dev/null +++ b/OpenRefine/extensions/database/module/styles/bootstrap.css @@ -0,0 +1,1701 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2017 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +/*! + * Generated using the Bootstrap Customizer (http://getbootstrap.com/docs/3.3/customize/?id=3426e25f732fc7882717e871fd08de17) + * Config saved to config.json and https://gist.github.com/3426e25f732fc7882717e871fd08de17 + */ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ + +.panel { + margin-bottom: 20px; + background-color: #ffffff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} +.panel-body { + padding: 15px; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 16px; + color: inherit; +} +.panel-title > a, +.panel-title > small, +.panel-title > .small, +.panel-title > small > a, +.panel-title > .small > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #dddddd; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .list-group, +.panel > .panel-collapse > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item, +.panel > .panel-collapse > .list-group .list-group-item { + border-width: 1px 0; + border-radius: 0; +} +.panel > .list-group:first-child .list-group-item:first-child, +.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { + border-top: 0; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel > .list-group:last-child .list-group-item:last-child, +.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { + border-bottom: 0; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.list-group + .panel-footer { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table, +.panel > .panel-collapse > .table { + margin-bottom: 0; +} +.panel > .table caption, +.panel > .table-responsive > .table caption, +.panel > .panel-collapse > .table caption { + padding-left: 15px; + padding-right: 15px; +} +.panel > .table:first-child, +.panel > .table-responsive:first-child > .table:first-child { + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { + border-top-right-radius: 3px; +} +.panel > .table:last-child, +.panel > .table-responsive:last-child > .table:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { + border-bottom-right-radius: 3px; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive, +.panel > .table + .panel-body, +.panel > .table-responsive + .panel-body { + border-top: 1px solid #dddddd; +} +.panel > .table > tbody:first-child > tr:first-child th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:first-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, +.panel > .table-bordered > tbody > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { + border-bottom: 0; +} +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { + border-bottom: 0; +} +.panel > .table-responsive { + border: 0; + margin-bottom: 0; +} +.panel-group { + margin-bottom: 20px; +} +.panel-group .panel { + margin-bottom: 0; + border-radius: 4px; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse > .panel-body, +.panel-group .panel-heading + .panel-collapse > .list-group { + border-top: 1px solid #dddddd; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #dddddd; +} +.panel-default { + border-color: #dddddd; +} +.panel-default > .panel-heading { + color: #333333; + background-color: #f5f5f5; + border-color: #dddddd; +} +.panel-default > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #dddddd; +} +.panel-default > .panel-heading .badge { + color: #f5f5f5; + background-color: #333333; +} +.panel-default > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #dddddd; +} +.panel-primary { + border-color: #337ab7; +} +.panel-primary > .panel-heading { + color: #ffffff; + background-color: #337ab7; + border-color: #337ab7; +} +.panel-primary > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #337ab7; +} +.panel-primary > .panel-heading .badge { + color: #337ab7; + background-color: #ffffff; +} +.panel-primary > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #337ab7; +} +.panel-success { + border-color: #d6e9c6; +} +.panel-success > .panel-heading { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.panel-success > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #d6e9c6; +} +.panel-success > .panel-heading .badge { + color: #dff0d8; + background-color: #3c763d; +} +.panel-success > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #d6e9c6; +} +.panel-info { + border-color: #bce8f1; +} +.panel-info > .panel-heading { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.panel-info > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #bce8f1; +} +.panel-info > .panel-heading .badge { + color: #d9edf7; + background-color: #31708f; +} +.panel-info > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #bce8f1; +} +.panel-warning { + border-color: #faebcc; +} +.panel-warning > .panel-heading { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.panel-warning > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #faebcc; +} +.panel-warning > .panel-heading .badge { + color: #fcf8e3; + background-color: #8a6d3b; +} +.panel-warning > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #faebcc; +} +.panel-danger { + border-color: #ebccd1; +} +.panel-danger > .panel-heading { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.panel-danger > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ebccd1; +} +.panel-danger > .panel-heading .badge { + color: #f2dede; + background-color: #a94442; +} +.panel-danger > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ebccd1; +} +.clearfix:before, +.clearfix:after, +.nav:before, +.nav:after, +.panel-body:before, +.panel-body:after { + content: " "; + display: table; +} +.clearfix:after, +.nav:after, +.panel-body:after { + clear: both; +} +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; +} +.affix { + position: fixed; +} + +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable, +.alert-dismissible { + padding-right: 35px; +} +.alert-dismissable .close, +.alert-dismissible .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; + color: #3c763d; +} +.alert-success hr { + border-top-color: #c9e2b3; +} +.alert-success .alert-link { + color: #2b542c; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; + color: #31708f; +} +.alert-info hr { + border-top-color: #a6e1ec; +} +.alert-info .alert-link { + color: #245269; +} +.alert-warning { + background-color: #fcf8e3; + border-color: #faebcc; + color: #8a6d3b; +} +.alert-warning hr { + border-top-color: #f7e1b5; +} +.alert-warning .alert-link { + color: #66512c; +} +.alert-danger { + background-color: #f2dede; + border-color: #ebccd1; + color: #a94442; +} +.alert-danger hr { + border-top-color: #e4b9c0; +} +.alert-danger .alert-link { + color: #843534; +} + +@font-face { + font-family: 'Glyphicons Halflings'; + src: url('../images/fonts/glyphicons-halflings-regular.eot'); + src: url('../images/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../images/fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../images/fonts/glyphicons-halflings-regular.woff') format('woff'), url('../images/fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../images/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); +} +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.glyphicon-asterisk:before { + content: "\002a"; +} +.glyphicon-plus:before { + content: "\002b"; +} +.glyphicon-euro:before, +.glyphicon-eur:before { + content: "\20ac"; +} +.glyphicon-minus:before { + content: "\2212"; +} +.glyphicon-cloud:before { + content: "\2601"; +} +.glyphicon-envelope:before { + content: "\2709"; +} +.glyphicon-pencil:before { + content: "\270f"; +} +.glyphicon-glass:before { + content: "\e001"; +} +.glyphicon-music:before { + content: "\e002"; +} +.glyphicon-search:before { + content: "\e003"; +} +.glyphicon-heart:before { + content: "\e005"; +} +.glyphicon-star:before { + content: "\e006"; +} +.glyphicon-star-empty:before { + content: "\e007"; +} +.glyphicon-user:before { + content: "\e008"; +} +.glyphicon-film:before { + content: "\e009"; +} +.glyphicon-th-large:before { + content: "\e010"; +} +.glyphicon-th:before { + content: "\e011"; +} +.glyphicon-th-list:before { + content: "\e012"; +} +.glyphicon-ok:before { + content: "\e013"; +} +.glyphicon-remove:before { + content: "\e014"; +} +.glyphicon-zoom-in:before { + content: "\e015"; +} +.glyphicon-zoom-out:before { + content: "\e016"; +} +.glyphicon-off:before { + content: "\e017"; +} +.glyphicon-signal:before { + content: "\e018"; +} +.glyphicon-cog:before { + content: "\e019"; +} +.glyphicon-trash:before { + content: "\e020"; +} +.glyphicon-home:before { + content: "\e021"; +} +.glyphicon-file:before { + content: "\e022"; +} +.glyphicon-time:before { + content: "\e023"; +} +.glyphicon-road:before { + content: "\e024"; +} +.glyphicon-download-alt:before { + content: "\e025"; +} +.glyphicon-download:before { + content: "\e026"; +} +.glyphicon-upload:before { + content: "\e027"; +} +.glyphicon-inbox:before { + content: "\e028"; +} +.glyphicon-play-circle:before { + content: "\e029"; +} +.glyphicon-repeat:before { + content: "\e030"; +} +.glyphicon-refresh:before { + content: "\e031"; +} +.glyphicon-list-alt:before { + content: "\e032"; +} +.glyphicon-lock:before { + content: "\e033"; +} +.glyphicon-flag:before { + content: "\e034"; +} +.glyphicon-headphones:before { + content: "\e035"; +} +.glyphicon-volume-off:before { + content: "\e036"; +} +.glyphicon-volume-down:before { + content: "\e037"; +} +.glyphicon-volume-up:before { + content: "\e038"; +} +.glyphicon-qrcode:before { + content: "\e039"; +} +.glyphicon-barcode:before { + content: "\e040"; +} +.glyphicon-tag:before { + content: "\e041"; +} +.glyphicon-tags:before { + content: "\e042"; +} +.glyphicon-book:before { + content: "\e043"; +} +.glyphicon-bookmark:before { + content: "\e044"; +} +.glyphicon-print:before { + content: "\e045"; +} +.glyphicon-camera:before { + content: "\e046"; +} +.glyphicon-font:before { + content: "\e047"; +} +.glyphicon-bold:before { + content: "\e048"; +} +.glyphicon-italic:before { + content: "\e049"; +} +.glyphicon-text-height:before { + content: "\e050"; +} +.glyphicon-text-width:before { + content: "\e051"; +} +.glyphicon-align-left:before { + content: "\e052"; +} +.glyphicon-align-center:before { + content: "\e053"; +} +.glyphicon-align-right:before { + content: "\e054"; +} +.glyphicon-align-justify:before { + content: "\e055"; +} +.glyphicon-list:before { + content: "\e056"; +} +.glyphicon-indent-left:before { + content: "\e057"; +} +.glyphicon-indent-right:before { + content: "\e058"; +} +.glyphicon-facetime-video:before { + content: "\e059"; +} +.glyphicon-picture:before { + content: "\e060"; +} +.glyphicon-map-marker:before { + content: "\e062"; +} +.glyphicon-adjust:before { + content: "\e063"; +} +.glyphicon-tint:before { + content: "\e064"; +} +.glyphicon-edit:before { + content: "\e065"; +} +.glyphicon-share:before { + content: "\e066"; +} +.glyphicon-check:before { + content: "\e067"; +} +.glyphicon-move:before { + content: "\e068"; +} +.glyphicon-step-backward:before { + content: "\e069"; +} +.glyphicon-fast-backward:before { + content: "\e070"; +} +.glyphicon-backward:before { + content: "\e071"; +} +.glyphicon-play:before { + content: "\e072"; +} +.glyphicon-pause:before { + content: "\e073"; +} +.glyphicon-stop:before { + content: "\e074"; +} +.glyphicon-forward:before { + content: "\e075"; +} +.glyphicon-fast-forward:before { + content: "\e076"; +} +.glyphicon-step-forward:before { + content: "\e077"; +} +.glyphicon-eject:before { + content: "\e078"; +} +.glyphicon-chevron-left:before { + content: "\e079"; +} +.glyphicon-chevron-right:before { + content: "\e080"; +} +.glyphicon-plus-sign:before { + content: "\e081"; +} +.glyphicon-minus-sign:before { + content: "\e082"; +} +.glyphicon-remove-sign:before { + content: "\e083"; +} +.glyphicon-ok-sign:before { + content: "\e084"; +} +.glyphicon-question-sign:before { + content: "\e085"; +} +.glyphicon-info-sign:before { + content: "\e086"; +} +.glyphicon-screenshot:before { + content: "\e087"; +} +.glyphicon-remove-circle:before { + content: "\e088"; +} +.glyphicon-ok-circle:before { + content: "\e089"; +} +.glyphicon-ban-circle:before { + content: "\e090"; +} +.glyphicon-arrow-left:before { + content: "\e091"; +} +.glyphicon-arrow-right:before { + content: "\e092"; +} +.glyphicon-arrow-up:before { + content: "\e093"; +} +.glyphicon-arrow-down:before { + content: "\e094"; +} +.glyphicon-share-alt:before { + content: "\e095"; +} +.glyphicon-resize-full:before { + content: "\e096"; +} +.glyphicon-resize-small:before { + content: "\e097"; +} +.glyphicon-exclamation-sign:before { + content: "\e101"; +} +.glyphicon-gift:before { + content: "\e102"; +} +.glyphicon-leaf:before { + content: "\e103"; +} +.glyphicon-fire:before { + content: "\e104"; +} +.glyphicon-eye-open:before { + content: "\e105"; +} +.glyphicon-eye-close:before { + content: "\e106"; +} +.glyphicon-warning-sign:before { + content: "\e107"; +} +.glyphicon-plane:before { + content: "\e108"; +} +.glyphicon-calendar:before { + content: "\e109"; +} +.glyphicon-random:before { + content: "\e110"; +} +.glyphicon-comment:before { + content: "\e111"; +} +.glyphicon-magnet:before { + content: "\e112"; +} +.glyphicon-chevron-up:before { + content: "\e113"; +} +.glyphicon-chevron-down:before { + content: "\e114"; +} +.glyphicon-retweet:before { + content: "\e115"; +} +.glyphicon-shopping-cart:before { + content: "\e116"; +} +.glyphicon-folder-close:before { + content: "\e117"; +} +.glyphicon-folder-open:before { + content: "\e118"; +} +.glyphicon-resize-vertical:before { + content: "\e119"; +} +.glyphicon-resize-horizontal:before { + content: "\e120"; +} +.glyphicon-hdd:before { + content: "\e121"; +} +.glyphicon-bullhorn:before { + content: "\e122"; +} +.glyphicon-bell:before { + content: "\e123"; +} +.glyphicon-certificate:before { + content: "\e124"; +} +.glyphicon-thumbs-up:before { + content: "\e125"; +} +.glyphicon-thumbs-down:before { + content: "\e126"; +} +.glyphicon-hand-right:before { + content: "\e127"; +} +.glyphicon-hand-left:before { + content: "\e128"; +} +.glyphicon-hand-up:before { + content: "\e129"; +} +.glyphicon-hand-down:before { + content: "\e130"; +} +.glyphicon-circle-arrow-right:before { + content: "\e131"; +} +.glyphicon-circle-arrow-left:before { + content: "\e132"; +} +.glyphicon-circle-arrow-up:before { + content: "\e133"; +} +.glyphicon-circle-arrow-down:before { + content: "\e134"; +} +.glyphicon-globe:before { + content: "\e135"; +} +.glyphicon-wrench:before { + content: "\e136"; +} +.glyphicon-tasks:before { + content: "\e137"; +} +.glyphicon-filter:before { + content: "\e138"; +} +.glyphicon-briefcase:before { + content: "\e139"; +} +.glyphicon-fullscreen:before { + content: "\e140"; +} +.glyphicon-dashboard:before { + content: "\e141"; +} +.glyphicon-paperclip:before { + content: "\e142"; +} +.glyphicon-heart-empty:before { + content: "\e143"; +} +.glyphicon-link:before { + content: "\e144"; +} +.glyphicon-phone:before { + content: "\e145"; +} +.glyphicon-pushpin:before { + content: "\e146"; +} +.glyphicon-usd:before { + content: "\e148"; +} +.glyphicon-gbp:before { + content: "\e149"; +} +.glyphicon-sort:before { + content: "\e150"; +} +.glyphicon-sort-by-alphabet:before { + content: "\e151"; +} +.glyphicon-sort-by-alphabet-alt:before { + content: "\e152"; +} +.glyphicon-sort-by-order:before { + content: "\e153"; +} +.glyphicon-sort-by-order-alt:before { + content: "\e154"; +} +.glyphicon-sort-by-attributes:before { + content: "\e155"; +} +.glyphicon-sort-by-attributes-alt:before { + content: "\e156"; +} +.glyphicon-unchecked:before { + content: "\e157"; +} +.glyphicon-expand:before { + content: "\e158"; +} +.glyphicon-collapse-down:before { + content: "\e159"; +} +.glyphicon-collapse-up:before { + content: "\e160"; +} +.glyphicon-log-in:before { + content: "\e161"; +} +.glyphicon-flash:before { + content: "\e162"; +} +.glyphicon-log-out:before { + content: "\e163"; +} +.glyphicon-new-window:before { + content: "\e164"; +} +.glyphicon-record:before { + content: "\e165"; +} +.glyphicon-save:before { + content: "\e166"; +} +.glyphicon-open:before { + content: "\e167"; +} +.glyphicon-saved:before { + content: "\e168"; +} +.glyphicon-import:before { + content: "\e169"; +} +.glyphicon-export:before { + content: "\e170"; +} +.glyphicon-send:before { + content: "\e171"; +} +.glyphicon-floppy-disk:before { + content: "\e172"; +} +.glyphicon-floppy-saved:before { + content: "\e173"; +} +.glyphicon-floppy-remove:before { + content: "\e174"; +} +.glyphicon-floppy-save:before { + content: "\e175"; +} +.glyphicon-floppy-open:before { + content: "\e176"; +} +.glyphicon-credit-card:before { + content: "\e177"; +} +.glyphicon-transfer:before { + content: "\e178"; +} +.glyphicon-cutlery:before { + content: "\e179"; +} +.glyphicon-header:before { + content: "\e180"; +} +.glyphicon-compressed:before { + content: "\e181"; +} +.glyphicon-earphone:before { + content: "\e182"; +} +.glyphicon-phone-alt:before { + content: "\e183"; +} +.glyphicon-tower:before { + content: "\e184"; +} +.glyphicon-stats:before { + content: "\e185"; +} +.glyphicon-sd-video:before { + content: "\e186"; +} +.glyphicon-hd-video:before { + content: "\e187"; +} +.glyphicon-subtitles:before { + content: "\e188"; +} +.glyphicon-sound-stereo:before { + content: "\e189"; +} +.glyphicon-sound-dolby:before { + content: "\e190"; +} +.glyphicon-sound-5-1:before { + content: "\e191"; +} +.glyphicon-sound-6-1:before { + content: "\e192"; +} +.glyphicon-sound-7-1:before { + content: "\e193"; +} +.glyphicon-copyright-mark:before { + content: "\e194"; +} +.glyphicon-registration-mark:before { + content: "\e195"; +} +.glyphicon-cloud-download:before { + content: "\e197"; +} +.glyphicon-cloud-upload:before { + content: "\e198"; +} +.glyphicon-tree-conifer:before { + content: "\e199"; +} +.glyphicon-tree-deciduous:before { + content: "\e200"; +} +.glyphicon-cd:before { + content: "\e201"; +} +.glyphicon-save-file:before { + content: "\e202"; +} +.glyphicon-open-file:before { + content: "\e203"; +} +.glyphicon-level-up:before { + content: "\e204"; +} +.glyphicon-copy:before { + content: "\e205"; +} +.glyphicon-paste:before { + content: "\e206"; +} +.glyphicon-alert:before { + content: "\e209"; +} +.glyphicon-equalizer:before { + content: "\e210"; +} +.glyphicon-king:before { + content: "\e211"; +} +.glyphicon-queen:before { + content: "\e212"; +} +.glyphicon-pawn:before { + content: "\e213"; +} +.glyphicon-bishop:before { + content: "\e214"; +} +.glyphicon-knight:before { + content: "\e215"; +} +.glyphicon-baby-formula:before { + content: "\e216"; +} +.glyphicon-tent:before { + content: "\26fa"; +} +.glyphicon-blackboard:before { + content: "\e218"; +} +.glyphicon-bed:before { + content: "\e219"; +} +.glyphicon-apple:before { + content: "\f8ff"; +} +.glyphicon-erase:before { + content: "\e221"; +} +.glyphicon-hourglass:before { + content: "\231b"; +} +.glyphicon-lamp:before { + content: "\e223"; +} +.glyphicon-duplicate:before { + content: "\e224"; +} +.glyphicon-piggy-bank:before { + content: "\e225"; +} +.glyphicon-scissors:before { + content: "\e226"; +} +.glyphicon-bitcoin:before { + content: "\e227"; +} +.glyphicon-btc:before { + content: "\e227"; +} +.glyphicon-xbt:before { + content: "\e227"; +} +.glyphicon-yen:before { + content: "\00a5"; +} +.glyphicon-jpy:before { + content: "\00a5"; +} +.glyphicon-ruble:before { + content: "\20bd"; +} +.glyphicon-rub:before { + content: "\20bd"; +} +.glyphicon-scale:before { + content: "\e230"; +} +.glyphicon-ice-lolly:before { + content: "\e231"; +} +.glyphicon-ice-lolly-tasted:before { + content: "\e232"; +} +.glyphicon-education:before { + content: "\e233"; +} +.glyphicon-option-horizontal:before { + content: "\e234"; +} +.glyphicon-option-vertical:before { + content: "\e235"; +} +.glyphicon-menu-hamburger:before { + content: "\e236"; +} +.glyphicon-modal-window:before { + content: "\e237"; +} +.glyphicon-oil:before { + content: "\e238"; +} +.glyphicon-grain:before { + content: "\e239"; +} +.glyphicon-sunglasses:before { + content: "\e240"; +} +.glyphicon-text-size:before { + content: "\e241"; +} +.glyphicon-text-color:before { + content: "\e242"; +} +.glyphicon-text-background:before { + content: "\e243"; +} +.glyphicon-object-align-top:before { + content: "\e244"; +} +.glyphicon-object-align-bottom:before { + content: "\e245"; +} +.glyphicon-object-align-horizontal:before { + content: "\e246"; +} +.glyphicon-object-align-left:before { + content: "\e247"; +} +.glyphicon-object-align-vertical:before { + content: "\e248"; +} +.glyphicon-object-align-right:before { + content: "\e249"; +} +.glyphicon-triangle-right:before { + content: "\e250"; +} +.glyphicon-triangle-left:before { + content: "\e251"; +} +.glyphicon-triangle-bottom:before { + content: "\e252"; +} +.glyphicon-triangle-top:before { + content: "\e253"; +} +.glyphicon-console:before { + content: "\e254"; +} +.glyphicon-superscript:before { + content: "\e255"; +} +.glyphicon-subscript:before { + content: "\e256"; +} +.glyphicon-menu-left:before { + content: "\e257"; +} +.glyphicon-menu-right:before { + content: "\e258"; +} +.glyphicon-menu-down:before { + content: "\e259"; +} +.glyphicon-menu-up:before { + content: "\e260"; +} + +.nav { + margin-bottom: 0; + padding-left: 0; + list-style: none; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} +.nav > li.disabled > a { + color: #777777; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #777777; + text-decoration: none; + background-color: transparent; + cursor: not-allowed; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #eeeeee; + border-color: #337ab7; +} +.nav .nav-divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #dddddd; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.42857143; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555555; + background-color: #ffffff; + border: 1px solid #dddddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #ffffff; + background-color: #337ab7; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +/* +* List Group +*/ +.list-group { + margin-bottom: 20px; + padding-left: 0; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #ffffff; + border: 1px solid #dddddd; +} +.list-group-item:first-child { + border-top-right-radius: 4px; + border-top-left-radius: 4px; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +a.list-group-item, +button.list-group-item { + color: #555555; +} +a.list-group-item .list-group-item-heading, +button.list-group-item .list-group-item-heading { + color: #333333; +} +a.list-group-item:hover, +button.list-group-item:hover, +a.list-group-item:focus, +button.list-group-item:focus { + text-decoration: none; + color: #555555; + background-color: #f5f5f5; +} +button.list-group-item { + width: 100%; + text-align: left; +} +.list-group-item.disabled, +.list-group-item.disabled:hover, +.list-group-item.disabled:focus { + background-color: #eeeeee; + color: #777777; + cursor: not-allowed; +} +.list-group-item.disabled .list-group-item-heading, +.list-group-item.disabled:hover .list-group-item-heading, +.list-group-item.disabled:focus .list-group-item-heading { + color: inherit; +} +.list-group-item.disabled .list-group-item-text, +.list-group-item.disabled:hover .list-group-item-text, +.list-group-item.disabled:focus .list-group-item-text { + color: #777777; +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + z-index: 2; + color: #ffffff; + background-color: #337ab7; + border-color: #337ab7; +} +.list-group-item.active .list-group-item-heading, +.list-group-item.active:hover .list-group-item-heading, +.list-group-item.active:focus .list-group-item-heading, +.list-group-item.active .list-group-item-heading > small, +.list-group-item.active:hover .list-group-item-heading > small, +.list-group-item.active:focus .list-group-item-heading > small, +.list-group-item.active .list-group-item-heading > .small, +.list-group-item.active:hover .list-group-item-heading > .small, +.list-group-item.active:focus .list-group-item-heading > .small { + color: inherit; +} +.list-group-item.active .list-group-item-text, +.list-group-item.active:hover .list-group-item-text, +.list-group-item.active:focus .list-group-item-text { + color: #c7ddef; +} +.list-group-item-success { + color: #3c763d; + background-color: #dff0d8; +} +a.list-group-item-success, +button.list-group-item-success { + color: #3c763d; +} +a.list-group-item-success .list-group-item-heading, +button.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +button.list-group-item-success:hover, +a.list-group-item-success:focus, +button.list-group-item-success:focus { + color: #3c763d; + background-color: #d0e9c6; +} +a.list-group-item-success.active, +button.list-group-item-success.active, +a.list-group-item-success.active:hover, +button.list-group-item-success.active:hover, +a.list-group-item-success.active:focus, +button.list-group-item-success.active:focus { + color: #fff; + background-color: #3c763d; + border-color: #3c763d; +} +.list-group-item-info { + color: #31708f; + background-color: #d9edf7; +} +a.list-group-item-info, +button.list-group-item-info { + color: #31708f; +} +a.list-group-item-info .list-group-item-heading, +button.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +button.list-group-item-info:hover, +a.list-group-item-info:focus, +button.list-group-item-info:focus { + color: #31708f; + background-color: #c4e3f3; +} +a.list-group-item-info.active, +button.list-group-item-info.active, +a.list-group-item-info.active:hover, +button.list-group-item-info.active:hover, +a.list-group-item-info.active:focus, +button.list-group-item-info.active:focus { + color: #fff; + background-color: #31708f; + border-color: #31708f; +} +.list-group-item-warning { + color: #8a6d3b; + background-color: #fcf8e3; +} +a.list-group-item-warning, +button.list-group-item-warning { + color: #8a6d3b; +} +a.list-group-item-warning .list-group-item-heading, +button.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +button.list-group-item-warning:hover, +a.list-group-item-warning:focus, +button.list-group-item-warning:focus { + color: #8a6d3b; + background-color: #faf2cc; +} +a.list-group-item-warning.active, +button.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +button.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus, +button.list-group-item-warning.active:focus { + color: #fff; + background-color: #8a6d3b; + border-color: #8a6d3b; +} +.list-group-item-danger { + color: #a94442; + background-color: #f2dede; +} +a.list-group-item-danger, +button.list-group-item-danger { + color: #a94442; +} +a.list-group-item-danger .list-group-item-heading, +button.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +button.list-group-item-danger:hover, +a.list-group-item-danger:focus, +button.list-group-item-danger:focus { + color: #a94442; + background-color: #ebcccc; +} +a.list-group-item-danger.active, +button.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +button.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus, +button.list-group-item-danger.active:focus { + color: #fff; + background-color: #a94442; + border-color: #a94442; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.well-lg { + padding: 24px; + border-radius: 6px; +} +.well-sm { + padding: 9px; + border-radius: 3px; +} diff --git a/OpenRefine/extensions/database/module/styles/database-import.less b/OpenRefine/extensions/database/module/styles/database-import.less new file mode 100644 index 000000000..770958405 --- /dev/null +++ b/OpenRefine/extensions/database/module/styles/database-import.less @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +@import-less url("theme.less"); + +.database-container { +// margin-left: 200px; + // width: 50%; +// min-height: 50%; +} + +.cleared { + clear: both; +} + +.custom-restricted-width { + /* To limit the menu width to the content of the menu: */ + display: inline-block; + /* Or set the width explicitly: */ + /* width: 10em; */ +} + + +.scrollable { + height: 400px; + overflow: auto; +} + +.database-importing-wizard-header { + font-size: 1.3em; + background: @chrome_primary; + padding: @padding_tight; + } + +.database-importing-parsing-data-panel { + font-size: 1.1em; + position: absolute; + overflow: auto; + } + +.database-importing-progress-data-panel { + position: absolute; + overflow: auto; + font-size: 200%; + padding: 3em; + background: rgba(255, 255, 255, 0.7); + text-align: center; + } + +.database-importing-parsing-control-panel { + font-size: 1.3em; + position: absolute; + overflow: auto; + border-top: 5px solid @chrome_primary; + background: white; + padding: @padding_looser; + } + +.context-menu-text { + padding: 4px 4px 2px 2px; +} + + +.custom-restricted { + height: 300px; + width: 100%; + border: 1px solid #bcf; + border-radius: 4px; +} + +// FIXME: This is a duplicate +.custom-restricted-width { + /* To limit the menu width to the content of the menu: */ + display: inline-block; + /* Or set the width explicitly: */ + /* width: 10em; */ + margin-right:10px; + padding-right:10px; + margin-bottom:10px; +} +.no-resize { + resize: none; +} +.layout-div { + width : 100%; + +} +.layout-div .connection-div-layout { + min-width: 400px; +} +.new-connection-legend { + padding-left: 2px; + margin-left: 2px; + border-color: #bcf; +} + +.sql-editor-div { + margin-left:40px; + padding-left:20px; +} +.new-connection-div { + margin-left:40px; + padding-left:20px; +} +.new-connection-fieldset { + border: 1px solid gray; +} + +.sc-context-more-vert:after { + content: ""; + display: inline-block; + background: url("../images/more-option-horiz-16.png") no-repeat top right; + // line-height: 1; + width: 16px; + height: 16px; + -webkit-font-smoothing: antialiased; + +} diff --git a/OpenRefine/extensions/database/module/styles/jquery.contextMenu.css b/OpenRefine/extensions/database/module/styles/jquery.contextMenu.css new file mode 100644 index 000000000..0253e6e1b --- /dev/null +++ b/OpenRefine/extensions/database/module/styles/jquery.contextMenu.css @@ -0,0 +1,292 @@ +@charset "UTF-8"; +/*! + * jQuery contextMenu - Plugin for simple contextMenu handling + * + * Version: v2.6.3 + * + * Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF) + * Web: http://swisnl.github.io/jQuery-contextMenu/ + * + * Copyright (c) 2011-2017 SWIS BV and contributors + * + * Licensed under + * MIT License http://www.opensource.org/licenses/mit-license + * + * Date: 2017-10-30T19:03:13.936Z + */ +@-webkit-keyframes cm-spin { + 0% { + -webkit-transform: translateY(-50%) rotate(0deg); + transform: translateY(-50%) rotate(0deg); + } + 100% { + -webkit-transform: translateY(-50%) rotate(359deg); + transform: translateY(-50%) rotate(359deg); + } +} +@-o-keyframes cm-spin { + 0% { + -webkit-transform: translateY(-50%) rotate(0deg); + -o-transform: translateY(-50%) rotate(0deg); + transform: translateY(-50%) rotate(0deg); + } + 100% { + -webkit-transform: translateY(-50%) rotate(359deg); + -o-transform: translateY(-50%) rotate(359deg); + transform: translateY(-50%) rotate(359deg); + } +} +@keyframes cm-spin { + 0% { + -webkit-transform: translateY(-50%) rotate(0deg); + -o-transform: translateY(-50%) rotate(0deg); + transform: translateY(-50%) rotate(0deg); + } + 100% { + -webkit-transform: translateY(-50%) rotate(359deg); + -o-transform: translateY(-50%) rotate(359deg); + transform: translateY(-50%) rotate(359deg); + } +} + +@font-face { + font-family: "context-menu-icons"; + font-style: normal; + font-weight: normal; + + src: url("font/context-menu-icons.eot?2wp27"); + src: url("font/context-menu-icons.eot?2wp27#iefix") format("embedded-opentype"), url("font/context-menu-icons.woff2?2wp27") format("woff2"), url("font/context-menu-icons.woff?2wp27") format("woff"), url("font/context-menu-icons.ttf?2wp27") format("truetype"); +} + +.context-menu-icon-add:before { + content: "\EA01"; +} + +.context-menu-icon-copy:before { + content: "\EA02"; +} + +.context-menu-icon-cut:before { + content: "\EA03"; +} + +.context-menu-icon-delete:before { + content: "\EA04"; +} + +.context-menu-icon-edit:before { + content: "\EA05"; +} + +.context-menu-icon-loading:before { + content: "\EA06"; +} + +.context-menu-icon-paste:before { + content: "\EA07"; +} + +.context-menu-icon-quit:before { + content: "\EA08"; +} + +.context-menu-icon::before { + position: absolute; + top: 50%; + left: 0; + width: 2em; + font-family: "context-menu-icons"; + font-size: 1em; + font-style: normal; + font-weight: normal; + line-height: 1; + color: #2980b9; + text-align: center; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + -o-transform: translateY(-50%); + transform: translateY(-50%); + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.context-menu-icon.context-menu-hover:before { + color: #fff; +} + +.context-menu-icon.context-menu-disabled::before { + color: #bbb; +} + +.context-menu-icon.context-menu-icon-loading:before { + -webkit-animation: cm-spin 2s infinite; + -o-animation: cm-spin 2s infinite; + animation: cm-spin 2s infinite; +} + +.context-menu-icon.context-menu-icon--fa { + display: list-item; + font-family: inherit; +} +.context-menu-icon.context-menu-icon--fa::before { + position: absolute; + top: 50%; + left: 0; + width: 2em; + font-family: FontAwesome; + font-size: 1em; + font-style: normal; + font-weight: normal; + line-height: 1; + color: #2980b9; + text-align: center; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + -o-transform: translateY(-50%); + transform: translateY(-50%); + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.context-menu-icon.context-menu-icon--fa.context-menu-hover:before { + color: #fff; +} +.context-menu-icon.context-menu-icon--fa.context-menu-disabled::before { + color: #bbb; +} + +.context-menu-list { + position: absolute; + display: inline-block; + min-width: 13em; + max-width: 26em; + padding: .25em 0; + margin: .3em; + font-family: inherit; + font-size: inherit; + list-style-type: none; + background: #fff; + border: 1px solid #bebebe; + border-radius: .2em; + -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, .5); + box-shadow: 0 2px 5px rgba(0, 0, 0, .5); +} + +.context-menu-item { + position: relative; + padding: .2em 2em; + color: #2f2f2f; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: #fff; + font: 15px "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +.context-menu-separator { + padding: 0; + margin: .35em 0; + border-bottom: 1px solid #e6e6e6; +} + +.context-menu-item > label > input, +.context-menu-item > label > textarea { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.context-menu-item.context-menu-hover { + color: #fff; + cursor: pointer; + background-color: #2980b9; +} + +.context-menu-item.context-menu-disabled { + color: #bbb; + cursor: default; + background-color: #fff; +} + +.context-menu-input.context-menu-hover { + color: #2f2f2f; + cursor: default; +} + +.context-menu-submenu:after { + position: absolute; + top: 50%; + right: .5em; + z-index: 1; + width: 0; + height: 0; + content: ''; + border-color: transparent transparent transparent #2f2f2f; + border-style: solid; + border-width: .25em 0 .25em .25em; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + -o-transform: translateY(-50%); + transform: translateY(-50%); +} + +/** + * Inputs + */ +.context-menu-item.context-menu-input { + padding: .3em .6em; +} + +/* vertically align inside labels */ +.context-menu-input > label > * { + vertical-align: top; +} + +/* position checkboxes and radios as icons */ +.context-menu-input > label > input[type="checkbox"], +.context-menu-input > label > input[type="radio"] { + position: relative; + top: .12em; + margin-right: .4em; +} + +.context-menu-input > label { + margin: 0; +} + +.context-menu-input > label, +.context-menu-input > label > input[type="text"], +.context-menu-input > label > textarea, +.context-menu-input > label > select { + display: block; + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.context-menu-input > label > textarea { + height: 7em; +} + +.context-menu-item > .context-menu-list { + top: .3em; + /* re-positioned by js */ + right: -.3em; + display: none; +} + +.context-menu-item.context-menu-visible > .context-menu-list { + display: block; +} + +.context-menu-accesskey { + text-decoration: underline; +} +/*Custom to display icons*/ + + + diff --git a/OpenRefine/extensions/database/module/styles/pure.css b/OpenRefine/extensions/database/module/styles/pure.css new file mode 100644 index 000000000..854e02cad --- /dev/null +++ b/OpenRefine/extensions/database/module/styles/pure.css @@ -0,0 +1,1549 @@ +/*! +Pure v1.0.0 +Copyright 2013 Yahoo! +Licensed under the BSD License. +https://github.com/yahoo/pure/blob/master/LICENSE.md +*/ +/*! +normalize.css v^3.0 | MIT License | git.io/normalize +Copyright (c) Nicolas Gallagher and Jonathan Neal +*/ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS and IE text size adjust after device orientation change, + * without disabling user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Improve readability of focused elements when they are also in an + * active/hover state. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * 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 Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +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"], /* 1 */ +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; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome. + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + box-sizing: content-box; /* 2 */ +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 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/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} + +/*csslint important:false*/ + +/* ========================================================================== + Pure Base Extras + ========================================================================== */ + +/** + * Extra rules that Pure adds on top of Normalize.css + */ + +/** + * Always hide an element when it has the `hidden` HTML attribute. + */ + +.hidden, +[hidden] { + display: none !important; +} + +/** + * Add this class to an image to make it fit within it's fluid parent wrapper while maintaining + * aspect ratio. + */ +.pure-img { + max-width: 100%; + height: auto; + display: block; +} + +/*csslint regex-selectors:false, known-properties:false, duplicate-properties:false*/ + +.pure-g { + letter-spacing: -0.31em; /* Webkit: collapse white-space between units */ + *letter-spacing: normal; /* reset IE < 8 */ + *word-spacing: -0.43em; /* IE < 8: collapse white-space between units */ + text-rendering: optimizespeed; /* Webkit: fixes text-rendering: optimizeLegibility */ + + /* + Sets the font stack to fonts known to work properly with the above letter + and word spacings. See: https://github.com/yahoo/pure/issues/41/ + + The following font stack makes Pure Grids work on all known environments. + + * FreeSans: Ships with many Linux distros, including Ubuntu + + * Arimo: Ships with Chrome OS. Arimo has to be defined before Helvetica and + Arial to get picked up by the browser, even though neither is available + in Chrome OS. + + * Droid Sans: Ships with all versions of Android. + + * Helvetica, Arial, sans-serif: Common font stack on OS X and Windows. + */ + font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif; + + /* Use flexbox when possible to avoid `letter-spacing` side-effects. */ + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-flow: row wrap; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + + /* Prevents distributing space between rows */ + -webkit-align-content: flex-start; + -ms-flex-line-pack: start; + align-content: flex-start; +} + +/* IE10 display: -ms-flexbox (and display: flex in IE 11) does not work inside a table; fall back to block and rely on font hack */ +@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + table .pure-g { + display: block; + } +} + +/* Opera as of 12 on Windows needs word-spacing. + The ".opera-only" selector is used to prevent actual prefocus styling + and is not required in markup. +*/ +.opera-only :-o-prefocus, +.pure-g { + word-spacing: -0.43em; +} + +.pure-u { + display: inline-block; + *display: inline; /* IE < 8: fake inline-block */ + zoom: 1; + letter-spacing: normal; + word-spacing: normal; + vertical-align: top; + text-rendering: auto; +} + +/* +Resets the font family back to the OS/browser's default sans-serif font, +this the same font stack that Normalize.css sets for the `body`. +*/ +.pure-g [class *= "pure-u"] { + font-family: sans-serif; +} + +.pure-u-1, +.pure-u-1-1, +.pure-u-1-2, +.pure-u-1-3, +.pure-u-2-3, +.pure-u-1-4, +.pure-u-3-4, +.pure-u-1-5, +.pure-u-2-5, +.pure-u-3-5, +.pure-u-4-5, +.pure-u-5-5, +.pure-u-1-6, +.pure-u-5-6, +.pure-u-1-8, +.pure-u-3-8, +.pure-u-5-8, +.pure-u-7-8, +.pure-u-1-12, +.pure-u-5-12, +.pure-u-7-12, +.pure-u-11-12, +.pure-u-1-24, +.pure-u-2-24, +.pure-u-3-24, +.pure-u-4-24, +.pure-u-5-24, +.pure-u-6-24, +.pure-u-7-24, +.pure-u-8-24, +.pure-u-9-24, +.pure-u-10-24, +.pure-u-11-24, +.pure-u-12-24, +.pure-u-13-24, +.pure-u-14-24, +.pure-u-15-24, +.pure-u-16-24, +.pure-u-17-24, +.pure-u-18-24, +.pure-u-19-24, +.pure-u-20-24, +.pure-u-21-24, +.pure-u-22-24, +.pure-u-23-24, +.pure-u-24-24 { + display: inline-block; + *display: inline; + zoom: 1; + letter-spacing: normal; + word-spacing: normal; + vertical-align: top; + text-rendering: auto; +} + +.pure-u-1-24 { + width: 4.1667%; + *width: 4.1357%; +} + +.pure-u-1-12, +.pure-u-2-24 { + width: 8.3333%; + *width: 8.3023%; +} + +.pure-u-1-8, +.pure-u-3-24 { + width: 12.5000%; + *width: 12.4690%; +} + +.pure-u-1-6, +.pure-u-4-24 { + width: 16.6667%; + *width: 16.6357%; +} + +.pure-u-1-5 { + width: 20%; + *width: 19.9690%; +} + +.pure-u-5-24 { + width: 20.8333%; + *width: 20.8023%; +} + +.pure-u-1-4, +.pure-u-6-24 { + width: 25%; + *width: 24.9690%; +} + +.pure-u-7-24 { + width: 29.1667%; + *width: 29.1357%; +} + +.pure-u-1-3, +.pure-u-8-24 { + width: 33.3333%; + *width: 33.3023%; +} + +.pure-u-3-8, +.pure-u-9-24 { + width: 37.5000%; + *width: 37.4690%; +} + +.pure-u-2-5 { + width: 40%; + *width: 39.9690%; +} + +.pure-u-5-12, +.pure-u-10-24 { + width: 41.6667%; + *width: 41.6357%; +} + +.pure-u-11-24 { + width: 45.8333%; + *width: 45.8023%; +} + +.pure-u-1-2, +.pure-u-12-24 { + width: 50%; + *width: 49.9690%; +} + +.pure-u-13-24 { + width: 54.1667%; + *width: 54.1357%; +} + +.pure-u-7-12, +.pure-u-14-24 { + width: 58.3333%; + *width: 58.3023%; +} + +.pure-u-3-5 { + width: 60%; + *width: 59.9690%; +} + +.pure-u-5-8, +.pure-u-15-24 { + width: 62.5000%; + *width: 62.4690%; +} + +.pure-u-2-3, +.pure-u-16-24 { + width: 66.6667%; + *width: 66.6357%; +} + +.pure-u-17-24 { + width: 70.8333%; + *width: 70.8023%; +} + +.pure-u-3-4, +.pure-u-18-24 { + width: 75%; + *width: 74.9690%; +} + +.pure-u-19-24 { + width: 79.1667%; + *width: 79.1357%; +} + +.pure-u-4-5 { + width: 80%; + *width: 79.9690%; +} + +.pure-u-5-6, +.pure-u-20-24 { + width: 83.3333%; + *width: 83.3023%; +} + +.pure-u-7-8, +.pure-u-21-24 { + width: 87.5000%; + *width: 87.4690%; +} + +.pure-u-11-12, +.pure-u-22-24 { + width: 91.6667%; + *width: 91.6357%; +} + +.pure-u-23-24 { + width: 95.8333%; + *width: 95.8023%; +} + +.pure-u-1, +.pure-u-1-1, +.pure-u-5-5, +.pure-u-24-24 { + width: 100%; +} +.pure-button { + /* Structure */ + display: inline-block; + zoom: 1; + line-height: normal; + white-space: nowrap; + vertical-align: middle; + text-align: center; + cursor: pointer; + -webkit-user-drag: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + box-sizing: border-box; +} + +/* Firefox: Get rid of the inner focus border */ +.pure-button::-moz-focus-inner { + padding: 0; + border: 0; +} + +/* Inherit .pure-g styles */ +.pure-button-group { + letter-spacing: -0.31em; /* Webkit: collapse white-space between units */ + *letter-spacing: normal; /* reset IE < 8 */ + *word-spacing: -0.43em; /* IE < 8: collapse white-space between units */ + text-rendering: optimizespeed; /* Webkit: fixes text-rendering: optimizeLegibility */ +} + +.opera-only :-o-prefocus, +.pure-button-group { + word-spacing: -0.43em; +} + +.pure-button-group .pure-button { + letter-spacing: normal; + word-spacing: normal; + vertical-align: top; + text-rendering: auto; +} + +/*csslint outline-none:false*/ + +.pure-button { + font-family: inherit; + font-size: 100%; + padding: 0.5em 1em; + color: #444; /* rgba not supported (IE 8) */ + color: rgba(0, 0, 0, 0.80); /* rgba supported */ + border: 1px solid #999; /*IE 6/7/8*/ + border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/ + background-color: #E6E6E6; + text-decoration: none; + border-radius: 2px; +} + +.pure-button-hover, +.pure-button:hover, +.pure-button:focus { + /* csslint ignore:start */ + filter: alpha(opacity=90); + /* csslint ignore:end */ + background-image: -webkit-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10)); + background-image: linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10)); +} +.pure-button:focus { + outline: 0; +} +.pure-button-active, +.pure-button:active { + box-shadow: 0 0 0 1px rgba(0,0,0, 0.15) inset, 0 0 6px rgba(0,0,0, 0.20) inset; + border-color: #000\9; +} + +.pure-button[disabled], +.pure-button-disabled, +.pure-button-disabled:hover, +.pure-button-disabled:focus, +.pure-button-disabled:active { + border: none; + background-image: none; + /* csslint ignore:start */ + filter: alpha(opacity=40); + /* csslint ignore:end */ + opacity: 0.40; + cursor: not-allowed; + box-shadow: none; + pointer-events: none; +} + +.pure-button-hidden { + display: none; +} + +.pure-button-primary, +.pure-button-selected, +a.pure-button-primary, +a.pure-button-selected { + background-color: rgb(0, 120, 231); + color: #fff; +} + +/* Button Groups */ +.pure-button-group .pure-button { + margin: 0; + border-radius: 0; + border-right: 1px solid #111; /* fallback color for rgba() for IE7/8 */ + border-right: 1px solid rgba(0, 0, 0, 0.2); + +} + +.pure-button-group .pure-button:first-child { + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; +} +.pure-button-group .pure-button:last-child { + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-right: none; +} + +/*csslint box-model:false*/ +/* +Box-model set to false because we're setting a height on select elements, which +also have border and padding. This is done because some browsers don't render +the padding. We explicitly set the box-model for select elements to border-box, +so we can ignore the csslint warning. +*/ + +.pure-form input[type="text"], +.pure-form input[type="password"], +.pure-form input[type="email"], +.pure-form input[type="url"], +.pure-form input[type="date"], +.pure-form input[type="month"], +.pure-form input[type="time"], +.pure-form input[type="datetime"], +.pure-form input[type="datetime-local"], +.pure-form input[type="week"], +.pure-form input[type="number"], +.pure-form input[type="search"], +.pure-form input[type="tel"], +.pure-form input[type="color"], +.pure-form select, +.pure-form textarea { + padding: 0.5em 0.6em; + display: inline-block; + border: 1px solid #ccc; + box-shadow: inset 0 1px 3px #ddd; + border-radius: 4px; + vertical-align: middle; + box-sizing: border-box; +} + +/* +Need to separate out the :not() selector from the rest of the CSS 2.1 selectors +since IE8 won't execute CSS that contains a CSS3 selector. +*/ +.pure-form input:not([type]) { + padding: 0.5em 0.6em; + display: inline-block; + border: 1px solid #ccc; + box-shadow: inset 0 1px 3px #ddd; + border-radius: 4px; + box-sizing: border-box; +} + + +/* Chrome (as of v.32/34 on OS X) needs additional room for color to display. */ +/* May be able to remove this tweak as color inputs become more standardized across browsers. */ +.pure-form input[type="color"] { + padding: 0.2em 0.5em; +} + + +.pure-form input[type="text"]:focus, +.pure-form input[type="password"]:focus, +.pure-form input[type="email"]:focus, +.pure-form input[type="url"]:focus, +.pure-form input[type="date"]:focus, +.pure-form input[type="month"]:focus, +.pure-form input[type="time"]:focus, +.pure-form input[type="datetime"]:focus, +.pure-form input[type="datetime-local"]:focus, +.pure-form input[type="week"]:focus, +.pure-form input[type="number"]:focus, +.pure-form input[type="search"]:focus, +.pure-form input[type="tel"]:focus, +.pure-form input[type="color"]:focus, +.pure-form select:focus, +.pure-form textarea:focus { + outline: 0; + border-color: #129FEA; +} + +/* +Need to separate out the :not() selector from the rest of the CSS 2.1 selectors +since IE8 won't execute CSS that contains a CSS3 selector. +*/ +.pure-form input:not([type]):focus { + outline: 0; + border-color: #129FEA; +} + +.pure-form input[type="file"]:focus, +.pure-form input[type="radio"]:focus, +.pure-form input[type="checkbox"]:focus { + outline: thin solid #129FEA; + outline: 1px auto #129FEA; +} +.pure-form .pure-checkbox, +.pure-form .pure-radio { + margin: 0.5em 0; + display: block; +} + +.pure-form input[type="text"][disabled], +.pure-form input[type="password"][disabled], +.pure-form input[type="email"][disabled], +.pure-form input[type="url"][disabled], +.pure-form input[type="date"][disabled], +.pure-form input[type="month"][disabled], +.pure-form input[type="time"][disabled], +.pure-form input[type="datetime"][disabled], +.pure-form input[type="datetime-local"][disabled], +.pure-form input[type="week"][disabled], +.pure-form input[type="number"][disabled], +.pure-form input[type="search"][disabled], +.pure-form input[type="tel"][disabled], +.pure-form input[type="color"][disabled], +.pure-form select[disabled], +.pure-form textarea[disabled] { + cursor: not-allowed; + background-color: #eaeded; + color: #cad2d3; +} + +/* +Need to separate out the :not() selector from the rest of the CSS 2.1 selectors +since IE8 won't execute CSS that contains a CSS3 selector. +*/ +.pure-form input:not([type])[disabled] { + cursor: not-allowed; + background-color: #eaeded; + color: #cad2d3; +} +.pure-form input[readonly], +.pure-form select[readonly], +.pure-form textarea[readonly] { + background-color: #eee; /* menu hover bg color */ + color: #777; /* menu text color */ + border-color: #ccc; +} + +.pure-form input:focus:invalid, +.pure-form textarea:focus:invalid, +.pure-form select:focus:invalid { + color: #b94a48; + border-color: #e9322d; +} +.pure-form input[type="file"]:focus:invalid:focus, +.pure-form input[type="radio"]:focus:invalid:focus, +.pure-form input[type="checkbox"]:focus:invalid:focus { + outline-color: #e9322d; +} +.pure-form select { + /* Normalizes the height; padding is not sufficient. */ + height: 2.25em; + border: 1px solid #ccc; + background-color: white; +} +.pure-form select[multiple] { + height: auto; +} +.pure-form label { + margin: 0.5em 0 0.2em; +} +.pure-form fieldset { + margin: 0; + padding: 0.35em 0 0.75em; + border: 0; +} +.pure-form legend { + display: block; + width: 50%; + padding: 0.3em 0; + margin-bottom: 0.3em; + margin-left: 5px; + color: #333; + /* border-bottom: 1px solid #e5e5e5; */ + border-bottom: 1px solid #bcf; +} + +.pure-form-stacked input[type="text"], +.pure-form-stacked input[type="password"], +.pure-form-stacked input[type="email"], +.pure-form-stacked input[type="url"], +.pure-form-stacked input[type="date"], +.pure-form-stacked input[type="month"], +.pure-form-stacked input[type="time"], +.pure-form-stacked input[type="datetime"], +.pure-form-stacked input[type="datetime-local"], +.pure-form-stacked input[type="week"], +.pure-form-stacked input[type="number"], +.pure-form-stacked input[type="search"], +.pure-form-stacked input[type="tel"], +.pure-form-stacked input[type="color"], +.pure-form-stacked input[type="file"], +.pure-form-stacked select, +.pure-form-stacked label, +.pure-form-stacked textarea { + display: block; + margin: 0.25em 0; +} + +/* +Need to separate out the :not() selector from the rest of the CSS 2.1 selectors +since IE8 won't execute CSS that contains a CSS3 selector. +*/ +.pure-form-stacked input:not([type]) { + display: block; + margin: 0.25em 0; +} +.pure-form-aligned input, +.pure-form-aligned textarea, +.pure-form-aligned select, +/* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */ +.pure-form-aligned .pure-help-inline, +.pure-form-message-inline { + display: inline-block; + *display: inline; + *zoom: 1; + vertical-align: middle; +} +.pure-form-aligned textarea { + vertical-align: top; +} + +/* Aligned Forms */ +.pure-form-aligned .pure-control-group { + margin-bottom: 0.5em; +} +.pure-form-aligned .pure-control-group label { + text-align: right; + display: inline-block; + vertical-align: middle; + width: 10em; + margin: 0 1em 0 0; +} +.pure-form-aligned .pure-controls { + margin: 1.5em 0 0 11em; +} + +/* Rounded Inputs */ +.pure-form input.pure-input-rounded, +.pure-form .pure-input-rounded { + border-radius: 2em; + padding: 0.5em 1em; +} + +/* Grouped Inputs */ +.pure-form .pure-group fieldset { + margin-bottom: 10px; +} +.pure-form .pure-group input, +.pure-form .pure-group textarea { + display: block; + padding: 10px; + margin: 0 0 -1px; + border-radius: 0; + position: relative; + top: -1px; +} +.pure-form .pure-group input:focus, +.pure-form .pure-group textarea:focus { + z-index: 3; +} +.pure-form .pure-group input:first-child, +.pure-form .pure-group textarea:first-child { + top: 1px; + border-radius: 4px 4px 0 0; + margin: 0; +} +.pure-form .pure-group input:first-child:last-child, +.pure-form .pure-group textarea:first-child:last-child { + top: 1px; + border-radius: 4px; + margin: 0; +} +.pure-form .pure-group input:last-child, +.pure-form .pure-group textarea:last-child { + top: -2px; + border-radius: 0 0 4px 4px; + margin: 0; +} +.pure-form .pure-group button { + margin: 0.35em 0; +} + +.pure-form .pure-input-1 { + width: 100%; +} +.pure-form .pure-input-3-4 { + width: 75%; +} +.pure-form .pure-input-2-3 { + width: 66%; +} +.pure-form .pure-input-1-2 { + width: 50%; +} +.pure-form .pure-input-1-3 { + width: 33%; +} +.pure-form .pure-input-1-4 { + width: 25%; +} + +/* Inline help for forms */ +/* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */ +.pure-form .pure-help-inline, +.pure-form-message-inline { + display: inline-block; + padding-left: 0.3em; + color: #666; + vertical-align: middle; + font-size: 0.875em; +} + +/* Block help for forms */ +.pure-form-message { + display: block; + color: #666; + font-size: 0.875em; +} + +@media only screen and (max-width : 480px) { + .pure-form button[type="submit"] { + margin: 0.7em 0 0; + } + + .pure-form input:not([type]), + .pure-form input[type="text"], + .pure-form input[type="password"], + .pure-form input[type="email"], + .pure-form input[type="url"], + .pure-form input[type="date"], + .pure-form input[type="month"], + .pure-form input[type="time"], + .pure-form input[type="datetime"], + .pure-form input[type="datetime-local"], + .pure-form input[type="week"], + .pure-form input[type="number"], + .pure-form input[type="search"], + .pure-form input[type="tel"], + .pure-form input[type="color"], + .pure-form label { + margin-bottom: 0.3em; + display: block; + } + + .pure-group input:not([type]), + .pure-group input[type="text"], + .pure-group input[type="password"], + .pure-group input[type="email"], + .pure-group input[type="url"], + .pure-group input[type="date"], + .pure-group input[type="month"], + .pure-group input[type="time"], + .pure-group input[type="datetime"], + .pure-group input[type="datetime-local"], + .pure-group input[type="week"], + .pure-group input[type="number"], + .pure-group input[type="search"], + .pure-group input[type="tel"], + .pure-group input[type="color"] { + margin-bottom: 0; + } + + .pure-form-aligned .pure-control-group label { + margin-bottom: 0.3em; + text-align: left; + display: block; + width: 100%; + } + + .pure-form-aligned .pure-controls { + margin: 1.5em 0 0 0; + } + + /* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */ + .pure-form .pure-help-inline, + .pure-form-message-inline, + .pure-form-message { + display: block; + font-size: 0.75em; + /* Increased bottom padding to make it group with its related input element. */ + padding: 0.2em 0 0.8em; + } +} + +/*csslint adjoining-classes: false, box-model:false*/ +.pure-menu { + box-sizing: border-box; +} + +.pure-menu-fixed { + position: fixed; + left: 0; + top: 0; + z-index: 3; +} + +.pure-menu-list, +.pure-menu-item { + position: relative; +} + +.pure-menu-list { + list-style: none; + margin: 0; + padding: 0; +} + +.pure-menu-item { + padding: 0; + margin: 0; + height: 100%; +} + +.pure-menu-link, +.pure-menu-heading { + display: block; + text-decoration: none; + white-space: nowrap; +} + +/* HORIZONTAL MENU */ +.pure-menu-horizontal { + width: 100%; + white-space: nowrap; +} + +.pure-menu-horizontal .pure-menu-list { + display: inline-block; +} + +/* Initial menus should be inline-block so that they are horizontal */ +.pure-menu-horizontal .pure-menu-item, +.pure-menu-horizontal .pure-menu-heading, +.pure-menu-horizontal .pure-menu-separator { + display: inline-block; + *display: inline; + zoom: 1; + vertical-align: middle; +} + +/* Submenus should still be display: block; */ +.pure-menu-item .pure-menu-item { + display: block; +} + +.pure-menu-children { + display: none; + position: absolute; + left: 100%; + top: 0; + margin: 0; + padding: 0; + z-index: 3; +} + +.pure-menu-horizontal .pure-menu-children { + left: 0; + top: auto; + width: inherit; +} + +.pure-menu-allow-hover:hover > .pure-menu-children, +.pure-menu-active > .pure-menu-children { + display: block; + position: absolute; +} + +/* Vertical Menus - show the dropdown arrow */ +.pure-menu-has-children > .pure-menu-link:after { + padding-left: 0.5em; + content: "\25B8"; + font-size: small; +} + +/* Horizontal Menus - show the dropdown arrow */ +.pure-menu-horizontal .pure-menu-has-children > .pure-menu-link:after { + content: "\25BE"; +} + +/* scrollable menus */ +.pure-menu-scrollable { + overflow-y: scroll; + overflow-x: scroll; +} + +.pure-menu-scrollable .pure-menu-list { + display: block; +} + +.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list { + display: inline-block; +} + +.pure-menu-horizontal.pure-menu-scrollable { + white-space: nowrap; + overflow-y: hidden; + overflow-x: auto; + -ms-overflow-style: none; + -webkit-overflow-scrolling: touch; + /* a little extra padding for this style to allow for scrollbars */ + padding: .5em 0; +} + +.pure-menu-horizontal.pure-menu-scrollable::-webkit-scrollbar { + display: none; +} + +/* misc default styling */ + +.pure-menu-separator, +.pure-menu-horizontal .pure-menu-children .pure-menu-separator { + background-color: #ccc; + height: 1px; + margin: .3em 0; +} + +.pure-menu-horizontal .pure-menu-separator { + width: 1px; + height: 1.3em; + margin: 0 .3em ; +} + +/* Need to reset the separator since submenu is vertical */ +.pure-menu-horizontal .pure-menu-children .pure-menu-separator { + display: block; + width: auto; +} + +.pure-menu-heading { + text-transform: uppercase; + color: #565d64; +} + +.pure-menu-link { + /* color: #777; */ +} + +.pure-menu-children { + background-color: #fff; +} + +.pure-menu-link, +.pure-menu-disabled, +.pure-menu-heading { + padding: .5em 1em; +} + +.pure-menu-disabled { + opacity: .5; +} + +.pure-menu-disabled .pure-menu-link:hover { + background-color: transparent; +} + +.pure-menu-active > .pure-menu-link, +.pure-menu-link:hover, +.pure-menu-link:focus { + background-color: #eee; +} + +.pure-menu-selected .pure-menu-link, +.pure-menu-selected .pure-menu-link:visited { + color: #000; +} + +.pure-table { + /* Remove spacing between table cells (from Normalize.css) */ + border-collapse: collapse; + border-spacing: 0; + empty-cells: show; + border: 1px solid #cbcbcb; +} + +.pure-table caption { + color: #000; + font: italic 85%/1 arial, sans-serif; + padding: 1em 0; + text-align: center; +} + +.pure-table td, +.pure-table th { + border-left: 1px solid #cbcbcb;/* inner column border */ + border-width: 0 0 0 1px; + font-size: inherit; + margin: 0; + overflow: visible; /*to make ths where the title is really long work*/ + padding: 0.5em 1em; /* cell padding */ +} + +/* Consider removing this next declaration block, as it causes problems when +there's a rowspan on the first cell. Case added to the tests. issue#432 */ +.pure-table td:first-child, +.pure-table th:first-child { + border-left-width: 0; +} + +.pure-table thead { + background-color: #e0e0e0; + color: #000; + text-align: left; + vertical-align: bottom; +} + +/* +striping: + even - #fff (white) + odd - #f2f2f2 (light gray) +*/ +.pure-table td { + background-color: transparent; +} +.pure-table-odd td { + background-color: #f2f2f2; +} + +/* nth-child selector for modern browsers */ +.pure-table-striped tr:nth-child(2n-1) td { + background-color: #f2f2f2; +} + +/* BORDERED TABLES */ +.pure-table-bordered td { + border-bottom: 1px solid #cbcbcb; +} +.pure-table-bordered tbody > tr:last-child > td { + border-bottom-width: 0; +} + + +/* HORIZONTAL BORDERED TABLES */ + +.pure-table-horizontal td, +.pure-table-horizontal th { + border-width: 0 0 1px 0; + border-bottom: 1px solid #cbcbcb; +} +.pure-table-horizontal tbody > tr:last-child > td { + border-bottom-width: 0; +} + + +/* + * -- HELPER STYLES -- + * Over-riding some of the .pure-button styles to make my buttons look unique + */ +.button-success, +.button-error, +.button-warning, +.button-secondary { + color: white; + border-radius: 4px; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); +} + +.button-success { + background: rgb(28, 184, 65); /* this is a green */ +} + +.button-error { + background: rgb(202, 60, 60); /* this is a maroon */ +} + +.button-warning { + background: rgb(223, 117, 20); /* this is an orange */ +} + +.button-secondary { + background: rgb(66, 184, 221); /* this is a light blue */ +} + + +.custom-restricted { + height: 160px; + width: 150px; + border: 1px solid gray; + border-radius: 4px; +} + diff --git a/OpenRefine/extensions/database/module/styles/theme.less b/OpenRefine/extensions/database/module/styles/theme.less new file mode 100644 index 000000000..443a411bc --- /dev/null +++ b/OpenRefine/extensions/database/module/styles/theme.less @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +@import-less url("../../../../main/webapp/modules/core/styles/theme.less"); diff --git a/OpenRefine/extensions/database/pom.xml b/OpenRefine/extensions/database/pom.xml new file mode 100644 index 000000000..47984c6d2 --- /dev/null +++ b/OpenRefine/extensions/database/pom.xml @@ -0,0 +1,150 @@ + + 4.0.0 + + database + jar + + OpenRefine - Database extension + Connections to SQL databases for import and export + http://openrefine.org/ + + org.openrefine + extensions + 3.6-SNAPSHOT + + + + openrefine-database + + + src + + + tests/src + module/MOD-INF/classes + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.version} + + + tests/conf/tests.xml + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + ${maven-dependency-plugin.version} + + + compile + + copy-dependencies + + + module/MOD-INF/lib + runtime + + + + + + + + + + + ${project.groupId} + main + ${project.version} + provided + + + javax.servlet + javax.servlet-api + ${servlet-api.version} + provided + + + org.postgresql + postgresql + 42.3.1 + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + com.google.http-client + google-http-client-jackson2 + 1.41.2 + + + mysql + mysql-connector-java + 8.0.28 + + + org.jasypt + jasypt + ${jasypt.version} + + + org.mariadb.jdbc + mariadb-java-client + 2.7.5 + + + org.xerial + sqlite-jdbc + 3.36.0.3 + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + provided + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + org.owasp.encoder + encoder + ${owasp-encoder.version} + + + + + + org.testng + testng + ${testng.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + + + + + diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/DBQueryResultImportReader.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DBQueryResultImportReader.java new file mode 100644 index 000000000..0da3fa055 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DBQueryResultImportReader.java @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseQueryInfo; +import com.google.refine.extension.database.model.DatabaseRow; +import com.google.refine.importers.TabularImportingParserBase.TableDataReader; +import com.google.refine.importing.ImportingJob; + + +public class DBQueryResultImportReader implements TableDataReader { + + private static final Logger logger = LoggerFactory.getLogger("DBQueryResultImportReader"); + + private final ImportingJob job; + private final String querySource; + private List dbColumns; + private final int batchSize; + + private int nextRow = 0; // 0-based + private int batchRowStart = 0; // 0-based + private boolean end = false; + private List> rowsOfCells = null; + private boolean usedHeaders = false; + private DatabaseService databaseService; + private DatabaseQueryInfo dbQueryInfo; + private int processedRows = 0; + private static int progress = 0; + + + public DBQueryResultImportReader( + ImportingJob job, + DatabaseService databaseService, + String querySource, + List columns, + DatabaseQueryInfo dbQueryInfo, + int batchSize) { + + this.job = job; + this.querySource = querySource; + this.batchSize = batchSize; + this.dbColumns = columns; + this.databaseService = databaseService; + this.dbQueryInfo = dbQueryInfo; + if(logger.isDebugEnabled()) { + logger.debug("batchSize:" + batchSize); + } + + } + + @Override + public List getNextRowOfCells() throws IOException { + + try { + + if (!usedHeaders) { + List row = new ArrayList(dbColumns.size()); + for (DatabaseColumn cd : dbColumns) { + row.add(cd.getName()); + } + usedHeaders = true; + //logger.info("Exit::getNextRowOfCells return header::row:" + row); + return row; + } + + if (rowsOfCells == null || (nextRow >= batchRowStart + rowsOfCells.size() && !end)) { + int newBatchRowStart = batchRowStart + (rowsOfCells == null ? 0 : rowsOfCells.size()); + rowsOfCells = getRowsOfCells(newBatchRowStart); + processedRows = processedRows + rowsOfCells.size(); + batchRowStart = newBatchRowStart; + setProgress(job, querySource, -1 /* batchRowStart * 100 / totalRows */); + } + + if (rowsOfCells != null && nextRow - batchRowStart < rowsOfCells.size()) { + List result = rowsOfCells.get(nextRow++ - batchRowStart); + if(nextRow >= batchSize) { + rowsOfCells = getRowsOfCells(processedRows); + processedRows = processedRows + rowsOfCells.size(); + + if(logger.isDebugEnabled()) { + logger.debug("[[ Returning last row in batch:nextRow::{}, processedRows:{} ]]", nextRow, processedRows); + } + + nextRow = 0; + if(processedRows % 100 == 0) { + setProgress(job, querySource, progress++); + } + if(processedRows % 10000 == 0) { + if(logger.isDebugEnabled()) { + logger.debug("[[ {} rows processed... ]]",processedRows); + } + } + } + return result; + } else { + if(logger.isDebugEnabled()) { + logger.debug("[[processedRows:{} ]]", processedRows); + } + return null; + } + + + }catch(DatabaseServiceException e) { + logger.error("DatabaseServiceException::{}", e); + throw new IOException(e); + + } + + + } + + /** + * @param startRow + * @return + * @throws IOException + * @throws DatabaseServiceException + */ + private List> getRowsOfCells(int startRow) throws IOException, DatabaseServiceException { + //logger.info("Entry getRowsOfCells::startRow:" + startRow); + + List> rowsOfCells = new ArrayList>(batchSize); + + String query = databaseService.buildLimitQuery(batchSize, startRow, dbQueryInfo.getQuery()); + //logger.info("batchSize::" + batchSize + " startRow::" + startRow + " query::" + query ); + + List dbRows = databaseService.getRows(dbQueryInfo.getDbConfig(), query); + + if(dbRows != null && !dbRows.isEmpty() && dbRows.size() > 0) { + + for(DatabaseRow dbRow: dbRows) { + List row = dbRow.getValues(); + List rowOfCells = new ArrayList(row.size()); + + for (int j = 0; j < row.size() && j < dbColumns.size(); j++) { + + String text = row.get(j); + if (text == null || text.isEmpty()) { + rowOfCells.add(null); + }else { + DatabaseColumn col = dbColumns.get(j); + if(col.getType() == DatabaseColumnType.NUMBER) { + try { + rowOfCells.add(Long.parseLong(text)); + continue; + } catch (NumberFormatException e) {} + + }else if(col.getType() == DatabaseColumnType.DOUBLE || col.getType() == DatabaseColumnType.FLOAT ) { + try { + double d = Double.parseDouble(text); + if (!Double.isInfinite(d) && !Double.isNaN(d)) { + rowOfCells.add(d); + continue; + } + } catch (NumberFormatException e) {} + + } + + rowOfCells.add(text); + } + + } + + rowsOfCells.add(rowOfCells); + + } + + } + end = dbRows.size() < batchSize + 1; + //logger.info("Exit::getRowsOfCells::rowsOfCells:{}", rowsOfCells); + return rowsOfCells; + + } + + private static void setProgress(ImportingJob job, String querySource, int percent) { + job.setProgress(percent, "Reading " + querySource); + } + + public List getColumns() { + return dbColumns; + } + + + public void setColumns(List columns) { + this.dbColumns = columns; + } + + + public int getNextRow() { + return nextRow; + } + + + public void setNextRow(int nextRow) { + this.nextRow = nextRow; + } + + + public int getBatchRowStart() { + return batchRowStart; + } + + + public void setBatchRowStart(int batchRowStart) { + this.batchRowStart = batchRowStart; + } + + + public boolean isEnd() { + return end; + } + + + public void setEnd(boolean end) { + this.end = end; + } + + + public List> getRowsOfCells() { + return rowsOfCells; + } + + + public void setRowsOfCells(List> rowsOfCells) { + this.rowsOfCells = rowsOfCells; + } + + + public boolean isUsedHeaders() { + return usedHeaders; + } + + + public void setUsedHeaders(boolean usedHeaders) { + this.usedHeaders = usedHeaders; + } + + + public ImportingJob getJob() { + return job; + } + + + public String getQuerySource() { + return querySource; + } + + + public int getBatchSize() { + return batchSize; + } + + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/DBQueryResultPreviewReader.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DBQueryResultPreviewReader.java new file mode 100644 index 000000000..95f8a6cf7 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DBQueryResultPreviewReader.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseQueryInfo; +import com.google.refine.extension.database.model.DatabaseRow; +import com.google.refine.importers.TabularImportingParserBase.TableDataReader; +import com.google.refine.importing.ImportingJob; + + +public class DBQueryResultPreviewReader implements TableDataReader { + + private static final Logger logger = LoggerFactory.getLogger("DBQueryResultPreviewReader"); + + private final ImportingJob job; + private final String querySource; + private List dbColumns; + private final int batchSize; + + private int nextRow = 0; // 0-based + private int batchRowStart = 0; // 0-based + private boolean end = false; + private List> rowsOfCells = null; + private boolean usedHeaders = false; + private DatabaseService databaseService; + private DatabaseQueryInfo dbQueryInfo; + + + public DBQueryResultPreviewReader( + ImportingJob job, + DatabaseService databaseService, + String querySource, + List columns, + DatabaseQueryInfo dbQueryInfo, + int batchSize) { + + this.job = job; + this.querySource = querySource; + this.batchSize = batchSize; + this.dbColumns = columns; + this.databaseService = databaseService; + this.dbQueryInfo = dbQueryInfo; + logger.debug("DBQueryResultPreviewReader::batchSize:" + batchSize); + + } + + @Override + public List getNextRowOfCells() throws IOException { + + // logger.info("Entry::getNextRowOfCells"); + + try { + + if (!usedHeaders) { + List row = new ArrayList(dbColumns.size()); + for (DatabaseColumn cd : dbColumns) { + row.add(cd.getName()); + } + usedHeaders = true; + // logger.debug("Exit::getNextRowOfCells return header::row:" + row); + return row; + } + + if (rowsOfCells == null || (nextRow >= batchRowStart + rowsOfCells.size() && !end)) { + int newBatchRowStart = batchRowStart + (rowsOfCells == null ? 0 : rowsOfCells.size()); + rowsOfCells = getRowsOfCells(newBatchRowStart); + batchRowStart = newBatchRowStart; + setProgress(job, querySource, -1 /* batchRowStart * 100 / totalRows */); + // logger.info("getNextRowOfCells:: rowsOfCellsIsNull::rowsOfCells size:" + rowsOfCells.size() + ":batchRowStart:" + batchRowStart + " ::nextRow:" + nextRow); + } + + if (rowsOfCells != null && nextRow - batchRowStart < rowsOfCells.size()) { + //logger.info("Exit::getNextRowOfCells :rowsOfCellsNotNull::rowsOfCells size:" + rowsOfCells.size() + ":batchRowStart:" + batchRowStart + " ::nextRow:" + nextRow); + return rowsOfCells.get(nextRow++ - batchRowStart); + } else { + if(logger.isDebugEnabled()) { + logger.debug("nextRow:{}, batchRowStart:{}", nextRow, batchRowStart); + } + + return null; + } + + + }catch(DatabaseServiceException e) { + logger.error("DatabaseServiceException::preview:{}", e.getMessage()); + IOException ioEx = new IOException(e.getMessage(), e); + throw ioEx; + + } + + } + + /** + * + * @param startRow + * @return + * @throws IOException + * @throws DatabaseServiceException + */ + private List> getRowsOfCells(int startRow) throws IOException, DatabaseServiceException { + //logger.info("Entry getRowsOfCells::startRow:" + startRow); + + List> rowsOfCells = new ArrayList>(batchSize); + + String query = databaseService.buildLimitQuery(batchSize, startRow, dbQueryInfo.getQuery()); + if(logger.isDebugEnabled()) { + logger.debug("batchSize::" + batchSize + " startRow::" + startRow + " query::" + query ); + } + + List dbRows = databaseService.getRows(dbQueryInfo.getDbConfig(), query); + + if(dbRows != null && !dbRows.isEmpty() && dbRows.size() > 0) { + + for(DatabaseRow dbRow: dbRows) { + List row = dbRow.getValues(); + List rowOfCells = new ArrayList(row.size()); + + for (int j = 0; j < row.size() && j < dbColumns.size(); j++) { + + String text = row.get(j); + if (text == null || text.isEmpty()) { + rowOfCells.add(null); + }else { + DatabaseColumn col = dbColumns.get(j); + if(col.getType() == DatabaseColumnType.NUMBER) { + try { + rowOfCells.add(Long.parseLong(text)); + continue; + } catch (NumberFormatException e) {} + + }else if(col.getType() == DatabaseColumnType.DOUBLE || col.getType() == DatabaseColumnType.FLOAT ) { + try { + double d = Double.parseDouble(text); + if (!Double.isInfinite(d) && !Double.isNaN(d)) { + rowOfCells.add(d); + continue; + } + } catch (NumberFormatException e) {} + + } + + rowOfCells.add(text); + } + + } + rowsOfCells.add(rowOfCells); + + } + + } + end = dbRows.size() < batchSize + 1; + //logger.info("Exit::getRowsOfCells::rowsOfCells:{}", rowsOfCells); + return rowsOfCells; + + } + + private static void setProgress(ImportingJob job, String querySource, int percent) { + job.setProgress(percent, "Reading " + querySource); + } + + public List getColumns() { + return dbColumns; + } + + + public void setColumns(List columns) { + this.dbColumns = columns; + } + + + public int getNextRow() { + return nextRow; + } + + + public void setNextRow(int nextRow) { + this.nextRow = nextRow; + } + + + public int getBatchRowStart() { + return batchRowStart; + } + + + public void setBatchRowStart(int batchRowStart) { + this.batchRowStart = batchRowStart; + } + + + public boolean isEnd() { + return end; + } + + + public void setEnd(boolean end) { + this.end = end; + } + + + public List> getRowsOfCells() { + return rowsOfCells; + } + + + public void setRowsOfCells(List> rowsOfCells) { + this.rowsOfCells = rowsOfCells; + } + + + public boolean isUsedHeaders() { + return usedHeaders; + } + + + public void setUsedHeaders(boolean usedHeaders) { + this.usedHeaders = usedHeaders; + } + + + public ImportingJob getJob() { + return job; + } + + + public String getQuerySource() { + return querySource; + } + + + public int getBatchSize() { + return batchSize; + } + + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseColumnType.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseColumnType.java new file mode 100644 index 000000000..79a0c8f3a --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseColumnType.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database; + + +public enum DatabaseColumnType { + + STRING, + NUMBER, + DATETIME, + LOCATION, + BOOLEAN, + DATE, + DOUBLE, + FLOAT + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseConfiguration.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseConfiguration.java new file mode 100644 index 000000000..47dad7f4e --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseConfiguration.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database; + + +public class DatabaseConfiguration { + + private String connectionName; + private String databaseType; + private String databaseHost; + private int databasePort; + private String databaseUser; + private String databasePassword; + private String databaseName; + private String databaseSchema; + + //optional parameters + private boolean useSSL; + + + public String getConnectionName() { + return connectionName; + } + + public void setConnectionName(String connectionName) { + this.connectionName = connectionName; + } + + public String getDatabaseType() { + return databaseType; + } + + public void setDatabaseType(String databaseType) { + this.databaseType = databaseType; + } + + public String getDatabaseHost() { + return databaseHost; + } + + public void setDatabaseHost(String databaseServer) { + this.databaseHost = databaseServer; + } + + public int getDatabasePort() { + return databasePort; + } + + public void setDatabasePort(int databasePort) { + this.databasePort = databasePort; + } + + public String getDatabaseUser() { + return databaseUser; + } + + public void setDatabaseUser(String databaseUser) { + this.databaseUser = databaseUser; + } + + public String getDatabasePassword() { + return databasePassword; + } + + public void setDatabasePassword(String databasePassword) { + this.databasePassword = databasePassword; + } + + public String getDatabaseName() { + return databaseName; + } + + public void setDatabaseName(String initialDatabase) { + this.databaseName = initialDatabase; + } + + public String getDatabaseSchema() { + return databaseSchema; + } + + public void setDatabaseSchema(String initialSchema) { + this.databaseSchema = initialSchema; + } + + + + public boolean isUseSSL() { + return useSSL; + } + + public void setUseSSL(boolean useSSL) { + this.useSSL = useSSL; + } + + @Override + public String toString() { + return "DatabaseConfiguration [connectionName=" + connectionName + ", databaseType=" + databaseType + + ", databaseHost=" + databaseHost + ", databasePort=" + databasePort + ", databaseUser=" + databaseUser + + ", databaseName=" + databaseName + ", databaseSchema=" + + databaseSchema + ", useSSL=" + useSSL + "]"; + } + + + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseImportController.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseImportController.java new file mode 100644 index 000000000..a7126e925 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseImportController.java @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.refine.extension.database; + +import java.io.IOException; +import java.io.Writer; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.refine.ProjectManager; +import com.google.refine.ProjectMetadata; +import com.google.refine.RefineServlet; +import com.google.refine.commands.HttpUtilities; +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseQueryInfo; +import com.google.refine.importers.TabularImportingParserBase; +import com.google.refine.importing.ImportingController; +import com.google.refine.importing.ImportingJob; +import com.google.refine.importing.ImportingManager; +import com.google.refine.model.Project; +import com.google.refine.util.JSONUtilities; +import com.google.refine.util.ParsingUtilities; + + +public class DatabaseImportController implements ImportingController { + + private static final Logger logger = LoggerFactory.getLogger("DatabaseImportController"); + protected RefineServlet servlet; + public static int DEFAULT_PREVIEW_LIMIT = 100; + public static String OPTIONS_KEY = "options"; + + @Override + public void init(RefineServlet servlet) { + this.servlet = servlet; + } + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + HttpUtilities.respond(response, "error", "GET not implemented"); + } + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + if(logger.isDebugEnabled()){ + logger.debug("doPost Query String::{}", request.getQueryString()); + } + response.setCharacterEncoding("UTF-8"); + Properties parameters = ParsingUtilities.parseUrlParameters(request); + + String subCommand = parameters.getProperty("subCommand"); + + if(logger.isDebugEnabled()){ + logger.info("doPost::subCommand::{}", subCommand); + } + + if ("initialize-parser-ui".equals(subCommand)) { + doInitializeParserUI(request, response, parameters); + } else if ("parse-preview".equals(subCommand)) { + try { + + doParsePreview(request, response, parameters); + + } catch (DatabaseServiceException e) { + logger.error("doPost::DatabaseServiceException::{}", e); + HttpUtilities.respond(response, "error", getDbServiceException(e)); + } + } else if ("create-project".equals(subCommand)) { + doCreateProject(request, response, parameters); + } else { + HttpUtilities.respond(response, "error", "No such sub command"); + } + + } + + private String getDbServiceException(Exception ex) { + String message = ""; + if(ex instanceof DatabaseServiceException) { + DatabaseServiceException dbEx = (DatabaseServiceException) ex; + if(dbEx.isSqlException()) { + message = message + dbEx.getSqlCode() + " " + dbEx.getSqlState(); + } + } + message = message + ex.getMessage(); + + return message; + } + + /** + * + * @param request + * @param response + * @param parameters + * @throws ServletException + * @throws IOException + */ + private void doInitializeParserUI(HttpServletRequest request, HttpServletResponse response, Properties parameters) + throws ServletException, IOException { + if(logger.isDebugEnabled()) { + logger.debug("::doInitializeParserUI::"); + } + + + ObjectNode result = ParsingUtilities.mapper.createObjectNode(); + ObjectNode options = ParsingUtilities.mapper.createObjectNode(); + JSONUtilities.safePut(result, "status", "ok"); + JSONUtilities.safePut(result, OPTIONS_KEY, options); + + JSONUtilities.safePut(options, "skipDataLines", 0); + JSONUtilities.safePut(options, "storeBlankRows", true); + JSONUtilities.safePut(options, "storeBlankCellsAsNulls", true); + if(logger.isDebugEnabled()) { + logger.debug("doInitializeParserUI:::{}", result.toString()); + } + + HttpUtilities.respond(response, result.toString()); + + } + + + /** + * doParsePreview + * @param request + * @param response + * @param parameters + * @throws ServletException + * @throws IOException + * @throws DatabaseServiceException + */ + private void doParsePreview( + HttpServletRequest request, HttpServletResponse response, Properties parameters) + throws ServletException, IOException, DatabaseServiceException { + if(logger.isDebugEnabled()) { + logger.debug("JobID::{}", parameters.getProperty("jobID")); + } + + + long jobID = Long.parseLong(parameters.getProperty("jobID")); + ImportingJob job = ImportingManager.getJob(jobID); + if (job == null) { + HttpUtilities.respond(response, "error", "No such import job"); + return; + } + + + DatabaseQueryInfo databaseQueryInfo = getQueryInfo(request); + + + if(databaseQueryInfo == null) { + HttpUtilities.respond(response, "error", "Invalid or missing Query Info"); + } + + job.updating = true; + try { + ObjectNode optionObj = ParsingUtilities.evaluateJsonStringToObjectNode( + request.getParameter("options")); + + List exceptions = new LinkedList(); + + job.prepareNewProject(); + + parsePreview( + databaseQueryInfo, + job.project, + job.metadata, + job, + DEFAULT_PREVIEW_LIMIT , + optionObj, + exceptions + ); + Writer w = response.getWriter(); + JsonGenerator writer = ParsingUtilities.mapper.getFactory().createGenerator(w); + try { + writer.writeStartObject(); + if (exceptions.size() == 0) { + job.project.update(); // update all internal models, indexes, caches, etc. + writer.writeStringField("status", "ok"); + } else { + writer.writeStringField("status", "error"); + writer.writeStringField("message", getExceptionString(exceptions)); + } + writer.writeEndObject(); + } catch (IOException e) { + throw new ServletException(e); + } finally { + writer.flush(); + writer.close(); + w.flush(); + w.close(); + } + + } catch (IOException e) { + throw new ServletException(e); + } finally { + job.touch(); + job.updating = false; + } + } + + + + private String getExceptionString(List exceptions) { + String ex = ""; + for(Exception e: exceptions) { + ex = ex + e.getLocalizedMessage() + "\n"; + } + // TODO Auto-generated method stub + return ex; + } + + /** + * + * @param dbQueryInfo + * @param project + * @param metadata + * @param job + * @param limit + * @param options + * @param exceptions + * @throws DatabaseServiceException + */ + private static void parsePreview( + DatabaseQueryInfo dbQueryInfo, + Project project, + ProjectMetadata metadata, + final ImportingJob job, + int limit, + ObjectNode options, + List exceptions) throws DatabaseServiceException{ + + + DatabaseService databaseService = DatabaseService.get(dbQueryInfo.getDbConfig().getDatabaseType()); + String querySource = getQuerySource(dbQueryInfo); + + List columns = databaseService.getColumns(dbQueryInfo.getDbConfig(), dbQueryInfo.getQuery()); + + + setProgress(job, querySource, -1); + + JSONUtilities.safePut(options, "ignoreLines", 0); // number of blank lines at the beginning to ignore + JSONUtilities.safePut(options, "headerLines", 1); // number of header lines + + + TabularImportingParserBase.readTable( + project, + metadata, + job, + new DBQueryResultPreviewReader(job, databaseService, querySource, columns, dbQueryInfo, 100), + querySource, + limit, + options, + exceptions + ); + + setProgress(job, querySource, 100); + + } + + + /** + * doCreateProject + * @param request + * @param response + * @param parameters + */ + private void doCreateProject(HttpServletRequest request, HttpServletResponse response, Properties parameters) + throws ServletException, IOException{ + if(logger.isDebugEnabled()) { + logger.debug("DatabaseImportController::doCreateProject:::{}", parameters.getProperty("jobID")); + } + + long jobID = Long.parseLong(parameters.getProperty("jobID")); + final ImportingJob job = ImportingManager.getJob(jobID); + if (job == null) { + HttpUtilities.respond(response, "error", "No such import job"); + return; + } + + final DatabaseQueryInfo databaseQueryInfo = getQueryInfo(request); + if(databaseQueryInfo == null) { + HttpUtilities.respond(response, "error", "Invalid or missing Query Info"); + } + + job.updating = true; + try { + final ObjectNode optionObj = ParsingUtilities.evaluateJsonStringToObjectNode( + request.getParameter("options")); + + final List exceptions = new LinkedList(); + + job.setState("creating-project"); + + final Project project = new Project(); + + new Thread() { + @Override + public void run() { + ProjectMetadata pm = new ProjectMetadata(); + pm.setName(JSONUtilities.getString(optionObj, "projectName", "Untitled")); + pm.setEncoding(JSONUtilities.getString(optionObj, "encoding", "UTF-8")); + + try { + parseCreate( + databaseQueryInfo, + project, + pm, + job, + -1, + optionObj, + exceptions + ); + } catch (DatabaseServiceException e) { + logger.error("DatabaseImportController::doCreateProject:::run{}", e); + // throw new RuntimeException("DatabaseServiceException::", e); + } + + if (!job.canceled) { + if (exceptions.size() > 0) { + job.setError(exceptions); + } else { + project.update(); // update all internal models, indexes, caches, etc. + ProjectManager.singleton.registerProject(project, pm); + job.setState("created-project"); + job.setProjectID(project.id); + // logger.info("DatabaseImportController::doCreateProject:::run::projectID :{}", project.id); + } + + job.touch(); + job.updating = false; + } + } + }.start(); + + HttpUtilities.respond(response, "ok", "done"); + } catch (IOException e) { + throw new ServletException(e); + } + } + + + /** + * @param dbQueryInfo + * @param project + * @param metadata + * @param job + * @param limit + * @param options + * @param exceptions + * @throws DatabaseServiceException + */ + private static void parseCreate( + DatabaseQueryInfo dbQueryInfo, + Project project, + ProjectMetadata metadata, + final ImportingJob job, + int limit, + ObjectNode options, + List exceptions) throws DatabaseServiceException{ + + + DatabaseService databaseService = DatabaseService.get(dbQueryInfo.getDbConfig().getDatabaseType()); + String querySource = getQuerySource(dbQueryInfo); + + List columns = databaseService.getColumns(dbQueryInfo.getDbConfig(), dbQueryInfo.getQuery()); + + setProgress(job, querySource, -1); + + JSONUtilities.safePut(options, "ignoreLines", 0); // number of blank lines at the beginning to ignore + JSONUtilities.safePut(options, "headerLines", 1); // number of header lines + + long startTime = System.currentTimeMillis() ; + + TabularImportingParserBase.readTable( + project, + metadata, + job, + new DBQueryResultImportReader(job, databaseService, querySource, columns, dbQueryInfo, getCreateBatchSize()), + querySource, + limit, + options, + exceptions + ); + + long endTime = System.currentTimeMillis() ; + if(logger.isDebugEnabled()) { + logger.debug("Execution Time: {}", endTime - startTime); + } + + setProgress(job, querySource, 100); + + } + + private static int getCreateBatchSize() { + String propBatchSize = DatabaseModuleImpl.getImportCreateBatchSize(); + int batchSize = 100; + if(propBatchSize != null && !propBatchSize.isEmpty()) { + try { + batchSize = Integer.parseInt(propBatchSize); + }catch(NumberFormatException nfe) { + + } + } + return batchSize; + } + + /** + * @param request + * @return + */ + private DatabaseQueryInfo getQueryInfo(HttpServletRequest request) { + DatabaseConfiguration jdbcConfig = new DatabaseConfiguration(); + jdbcConfig.setConnectionName(request.getParameter("connectionName")); + jdbcConfig.setDatabaseType(request.getParameter("databaseType")); + jdbcConfig.setDatabaseHost(request.getParameter("databaseServer")); + try { + jdbcConfig.setDatabasePort(Integer.parseInt(request.getParameter("databasePort"))); + } catch(NumberFormatException nfE) { + logger.error("getQueryInfo :: invalid database port ::{}", nfE); + } + jdbcConfig.setDatabaseUser(request.getParameter("databaseUser")); + jdbcConfig.setDatabasePassword(request.getParameter("databasePassword")); + jdbcConfig.setDatabaseName(request.getParameter("initialDatabase")); + jdbcConfig.setDatabaseSchema(request.getParameter("initialSchema")); + + String query = request.getParameter("query"); + if(logger.isDebugEnabled()) { + logger.debug("jdbcConfig::{}, query::{}", jdbcConfig, query); + } + if (jdbcConfig.getDatabaseHost() == null || jdbcConfig.getDatabaseName() == null + || jdbcConfig.getDatabasePassword() == null || jdbcConfig.getDatabaseType() == null + || jdbcConfig.getDatabaseUser() == null || query == null + || (jdbcConfig.getDatabasePort() == 0 && !"SQLite".equalsIgnoreCase(jdbcConfig.getDatabaseType()))) { + if(logger.isDebugEnabled()) { + logger.debug("Missing Database Configuration::{}", jdbcConfig); + } + return null; + } + + return new DatabaseQueryInfo(jdbcConfig, query); + } + + + private static String getQuerySource(DatabaseQueryInfo dbQueryInfo) { + String dbType = dbQueryInfo.getDbConfig().getDatabaseType(); + return DatabaseService.get(dbType).getDatabaseUrl(dbQueryInfo.getDbConfig()); + } + + + private static void setProgress(ImportingJob job, String querySource, int percent) { + job.setProgress(percent, "Reading " + querySource); + } +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseModuleImpl.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseModuleImpl.java new file mode 100644 index 000000000..b40805238 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseModuleImpl.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.util.Properties; + +import javax.servlet.ServletConfig; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import edu.mit.simile.butterfly.ButterflyModuleImpl; + + +public class DatabaseModuleImpl extends ButterflyModuleImpl { + + private static final Logger logger = LoggerFactory.getLogger("DatabaseModuleImpl"); + + public static DatabaseModuleImpl instance; + + public static Properties extensionProperties; + + private static String DEFAULT_CREATE_PROJ_BATCH_SIZE = "100"; + private static String DEFAULT_PREVIEW_BATCH_SIZE = "100"; + + + + @Override + public void init(ServletConfig config) + throws Exception { + // TODO Auto-generated method stub + super.init(config); + + + readModuleProperty(); + + // Set the singleton. + instance = this; + + logger.trace("Database Extension module initialization completed"); + } + + public static String getImportCreateBatchSize() { + if(extensionProperties == null) { + return DEFAULT_CREATE_PROJ_BATCH_SIZE; + } + return extensionProperties.getProperty("create.batchSize", DEFAULT_CREATE_PROJ_BATCH_SIZE); + } + + public static String getImportPreviewBatchSize() { + if(extensionProperties == null) { + return DEFAULT_PREVIEW_BATCH_SIZE; + } + return extensionProperties.getProperty("preview.batchSize", DEFAULT_PREVIEW_BATCH_SIZE); + } + + private void readModuleProperty() { + // The module path + File f = getPath(); + if(logger.isDebugEnabled()) { + logger.debug("Module getPath(): {}", f.getPath()); + } + + // Load our custom properties. + File modFile = new File(f,"MOD-INF"); + if(logger.isDebugEnabled()) { + logger.debug("Module File: {}", modFile.getPath()); + } + + if (modFile.exists()) { + + extensionProperties = loadProperties (new File(modFile,"dbextension.properties")); + + } + + } + + private Properties loadProperties(File propFile) { + Properties ps = new Properties(); + try { + if (propFile.exists()) { + if(logger.isDebugEnabled()) { + logger.debug("Loading Extension properties ({})", propFile); + } + BufferedInputStream stream = null; + try { + ps = new Properties(); + stream = new BufferedInputStream(new FileInputStream(propFile)); + ps.load(stream); + + } finally { + // Close the stream. + if (stream != null) stream.close(); + } + + } + } catch (Exception e) { + logger.error("Error loading Database properties", e); + } + return ps; + } + + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseService.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseService.java new file mode 100644 index 000000000..f25d5b114 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseService.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database; + +import java.sql.Connection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.refine.extension.database.sqlite.SQLiteDatabaseService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.refine.extension.database.mariadb.MariaDBDatabaseService; +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.extension.database.model.DatabaseRow; +import com.google.refine.extension.database.mysql.MySQLDatabaseService; +import com.google.refine.extension.database.pgsql.PgSQLDatabaseService; + +public abstract class DatabaseService { + + private static final Logger logger = LoggerFactory.getLogger("DatabaseService"); + + + public static class DBType { + private static Map databaseServiceMap = new HashMap(); + + static { + try { + + DatabaseService.DBType.registerDatabase(MySQLDatabaseService.DB_NAME, MySQLDatabaseService.getInstance()); + DatabaseService.DBType.registerDatabase(PgSQLDatabaseService.DB_NAME, PgSQLDatabaseService.getInstance()); + DatabaseService.DBType.registerDatabase(MariaDBDatabaseService.DB_NAME, MariaDBDatabaseService.getInstance()); + DatabaseService.DBType.registerDatabase(SQLiteDatabaseService.DB_NAME, SQLiteDatabaseService.getInstance()); + + } catch (Exception e) { + logger.error("Exception occurred while trying to prepare databases!", e); + } + } + + public static void registerDatabase(String name, DatabaseService db) { + + if (!databaseServiceMap.containsKey(name)) { + //throw new DatabaseServiceException(name + " cannot be registered. Database Type already exists"); + databaseServiceMap.put(name, db); + logger.info(String.format("Registered %s Database", name)); + }else { + if(logger.isDebugEnabled()) { + logger.debug(name + " Database Type already exists"); + } + + } + + } + + public static DatabaseService getJdbcServiceFromType(String name) { + return databaseServiceMap.get(name); + } + + } + + protected String getDatabaseUrl(DatabaseConfiguration dbConfig) { + int port = dbConfig.getDatabasePort(); + return "jdbc:" + dbConfig.getDatabaseType() + "://" + dbConfig.getDatabaseHost() + + ((port == 0) ? "" : (":" + port)) + "/" + dbConfig.getDatabaseName(); + } + + /** + * get Database + * @param dbType + * @return + */ + public static DatabaseService get(String dbType) { + logger.debug("get called on DatabaseService with, {}", dbType); + DatabaseService databaseService = DatabaseService.DBType.getJdbcServiceFromType(dbType.toLowerCase()); + + logger.debug("DatabaseService found: {}", databaseService.getClass()); + return databaseService; + + } + + + //Database Service APIs + public abstract Connection getConnection(DatabaseConfiguration dbConfig) throws DatabaseServiceException; + + public abstract boolean testConnection(DatabaseConfiguration dbConfig) throws DatabaseServiceException; + + public abstract DatabaseInfo connect(DatabaseConfiguration dbConfig) throws DatabaseServiceException; + + public abstract DatabaseInfo executeQuery(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException; + + public abstract DatabaseInfo testQuery(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException; + + public String buildLimitQuery(Integer limit, Integer offset, String query) { + if(logger.isDebugEnabled()) { + logger.info( "<<< original input query::{} >>>" , query ); + } + + final int len = query.length(); + String parsedQuery = len > 0 && query.endsWith(";") ? query.substring(0, len - 1) : query; + + + StringBuilder sb = new StringBuilder(); + sb.append("SELECT * FROM ("); + sb.append(parsedQuery); + sb.append(") data"); + + if(limit != null) { + sb.append(" LIMIT" + " " + limit); + } + + if(offset != null) { + sb.append(" OFFSET" + " " + offset); + } + sb.append(";"); + String parsedQueryOut = sb.toString(); + + if(logger.isDebugEnabled()) { + logger.info( "<<>>" , parsedQueryOut ); + } + + return parsedQueryOut; + } + + public abstract List getColumns(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException; + + public abstract List getRows(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException; + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseServiceException.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseServiceException.java new file mode 100644 index 000000000..cb37f9040 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseServiceException.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database; + +import java.sql.SQLException; + +public class DatabaseServiceException extends Exception { + + + private static final long serialVersionUID = 1L; + + private boolean sqlException; + private String sqlState; + private int sqlCode; + + + public DatabaseServiceException(String exception) { + super(exception); + } + + + public DatabaseServiceException(boolean sqlException, String sqlState, int sqlCode, String message) { + super(message); + this.sqlException = sqlException; + this.sqlState = sqlState; + this.sqlCode = sqlCode; + + } + + + public boolean isSqlException() { + return sqlException; + } + + + public void setSqlException(boolean sqlException) { + this.sqlException = sqlException; + } + + + public String getSqlState() { + return sqlState; + } + + + public void setSqlState(String sqlState) { + this.sqlState = sqlState; + } + + + public int getSqlCode() { + return sqlCode; + } + + + public void setSqlCode(int sqlCode) { + this.sqlCode = sqlCode; + } + + public DatabaseServiceException(String string, SQLException e) { + super(string, e); + } + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseUtils.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseUtils.java new file mode 100644 index 000000000..a5d0a06bd --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/DatabaseUtils.java @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.refine.ProjectManager; +import com.google.refine.io.FileProjectManager; + +public class DatabaseUtils { + + private static final Logger logger = LoggerFactory.getLogger("DatabaseUtils"); + + + public final static String DATABASE_EXTENSION_DIR = "dbextension"; + public final static String SETTINGS_FILE_NAME = ".saved-db-connections.json"; + public final static String SAVED_CONNECTION_KEY = "savedConnections"; + + private static SimpleTextEncryptor textEncryptor = new SimpleTextEncryptor("Aa1Gb@tY7_Y"); + + + public static int getSavedConnectionsSize() { + List scList = getSavedConnections(); + if(scList == null || scList.isEmpty()) { + return 0; + } + + return scList.size(); + } + /** + * GET saved connections + * @return + */ + public static List getSavedConnections() { + ObjectMapper mapper = new ObjectMapper(); + try { + String filename = getExtensionFilePath(); + + File file = new File(filename); + if (!file.exists()) { + //logger.debug("saved connections file not found, creating new: {}", filename); + + String dirPath = getExtensionFolder(); + File dirFile = new File(dirPath); + boolean dirExists = true; + if(!dirFile.exists()) { + dirExists = dirFile.mkdir(); + } + + if(dirExists) { + + SavedConnectionContainer sc = new SavedConnectionContainer(new ArrayList()); + mapper.writerWithDefaultPrettyPrinter().writeValue(new File(filename), sc); + return sc.getSavedConnections(); + //return decryptAll(sc.getSavedConnections()); + + } + + } + //logger.debug("saved connections file found {}", filename); + SavedConnectionContainer savedConnectionContainer = mapper.readValue(new File(filename), SavedConnectionContainer.class); + //return decryptAll(savedConnectionContainer.getSavedConnections()); + return savedConnectionContainer.getSavedConnections(); + + } catch (JsonParseException e) { + logger.error("JsonParseException: {}", e); + } catch (JsonMappingException e) { + logger.error("JsonMappingException: {}", e); + } catch (IOException e) { + logger.error("IOException: {}", e); + } + return null; + } + + + + + + /** + * GET one saved connection + * @param connectionName + * @return + */ + public static DatabaseConfiguration getSavedConnection(String connectionName) { + //logger.debug("get saved connection called with connectionName: {}", connectionName); + List savedConfigurations = getSavedConnections(); + + for (DatabaseConfiguration dc : savedConfigurations) { + //logger.debug("Saved Connection : {}", dc.getConnectionName()); + if (dc.getConnectionName().equalsIgnoreCase(connectionName.trim())) { + //logger.debug("Saved Connection Found : {}", dc); + //dc.setDatabasePassword(decrypt(dc.getDatabasePassword())); + return dc; + } + } + + return null; + } + + public static String encrypt(String plainPassword) { + return textEncryptor.encrypt(plainPassword); + } + + public static String decrypt(String encodedPassword) { + return textEncryptor.decrypt(encodedPassword); + } + + public static List decryptAll(List savedConnections) { + List dbConfigs = new ArrayList(savedConnections.size()); + + for(DatabaseConfiguration d: savedConnections) { + d.setDatabasePassword(decrypt(d.getDatabasePassword())); + dbConfigs.add(d); + + } + return dbConfigs; + } + + + /** + * ADD to saved connections + * @param dbConfig + */ + public static void addToSavedConnections(DatabaseConfiguration dbConfig){ + + try { + ObjectMapper mapper = new ObjectMapper(); + String savedConnectionFile = getExtensionFilePath(); + SavedConnectionContainer savedConnectionContainer = mapper.readValue(new File(savedConnectionFile), SavedConnectionContainer.class); + savedConnectionContainer.getSavedConnections().add(dbConfig); + + mapper.writerWithDefaultPrettyPrinter().writeValue(new File(savedConnectionFile), savedConnectionContainer); + + } catch (JsonGenerationException e1) { + logger.error("JsonGenerationException: {}", e1); + // e1.printStackTrace(); + } catch (JsonMappingException e1) { + logger.error("JsonMappingException: {}", e1); + // e1.printStackTrace(); + } catch (IOException e1) { + logger.error("IOException: {}", e1); + // e1.printStackTrace(); + } + } + + + public static void deleteAllSavedConnections() { + if(logger.isDebugEnabled()) { + logger.debug("delete All Saved Connections called..."); + } + + try { + + List savedConnections = getSavedConnections(); + if(logger.isDebugEnabled()) { + logger.debug("Size before delete SavedConnections :: {}", savedConnections.size()); + } + + ArrayList newSavedConns = new ArrayList(); + + ObjectMapper mapper = new ObjectMapper(); + String savedConnectionFile = getExtensionFilePath(); + SavedConnectionContainer savedConnectionContainer = mapper.readValue(new File(savedConnectionFile), SavedConnectionContainer.class); + savedConnectionContainer.setSavedConnections(newSavedConns); + + if(logger.isDebugEnabled()) { + logger.debug("Size after delete SavedConnections :: {}", savedConnectionContainer.getSavedConnections().size()); + } + mapper.writerWithDefaultPrettyPrinter().writeValue(new File(savedConnectionFile), savedConnectionContainer); + + } catch (JsonGenerationException e1) { + logger.error("JsonGenerationException: {}", e1); + // e1.printStackTrace(); + } catch (JsonMappingException e1) { + logger.error("JsonMappingException: {}", e1); + // e1.printStackTrace(); + } catch (IOException e1) { + logger.error("IOException: {}", e1); + // e1.printStackTrace(); + } + + } + + /** + * DELETE saved connections + * @param connectionName + */ + public static void deleteSavedConnections(String connectionName) { + if(logger.isDebugEnabled()) { + logger.debug("deleteSavedConnections called with: {}", connectionName); + } + + try { + + List savedConnections = getSavedConnections();; + if(logger.isDebugEnabled()) { + logger.debug("Size before delete SavedConnections :: {}", savedConnections.size()); + } + + ArrayList newSavedConns = new ArrayList(); + for(DatabaseConfiguration dc: savedConnections) { + if(!dc.getConnectionName().equalsIgnoreCase(connectionName.trim())) { + newSavedConns.add(dc); + } + + } + + ObjectMapper mapper = new ObjectMapper(); + String savedConnectionFile = getExtensionFilePath(); + SavedConnectionContainer savedConnectionContainer = mapper.readValue(new File(savedConnectionFile), SavedConnectionContainer.class); + savedConnectionContainer.setSavedConnections(newSavedConns); + + if(logger.isDebugEnabled()) { + logger.debug("Size after delete SavedConnections :: {}", savedConnectionContainer.getSavedConnections().size()); + } + mapper.writerWithDefaultPrettyPrinter().writeValue(new File(savedConnectionFile), savedConnectionContainer); + + } catch (JsonGenerationException e1) { + logger.error("JsonGenerationException: {}", e1); + // e1.printStackTrace(); + } catch (JsonMappingException e1) { + logger.error("JsonMappingException: {}", e1); + // e1.printStackTrace(); + } catch (IOException e1) { + logger.error("IOException: {}", e1); + // e1.printStackTrace(); + } + } + + /** + * EDIT saved connections + * @param jdbcConfig + */ + public static void editSavedConnections(DatabaseConfiguration jdbcConfig) { + if(logger.isDebugEnabled()) { + logger.debug("Edit SavedConnections called with: {}", jdbcConfig); + } + + + try { + ObjectMapper mapper = new ObjectMapper(); + String savedConnectionFile = getExtensionFilePath(); + SavedConnectionContainer savedConnectionContainer = mapper.readValue(new File(savedConnectionFile), SavedConnectionContainer.class); + + List savedConnections = savedConnectionContainer.getSavedConnections(); + + ListIterator savedConnArrayIter = (ListIterator) savedConnections.listIterator(); + + while (savedConnArrayIter.hasNext()) { + DatabaseConfiguration sc = (DatabaseConfiguration) savedConnArrayIter.next(); + + if (sc.getConnectionName().equals(jdbcConfig.getConnectionName())) { + savedConnArrayIter.remove(); + } + + } + + savedConnections.add(jdbcConfig); + savedConnectionContainer.setSavedConnections(savedConnections); + + mapper.writerWithDefaultPrettyPrinter().writeValue(new File(savedConnectionFile), savedConnectionContainer); + + } catch (JsonGenerationException e1) { + logger.error("JsonGenerationException: {}", e1); + e1.printStackTrace(); + } catch (JsonMappingException e1) { + logger.error("JsonMappingException: {}", e1); + e1.printStackTrace(); + } catch (IOException e1) { + logger.error("IOException: {}", e1); + e1.printStackTrace(); + } + } + + public static String getExtensionFilePath(){ + File dir = ((FileProjectManager) ProjectManager.singleton).getWorkspaceDir(); + String fileSep = System.getProperty("file.separator"); + String filename = dir.getPath() + fileSep + DATABASE_EXTENSION_DIR + fileSep + SETTINGS_FILE_NAME; + + logger.debug("** extension file name: {} **", filename); + return filename; + } + public static String getExtensionFolder(){ + File dir = ((FileProjectManager) ProjectManager.singleton).getWorkspaceDir(); + String fileSep = System.getProperty("file.separator"); + String filename = dir.getPath() + fileSep + DATABASE_EXTENSION_DIR; + return filename; + } + + public static DatabaseColumnType getDbColumnType(int dbColumnType) { + + switch (dbColumnType) { + case java.sql.Types.BIGINT: + return DatabaseColumnType.NUMBER; + case java.sql.Types.FLOAT: + return DatabaseColumnType.FLOAT; + case java.sql.Types.REAL: + return DatabaseColumnType.DOUBLE; + case java.sql.Types.DOUBLE: + return DatabaseColumnType.DOUBLE; + case java.sql.Types.NUMERIC: + return DatabaseColumnType.NUMBER; + case java.sql.Types.DECIMAL: + return DatabaseColumnType.STRING; + case java.sql.Types.CHAR: + return DatabaseColumnType.STRING; + case java.sql.Types.VARCHAR: + return DatabaseColumnType.STRING; + case java.sql.Types.LONGVARCHAR: + return DatabaseColumnType.STRING; + case java.sql.Types.DATE: + return DatabaseColumnType.DATE; + case java.sql.Types.TIME: + return DatabaseColumnType.DATETIME; + case java.sql.Types.TIMESTAMP: + return DatabaseColumnType.DATETIME; + case java.sql.Types.BINARY: + return DatabaseColumnType.STRING; + case java.sql.Types.VARBINARY: + return DatabaseColumnType.STRING; + case java.sql.Types.LONGVARBINARY: + return DatabaseColumnType.STRING; + case java.sql.Types.NULL: + return DatabaseColumnType.STRING; + case java.sql.Types.OTHER: + return DatabaseColumnType.STRING; + case java.sql.Types.JAVA_OBJECT: + return DatabaseColumnType.STRING; + case java.sql.Types.DISTINCT: + return DatabaseColumnType.STRING; + case java.sql.Types.STRUCT: + return DatabaseColumnType.STRING; + case java.sql.Types.ARRAY: + return DatabaseColumnType.STRING; + case java.sql.Types.BLOB: + return DatabaseColumnType.STRING; + case java.sql.Types.CLOB: + return DatabaseColumnType.STRING; + case java.sql.Types.REF: + return DatabaseColumnType.STRING; + case java.sql.Types.BOOLEAN: + return DatabaseColumnType.BOOLEAN; + case java.sql.Types.INTEGER: + return DatabaseColumnType.NUMBER; + + default: + return DatabaseColumnType.STRING; + } + + } + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/SQLType.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/SQLType.java new file mode 100644 index 000000000..2871b6abd --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/SQLType.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database; + + + +import java.util.HashMap; +import java.util.Map; + + +public final class SQLType { + + private static final Map jdbcDriverRegistry = new HashMap(); + private final DriverContainer driverContainer; + + private SQLType(DriverContainer container) { + this.driverContainer = container; + } + + public static SQLType forName(String name) { + for (SQLType sqlType : jdbcDriverRegistry.values()) { + if (sqlType.getIdentifier().equalsIgnoreCase(name)) { + return sqlType; + } + } + return null; + } + + public static SQLType registerSQLDriver(String identifier, String classpath) { + return registerSQLDriver(identifier, classpath, true); + } + + public static SQLType registerSQLDriver(String identifier, String classpath, boolean useJDBCManager) { + DriverContainer driverContainer = new DriverContainer(identifier, classpath, useJDBCManager); + if (!jdbcDriverRegistry.containsKey(driverContainer)) { + SQLType newType = new SQLType(driverContainer); + jdbcDriverRegistry.put(driverContainer, newType); + return newType; + } + return null; + } + + + public String getClassPath() { + return this.driverContainer.classpath; + } + + public String getIdentifier() { + return this.driverContainer.identifier; + } + + public boolean usesJDBCManager() { + return this.driverContainer.useJDBCManager; + } + + + private static class DriverContainer { + + public final String classpath; + public final String identifier; + public final boolean useJDBCManager; + + private DriverContainer(String identifier, String classpath, boolean useJDBCManager) { + this.classpath = classpath; + this.identifier = identifier; + this.useJDBCManager = useJDBCManager; + } + + public final boolean equals(Object obj) { + return obj instanceof DriverContainer && ((DriverContainer) obj).classpath.equals(this.classpath) + && ((DriverContainer) obj).identifier.equals(this.identifier) + && ((DriverContainer) obj).useJDBCManager == this.useJDBCManager; + } + } +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/SavedConnectionContainer.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/SavedConnectionContainer.java new file mode 100644 index 000000000..15a45f731 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/SavedConnectionContainer.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database; + +import java.util.List; + +public class SavedConnectionContainer { + private List savedConnections; + + public List getSavedConnections() { + return savedConnections; + } + + + public void setSavedConnections(List savedConnections) { + this.savedConnections = savedConnections; + } + + + + public SavedConnectionContainer(List savedConnections) { + super(); + this.savedConnections = savedConnections; + } + + + public SavedConnectionContainer() { + + } + + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/SimpleTextEncryptor.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/SimpleTextEncryptor.java new file mode 100644 index 000000000..ad5f20d95 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/SimpleTextEncryptor.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database; + +import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; +import org.jasypt.util.text.TextEncryptor; + + +public class SimpleTextEncryptor implements TextEncryptor { + + private final StandardPBEStringEncryptor encryptor; + + @Override + public String decrypt(String encryptedMessage) { + return this.encryptor.decrypt(encryptedMessage); + } + + @Override + public String encrypt(String message) { + return this.encryptor.encrypt(message); + } + + public SimpleTextEncryptor(String passwordChars) { + super(); + + this.encryptor = new StandardPBEStringEncryptor(); + this.encryptor.setAlgorithm("PBEWithMD5AndDES"); + this.encryptor.setPasswordCharArray(passwordChars.toCharArray()); + } + + + + public void setPassword(final String password) { + this.encryptor.setPassword(password); + } + + + /** + * Sets a password, as a char[] + * + * @since 1.8 + * @param password the password to be set. + */ + public void setPasswordCharArray(final char[] password) { + this.encryptor.setPasswordCharArray(password); + } + + + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/ConnectCommand.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/ConnectCommand.java new file mode 100644 index 000000000..0e1fa1e6a --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/ConnectCommand.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.cmd; + +import java.io.IOException; +import java.io.Writer; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.http.HttpStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; +//import com.google.refine.ProjectManager; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.util.ParsingUtilities; + + +public class ConnectCommand extends DatabaseCommand { + + private static final Logger logger = LoggerFactory.getLogger("ConnectCommand"); + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + if(!hasValidCSRFToken(request)) { + respondCSRFError(response); + return; + } + + DatabaseConfiguration databaseConfiguration = getJdbcConfiguration(request); + if(logger.isDebugEnabled()) { + logger.debug("ConnectCommand::Post::{}", databaseConfiguration); + } + // ProjectManager.singleton.setBusy(true); + try { + + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Type", "application/json"); + Writer w = response.getWriter(); + JsonGenerator writer = ParsingUtilities.mapper.getFactory().createGenerator(w); + ObjectMapper mapperObj = new ObjectMapper(); + + try { + DatabaseInfo databaseInfo = DatabaseService.get(databaseConfiguration.getDatabaseType()) + .connect(databaseConfiguration); + String databaseInfoString = mapperObj.writeValueAsString(databaseInfo); + response.setStatus(HttpStatus.SC_OK); + writer.writeStartObject(); + writer.writeStringField("code", "ok"); + writer.writeStringField("databaseInfo", databaseInfoString); + writer.writeEndObject(); + + } catch (DatabaseServiceException e) { + logger.error("ConnectCommand::Post::DatabaseServiceException::{}", e); + sendError(HttpStatus.SC_UNAUTHORIZED,response, e); + }catch (Exception e) { + logger.error("ConnectCommand::Post::Exception::{}", e); + sendError(HttpStatus.SC_UNAUTHORIZED,response, e); + } finally { + writer.flush(); + writer.close(); + w.close(); + } + } catch (Exception e) { + logger.error("ConnectCommand::Post::Exception::{}", e); + throw new ServletException(e); + } +// finally { +// // ProjectManager.singleton.setBusy(false); +// } + + + } + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/DatabaseCommand.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/DatabaseCommand.java new file mode 100644 index 000000000..171dccac1 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/DatabaseCommand.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.cmd; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.refine.commands.Command; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseServiceException; + +public abstract class DatabaseCommand extends Command { + + private static final Logger logger = LoggerFactory.getLogger("DatabaseCommand"); + + /** + * + * @param request + * @return + */ + protected DatabaseConfiguration getJdbcConfiguration(HttpServletRequest request) { + DatabaseConfiguration jdbcConfig = new DatabaseConfiguration(); + + jdbcConfig.setConnectionName(request.getParameter("connectionName")); + jdbcConfig.setDatabaseType(request.getParameter("databaseType")); + jdbcConfig.setDatabaseHost(request.getParameter("databaseServer")); + + String dbPort = request.getParameter("databasePort"); + if(dbPort != null) { + try { + jdbcConfig.setDatabasePort(Integer.parseInt(dbPort)); + }catch(NumberFormatException nfe) {} + } + + jdbcConfig.setDatabaseUser(request.getParameter("databaseUser")); + jdbcConfig.setDatabasePassword(request.getParameter("databasePassword")); + jdbcConfig.setDatabaseName(request.getParameter("initialDatabase")); + jdbcConfig.setDatabaseSchema(request.getParameter("initialSchema")); + + if(logger.isDebugEnabled()) { + logger.debug("JDBC Configuration: {}", jdbcConfig); + } + return jdbcConfig; + } + /** + * + * @param status + * @param response + * @param writer + * @param e + * @throws IOException + */ + protected void sendError(int status, HttpServletResponse response, Exception e) + throws IOException { + + //logger.info("sendError::{}", writer); + response.sendError(status, e.getMessage()); + + } + /** + * + * @param status + * @param response + * @param writer + * @param e + * @throws IOException + */ + protected void sendError(int status, HttpServletResponse response, DatabaseServiceException e) + throws IOException { + + String message = ""; + + if(e.getSqlState() != null) { + + message = message + "SqlCode:" + e.getSqlCode() + "SqlState" + e.getSqlState(); + } + + message = message + e.getMessage(); + + response.sendError(status, e.getMessage()); + + } + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/ExecuteQueryCommand.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/ExecuteQueryCommand.java new file mode 100644 index 000000000..863ec9423 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/ExecuteQueryCommand.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.cmd; + +import java.io.IOException; +import java.io.Writer; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.http.HttpStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; +//import com.google.refine.ProjectManager; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.util.ParsingUtilities; + + +public class ExecuteQueryCommand extends DatabaseCommand { + + private static final Logger logger = LoggerFactory.getLogger("ExecuteQueryCommand"); + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + if(!hasValidCSRFToken(request)) { + respondCSRFError(response); + return; + } + + DatabaseConfiguration databaseConfiguration = getJdbcConfiguration(request); + String query = request.getParameter("queryString"); + if(logger.isDebugEnabled()) { + logger.debug("QueryCommand::Post::DatabaseConfiguration::{}::Query::{} " ,databaseConfiguration, query); + } + + //ProjectManager.singleton.setBusy(true); + try { + + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Type", "application/json"); + Writer w = response.getWriter(); + JsonGenerator writer = ParsingUtilities.mapper.getFactory().createGenerator(w); + + try { + DatabaseInfo databaseInfo = DatabaseService.get(databaseConfiguration.getDatabaseType()) + .executeQuery(databaseConfiguration, query); + ObjectMapper mapperObj = new ObjectMapper(); + + response.setStatus(HttpStatus.SC_OK); + String jsonStr = mapperObj.writeValueAsString(databaseInfo); + + if(logger.isDebugEnabled()) { + logger.debug("QueryCommand::Post::Result::{} " ,jsonStr); + } + + + writer.writeStartObject(); + writer.writeStringField("code", "ok"); + writer.writeStringField("QueryResult", jsonStr); + writer.writeEndObject(); + + + } catch (DatabaseServiceException e) { + logger.error("QueryCommand::Post::DatabaseServiceException::{}", e); + sendError(HttpStatus.SC_BAD_REQUEST, response, e); + + } catch (Exception e) { + logger.error("QueryCommand::Post::Exception::{}", e); + sendError(HttpStatus.SC_BAD_REQUEST,response, e); + } finally { + writer.flush(); + writer.close(); + w.close(); + } + } catch (Exception e) { + logger.error("QueryCommand::Post::Exception::{}", e); + throw new ServletException(e); + } +// finally { +// // ProjectManager.singleton.setBusy(false); +// } + + + } + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/SavedConnectionCommand.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/SavedConnectionCommand.java new file mode 100644 index 000000000..80e4955d2 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/SavedConnectionCommand.java @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.cmd; + +import java.io.IOException; +import java.io.Writer; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.http.HttpStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseUtils; +import com.google.refine.util.ParsingUtilities; + + +public class SavedConnectionCommand extends DatabaseCommand { + + private static final Logger logger = LoggerFactory.getLogger("SavedConnectionCommand"); + + private static final Pattern CONN_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9._-]*"); + private static final Pattern DATABASE_PORT_PATTERN = Pattern.compile("^[0-9]*"); + + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + if(logger.isDebugEnabled()) { + logger.debug("SavedConnectionCommand::Get::connectionName::{}", request.getParameter("connectionName")); + } + + String connectionName = request.getParameter("connectionName"); + try { + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Type", "application/json"); + if(connectionName == null || connectionName.isEmpty()) { + writeSavedConnectionResponse(response); + }else { + + DatabaseConfiguration savedConnection = DatabaseUtils.getSavedConnection(connectionName); + writeSavedConnectionResponse(response, savedConnection); + + } + + } catch (Exception e) { + logger.error("Exception while loading settings {}", e); + } + } + + + @Override + public void doDelete(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + + if(logger.isDebugEnabled()) { + logger.debug("SavedConnectionCommand::Delete Connection: {}", request.getParameter("connectionName")); + } + + String connectionName = request.getParameter("connectionName"); + + DatabaseConfiguration savedConn = DatabaseUtils.getSavedConnection(connectionName); + if(savedConn == null) { + //logger.error("Connection With name:: {} does not exist!", request.getParameter("connectionName")); + response.sendError(HttpStatus.SC_BAD_REQUEST, "Connection with name " + connectionName + " does not exists!"); + response.flushBuffer(); + return; + } + + try { + + DatabaseUtils.deleteSavedConnections(connectionName); + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Type", "application/json"); + + writeSavedConnectionResponse(response); + + } catch (Exception e) { + logger.error("Exception while Deleting Connection with name: {}, error:{}",connectionName, e); + } + } + + /** + * + * @param response + * @param savedConnection + * @throws IOException + * @throws JSONException + */ + private void writeSavedConnectionResponse(HttpServletResponse response, DatabaseConfiguration savedConnection) throws IOException { + Writer w = response.getWriter(); + try { + JsonGenerator writer = ParsingUtilities.mapper.getFactory().createGenerator(w); + + writer.writeStartObject(); + writer.writeArrayFieldStart(DatabaseUtils.SAVED_CONNECTION_KEY); + + writer.writeStartObject(); + + + writer.writeStringField("connectionName", savedConnection.getConnectionName()); + writer.writeStringField("databaseType", savedConnection.getDatabaseType()); + writer.writeStringField("databaseHost", savedConnection.getDatabaseHost()); + writer.writeNumberField("databasePort", savedConnection.getDatabasePort()); + writer.writeStringField("databaseName", savedConnection.getDatabaseName()); + + + String dbPasswd = savedConnection.getDatabasePassword(); + if(dbPasswd != null && !dbPasswd.isEmpty()) { + dbPasswd = DatabaseUtils.decrypt(savedConnection.getDatabasePassword()); + } + writer.writeStringField("databasePassword", dbPasswd); + writer.writeStringField("databaseSchema", savedConnection.getDatabaseSchema()); + writer.writeStringField("databaseUser", savedConnection.getDatabaseUser()); + + + writer.writeEndObject(); + writer.writeEndArray(); + + writer.writeEndObject(); + writer.flush(); + writer.close(); + + }finally { + w.flush(); + w.close(); + } + + } + /** + * + * @param response + * @throws IOException + * @throws JSONException + */ + private void writeSavedConnectionResponse(HttpServletResponse response) throws IOException { + Writer w = response.getWriter(); + try { + + List savedConnections = DatabaseUtils.getSavedConnections(); + JsonGenerator writer = ParsingUtilities.mapper.getFactory().createGenerator(w); + + writer.writeStartObject(); + writer.writeArrayFieldStart(DatabaseUtils.SAVED_CONNECTION_KEY); + + int size = savedConnections.size(); + + for (int i = 0; i < size; i++) { + + writer.writeStartObject(); + DatabaseConfiguration dbConfig = (DatabaseConfiguration) savedConnections.get(i); + + writer.writeStringField("connectionName", dbConfig.getConnectionName()); + + writer.writeStringField("databaseType", dbConfig.getDatabaseType()); + + writer.writeStringField("databaseHost", dbConfig.getDatabaseHost()); + + writer.writeNumberField("databasePort", dbConfig.getDatabasePort()); + + writer.writeStringField("databaseName", dbConfig.getDatabaseName()); + + + String dbPasswd = dbConfig.getDatabasePassword(); + if(dbPasswd != null && !dbPasswd.isEmpty()) { + dbPasswd = DatabaseUtils.decrypt(dbConfig.getDatabasePassword()); + } + // writer.value(dbConfig.getDatabasePassword()); + writer.writeStringField("databasePassword", dbPasswd); + + writer.writeStringField("databaseSchema", dbConfig.getDatabaseSchema()); + + writer.writeStringField("databaseUser", dbConfig.getDatabaseUser()); + + writer.writeEndObject(); + + } + writer.writeEndArray(); + writer.writeEndObject(); + writer.flush(); + writer.close(); + // logger.info("Saved Connection Get Response sent"); + } finally { + w.flush(); + w.close(); + } + } + + /** + * Add a new Saved JDBC connection configuration + */ + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + if(!hasValidCSRFToken(request)) { + respondCSRFError(response); + return; + } + + if(logger.isDebugEnabled()) { + logger.debug("doPost Connection: {}", request.getParameter("connectionName")); + } + + + DatabaseConfiguration jdbcConfig = getJdbcConfiguration(request); + + + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Type", "application/json"); + + if(jdbcConfig.getConnectionName() == null) { + response.sendError(HttpStatus.SC_BAD_REQUEST, "Connection Name is Required!"); + response.flushBuffer(); + return; + } + + if(!validateInput(jdbcConfig.getConnectionName(), CONN_NAME_PATTERN)) { + logger.warn("Invalid Connection Name: {}", jdbcConfig.getConnectionName()); + response.sendError(HttpStatus.SC_BAD_REQUEST, "Connection Name is Invalid. Expecting [a-zA-Z0-9._-]"); + response.flushBuffer(); + return; + } + + if(!validateInput("" + jdbcConfig.getDatabasePort(), DATABASE_PORT_PATTERN)) { + logger.warn("Invalid Database Port: {}", jdbcConfig.getDatabasePort()); + response.sendError(HttpStatus.SC_BAD_REQUEST, "Database Port Invalid. Expecting Numeric values only"); + response.flushBuffer(); + return; + } + + + DatabaseConfiguration savedConn = DatabaseUtils.getSavedConnection(jdbcConfig.getConnectionName()); + if(savedConn != null) { + response.sendError(HttpStatus.SC_BAD_REQUEST, "Connection with name " + jdbcConfig.getConnectionName() + " already exists!"); + response.flushBuffer(); + return; + } + + + if(jdbcConfig.getDatabasePassword() != null) { + //logger.debug("SavedConnectionCommand::Post::password::{}", jdbcConfig.getDatabasePassword()); + jdbcConfig.setDatabasePassword(DatabaseUtils.encrypt(jdbcConfig.getDatabasePassword())); + } + + DatabaseUtils.addToSavedConnections(jdbcConfig); + + try { + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Type", "application/json"); + + writeSavedConnectionResponse(response); + } catch (Exception e) { + logger.error("Exception while loading settings {}", e); + } + + } + + private boolean validateInput(String input, Pattern pattern){ + Matcher matcher = pattern.matcher(input); + if(matcher.matches()){ + return true; + } + return false; + } + + @Override + public void doPut(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + + if(logger.isDebugEnabled()) { + logger.debug("databaseType::{} " , request.getParameter("databaseHost")); + } + // logger.info("databaseHost::{} " , request.getParameter("databaseServer")); + + DatabaseConfiguration jdbcConfig = getJdbcConfiguration(request); + StringBuilder sb = new StringBuilder(); + boolean error = false; + if(jdbcConfig.getConnectionName() == null) { + sb.append("Connection Name, "); + error = true; + } + if(jdbcConfig.getDatabaseHost() == null) { + sb.append("Database Host, "); + error = true; + } + if(jdbcConfig.getDatabaseUser() == null) { + sb.append("Database User, "); + error = true; + } + if(jdbcConfig.getDatabaseName() == null) { + sb.append("Database Name, "); + error = true; + } + if(error) { + sb.append(" is missing"); + logger.debug("Connection Parameter errors::{}", sb.toString()); + response.sendError(HttpStatus.SC_BAD_REQUEST, sb.toString()); + } + + if(logger.isDebugEnabled()) { + logger.debug("Connection Config:: {}", jdbcConfig.getConnectionName()); + } + + if(jdbcConfig.getDatabasePassword() != null) { + jdbcConfig.setDatabasePassword(DatabaseUtils.encrypt(jdbcConfig.getDatabasePassword())); + } + + DatabaseUtils.editSavedConnections(jdbcConfig); + + try { + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Type", "application/json"); + + writeSavedConnectionResponse(response); + + } catch (Exception e) { + logger.error("Exception while loading settings {}", e); + } + } + + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/TestConnectCommand.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/TestConnectCommand.java new file mode 100644 index 000000000..af7b6f0f9 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/TestConnectCommand.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.cmd; + +import java.io.IOException; +import java.io.Writer; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.http.HttpStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.util.ParsingUtilities; + + + +public class TestConnectCommand extends DatabaseCommand { + + private static final Logger logger = LoggerFactory.getLogger("TestConnectCommand"); + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + if(!hasValidCSRFToken(request)) { + respondCSRFError(response); + return; + } + + DatabaseConfiguration databaseConfiguration = getJdbcConfiguration(request); + if(logger.isDebugEnabled()) { + logger.debug("TestConnectCommand::Post::{}", databaseConfiguration); + } + + + //ProjectManager.singleton.setBusy(true); + try { + + + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Type", "application/json"); + + Writer w = response.getWriter(); + JsonGenerator writer = ParsingUtilities.mapper.getFactory().createGenerator(w); + + try { + + boolean connectionTestResult = DatabaseService.get(databaseConfiguration.getDatabaseType()) + .testConnection(databaseConfiguration); + + response.setStatus(HttpStatus.SC_OK); + writer.writeStartObject(); + + writer.writeBooleanField("connectionResult", connectionTestResult); + writer.writeStringField("code", "ok"); + writer.writeEndObject(); + + } catch (DatabaseServiceException e) { + logger.error("TestConnectCommand::Post::DatabaseServiceException::{}", e); + sendError(HttpStatus.SC_UNAUTHORIZED,response, e); + } finally { + writer.flush(); + writer.close(); + w.close(); + } + } catch (Exception e) { + logger.error("TestConnectCommand::Post::Exception::{}", e); + throw new ServletException(e); + } finally { + //ProjectManager.singleton.setBusy(false); + } + + + } + + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/TestQueryCommand.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/TestQueryCommand.java new file mode 100644 index 000000000..82610f38b --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/cmd/TestQueryCommand.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.cmd; + +import java.io.IOException; +import java.io.Writer; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.http.HttpStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; +//import com.google.refine.ProjectManager; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.util.ParsingUtilities; + + +public class TestQueryCommand extends DatabaseCommand { + + private static final Logger logger = LoggerFactory.getLogger("TestQueryCommand"); + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + if(!hasValidCSRFToken(request)) { + respondCSRFError(response); + return; + } + + DatabaseConfiguration dbConfig = getJdbcConfiguration(request); + String query = request.getParameter("query"); + + if(logger.isDebugEnabled()) { + logger.debug("TestQueryCommand::Post::DatabaseConfiguration::{}::Query::{} " ,dbConfig, query); + } + + + //ProjectManager.singleton.setBusy(true); + try { + + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Type", "application/json"); + Writer w = response.getWriter(); + JsonGenerator writer = ParsingUtilities.mapper.getFactory().createGenerator(w); + + try { + DatabaseInfo databaseInfo = DatabaseService.get(dbConfig.getDatabaseType()) + .testQuery(dbConfig, query); + ObjectMapper mapperObj = new ObjectMapper(); + + response.setStatus(HttpStatus.SC_OK); + String jsonStr = mapperObj.writeValueAsString(databaseInfo); + if(logger.isDebugEnabled()) { + logger.debug("TestQueryCommand::Post::Result::{} " ,jsonStr); + } + + writer.writeStartObject(); + writer.writeStringField("code", "ok"); + writer.writeStringField("QueryResult", jsonStr); + writer.writeEndObject(); + + + } catch (DatabaseServiceException e) { + logger.error("TestQueryCommand::Post::DatabaseServiceException::{}", e); + sendError(HttpStatus.SC_BAD_REQUEST, response, e); + + } catch (Exception e) { + logger.error("TestQueryCommand::Post::Exception::{}", e); + sendError(HttpStatus.SC_BAD_REQUEST,response, e); + } finally { + writer.flush(); + writer.close(); + w.close(); + } + } catch (Exception e) { + logger.error("TestQueryCommand::Post::Exception::{}", e); + throw new ServletException(e); + } +// finally { +// // ProjectManager.singleton.setBusy(false); +// } + + + } + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/mariadb/MariaDBConnectionManager.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/mariadb/MariaDBConnectionManager.java new file mode 100644 index 000000000..4af014afc --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/mariadb/MariaDBConnectionManager.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.mariadb; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.SQLType; + + + +public class MariaDBConnectionManager { + + private static final Logger logger = LoggerFactory.getLogger("MariaDBConnectionManager"); + private Connection connection; + private SQLType type; + + private static MariaDBConnectionManager instance; + + /** + * + * @param type + * @param databaseConfiguration + * @throws SQLException + */ + private MariaDBConnectionManager() { + type = SQLType.forName(MariaDBDatabaseService.DB_NAME); + + } + + + + + /** + * Create a new instance of this connection manager. + * + * @return an instance of the manager + * + * @throws DatabaseServiceException + */ + public static MariaDBConnectionManager getInstance() throws DatabaseServiceException { + if (instance == null) { + //logger.info("::Creating new MariaDB Connection Manager ::"); + instance = new MariaDBConnectionManager(); + + } + return instance; + } + + + /** + * Get the SQL Database type. + * + * @return the type + */ + public SQLType getType() { + return this.type; + } + + /** + * testConnection + * @param databaseConfiguration + * @return + */ + public boolean testConnection(DatabaseConfiguration databaseConfiguration) throws DatabaseServiceException{ + + try { + boolean connResult = false; + + Connection conn = getConnection(databaseConfiguration, true); + if(conn != null) { + connResult = true; + conn.close(); + } + + return connResult; + + } + catch (SQLException e) { + logger.error("Test connection Failed!", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + + } + + /** + * Get a connection form the connection pool. + * + * @return connection from the pool + */ + public Connection getConnection(DatabaseConfiguration databaseConfiguration, boolean forceNewConnection) throws DatabaseServiceException{ + try { + + // logger.info("connection::{}, forceNewConnection: {}", connection, forceNewConnection); + + if (connection != null && !forceNewConnection) { + // logger.debug("connection closed::{}", connection.isClosed()); + if (!connection.isClosed()) { + if(logger.isDebugEnabled()) { + logger.debug("Returning existing connection::{}", connection); + } + + + return connection; + } + } + + Class.forName(type.getClassPath()); + DriverManager.setLoginTimeout(10); + String dbURL = getDatabaseUrl(databaseConfiguration); + connection = DriverManager.getConnection(dbURL, databaseConfiguration.getDatabaseUser(), + databaseConfiguration.getDatabasePassword()); + + if(logger.isDebugEnabled()) { + logger.debug("*** Acquired New connection for ::{} **** ", dbURL); + } + + + return connection; + + + } catch (ClassNotFoundException e) { + logger.error("Jdbc Driver not found", e); + throw new DatabaseServiceException(e.getMessage()); + } catch (SQLException e) { + logger.error("SQLException::Couldn't get a Connection!", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } + + + public void shutdown() { + + if (connection != null) { + try { + connection.close(); + } + catch (SQLException e) { + logger.warn("Non-Managed connection could not be closed. Whoops!", e); + } + } + + } + + + + private static String getDatabaseUrl(DatabaseConfiguration dbConfig) { + + int port = dbConfig.getDatabasePort(); + return "jdbc:" + dbConfig.getDatabaseType().toLowerCase() + "://" + dbConfig.getDatabaseHost() + + ((port == 0) ? "" : (":" + port)) + "/" + dbConfig.getDatabaseName(); + + } +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/mariadb/MariaDBDatabaseService.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/mariadb/MariaDBDatabaseService.java new file mode 100644 index 000000000..af8b4a948 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/mariadb/MariaDBDatabaseService.java @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.mariadb; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +import org.mariadb.jdbc.MariaDbResultSetMetaData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.DatabaseUtils; +import com.google.refine.extension.database.SQLType; +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.extension.database.model.DatabaseRow; + +public class MariaDBDatabaseService extends DatabaseService { + private static final Logger logger = LoggerFactory.getLogger("MariaDBDatabaseService"); + public static final String DB_NAME = "mariadb"; + public static final String DB_DRIVER = "org.mariadb.jdbc.Driver"; + private static MariaDBDatabaseService instance; + + private MariaDBDatabaseService() { + } + + public static MariaDBDatabaseService getInstance() { + if (instance == null) { + SQLType.registerSQLDriver(DB_NAME, DB_DRIVER); + instance = new MariaDBDatabaseService(); + if(logger.isDebugEnabled()) { + logger.debug("MariaDBDatabaseService Instance: {}", instance); + } + } + return instance; + } + + @Override + public boolean testConnection(DatabaseConfiguration dbConfig) throws DatabaseServiceException{ + return MariaDBConnectionManager.getInstance().testConnection(dbConfig); + } + + @Override + public DatabaseInfo connect(DatabaseConfiguration dbConfig) throws DatabaseServiceException{ + return getMetadata(dbConfig); + } + + @Override + public DatabaseInfo executeQuery(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException{ + try { + Connection connection = MariaDBConnectionManager.getInstance().getConnection(dbConfig, false); + Statement statement = connection.createStatement(); + ResultSet queryResult = statement.executeQuery(query); + MariaDbResultSetMetaData metadata = (MariaDbResultSetMetaData)queryResult.getMetaData(); + int columnCount = metadata.getColumnCount(); + ArrayList columns = new ArrayList(columnCount); + for (int i = 1; i <= columnCount; i++) { + DatabaseColumn dc = new DatabaseColumn( + metadata.getColumnName(i), + metadata.getColumnLabel(i), + DatabaseUtils.getDbColumnType(metadata.getColumnType(i)), + metadata.getColumnDisplaySize(i)); + columns.add(dc); + } + int index = 0; + List rows = new ArrayList(); + while (queryResult.next()) { + DatabaseRow row = new DatabaseRow(); + row.setIndex(index); + List values = new ArrayList(columnCount); + for (int i = 1; i <= columnCount; i++) { + values.add(queryResult.getString(i)); + } + row.setValues(values); + rows.add(row); + index++; + } + DatabaseInfo dbInfo = new DatabaseInfo(); + dbInfo.setColumns(columns); + dbInfo.setRows(rows); + return dbInfo; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } finally { + MariaDBConnectionManager.getInstance().shutdown(); + } + } + + /** + * @param connectionInfo + * @return + * @throws DatabaseServiceException + */ + private DatabaseInfo getMetadata(DatabaseConfiguration connectionInfo) throws DatabaseServiceException { + try { + Connection connection = MariaDBConnectionManager.getInstance().getConnection(connectionInfo, true); + if(connection != null) { + java.sql.DatabaseMetaData metadata = connection.getMetaData(); + int dbMajorVersion = metadata.getDatabaseMajorVersion(); + int dbMinorVersion = metadata.getDatabaseMinorVersion(); + String dbProductVersion = metadata.getDatabaseProductVersion(); + String dbProductName = metadata.getDatabaseProductName(); + DatabaseInfo dbInfo = new DatabaseInfo(); + dbInfo.setDatabaseMajorVersion(dbMajorVersion); + dbInfo.setDatabaseMinorVersion(dbMinorVersion); + dbInfo.setDatabaseProductVersion(dbProductVersion); + dbInfo.setDatabaseProductName(dbProductName); + return dbInfo; + } + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + + return null; + } + + @Override + public ArrayList getColumns(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException{ + try { + Connection connection = MariaDBConnectionManager.getInstance().getConnection(dbConfig, true); + Statement statement = connection.createStatement(); + ResultSet queryResult = statement.executeQuery(query); + MariaDbResultSetMetaData metadata = (MariaDbResultSetMetaData) queryResult.getMetaData(); + int columnCount = metadata.getColumnCount(); + ArrayList columns = new ArrayList(columnCount); + for (int i = 1; i <= columnCount; i++) { + DatabaseColumn dc = new DatabaseColumn(metadata.getColumnName(i), metadata.getColumnLabel(i), + DatabaseUtils.getDbColumnType(metadata.getColumnType(i)), metadata.getColumnDisplaySize(i)); + columns.add(dc); + } + return columns; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } + + @Override + public List getRows(DatabaseConfiguration dbConfig, String query) + throws DatabaseServiceException { + try { + Connection connection = MariaDBConnectionManager.getInstance().getConnection(dbConfig, false); + Statement statement = connection.createStatement(); + ResultSet queryResult = statement.executeQuery(query); + MariaDbResultSetMetaData metadata = (MariaDbResultSetMetaData)queryResult.getMetaData(); + int columnCount = metadata.getColumnCount(); + int index = 0; + List rows = new ArrayList(); + while (queryResult.next()) { + DatabaseRow row = new DatabaseRow(); + row.setIndex(index); + List values = new ArrayList(columnCount); + for (int i = 1; i <= columnCount; i++) { + values.add(queryResult.getString(i)); + } + row.setValues(values); + rows.add(row); + index++; + } + return rows; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } + + @Override + protected String getDatabaseUrl(DatabaseConfiguration dbConfig) { + int port = dbConfig.getDatabasePort(); + return "jdbc:" + dbConfig.getDatabaseType() + "://" + dbConfig.getDatabaseHost() + + ((port == 0) ? "" : (":" + port)) + "/" + dbConfig.getDatabaseName() + "?useSSL=" + dbConfig.isUseSSL(); + } + + @Override + public Connection getConnection(DatabaseConfiguration dbConfig) + throws DatabaseServiceException { + // TODO Auto-generated method stub + return MariaDBConnectionManager.getInstance().getConnection(dbConfig, true); + } + + @Override + public DatabaseInfo testQuery(DatabaseConfiguration dbConfig, String query) + throws DatabaseServiceException { + Statement statement = null; + ResultSet queryResult = null; + try { + Connection connection = MariaDBConnectionManager.getInstance().getConnection(dbConfig, true); + statement = connection.createStatement(); + queryResult = statement.executeQuery(query); + DatabaseInfo dbInfo = new DatabaseInfo(); + return dbInfo; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } finally { + try { + if (queryResult != null) { + queryResult.close(); + } + if (statement != null) { + statement.close(); + } + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + MariaDBConnectionManager.getInstance().shutdown(); + } + } +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseColumn.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseColumn.java new file mode 100644 index 000000000..35620146c --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseColumn.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.model; + +import com.google.refine.extension.database.DatabaseColumnType; + +public class DatabaseColumn { + + + private String name; + private int size; + private DatabaseColumnType type; + private String label; + + public DatabaseColumnType getType() { + return type; + } + + + + public void setType(DatabaseColumnType type) { + this.type = type; + } + + + + public String getLabel() { + return label; + } + + + + public void setLabel(String label) { + this.label = label; + } + + + public DatabaseColumn(String name, int size, DatabaseColumnType type) { + super(); + this.name = name; + this.size = size; + this.type = type; + } + + + public DatabaseColumn(String name, String label, DatabaseColumnType type, int size) { + this.name = name; + this.label = label; + this.size = size; + this.type = type; + } + + + public String getName() { + return name; + } + + + public void setName(String name) { + this.name = name; + } + + + public int getSize() { + return size; + } + + + public void setSize(int size) { + this.size = size; + } + + + + + @Override + public String toString() { + return "DatabaseColumn [name=" + name + ", size=" + size + ", type=" + type + ", label=" + label + "]"; + } + + + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseInfo.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseInfo.java new file mode 100644 index 000000000..c5755e9a7 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseInfo.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.model; + +import java.util.ArrayList; +import java.util.List; + +public class DatabaseInfo { + + private List tables; + private int dbMajorVersion; + private int dbMinorVersion; + private String dbProductVersion; + private String dbProductName; + + private ArrayList columns; + private List rows; + + public DatabaseInfo() { + // TODO Auto-generated constructor stub + } + + public List getTables() { + return tables; + } + + public void setTables(List tables) { + this.tables = tables; + } + + public void setDatabaseMajorVersion(int dbMajorVersion) { + this.dbMajorVersion = dbMajorVersion; + + } + + public void setDatabaseMinorVersion(int dbMinorVersion) { + this.dbMinorVersion = dbMinorVersion; + + } + + public void setDatabaseProductVersion(String dbProductVersion) { + this.dbProductVersion = dbProductVersion; + + } + + public void setDatabaseProductName(String dbProductName) { + this.dbProductName = dbProductName; + + } + + public int getDbMajorVersion() { + return dbMajorVersion; + } + + public void setDbMajorVersion(int dbMajorVersion) { + this.dbMajorVersion = dbMajorVersion; + } + + public int getDbMinorVersion() { + return dbMinorVersion; + } + + public void setDbMinorVersion(int dbMinorVersion) { + this.dbMinorVersion = dbMinorVersion; + } + + public String getDbProductVersion() { + return dbProductVersion; + } + + public void setDbProductVersion(String dbProductVersion) { + this.dbProductVersion = dbProductVersion; + } + + public String getDbProductName() { + return dbProductName; + } + + public void setDbProductName(String dbProductName) { + this.dbProductName = dbProductName; + } + + public void setColumns(ArrayList columns) { + this.columns = columns; + + } + + public void setRows(List rows) { + this.rows = rows; + + } + + public ArrayList getColumns() { + return columns; + } + + + public List getRows() { + return rows; + } + + + @Override + public String toString() { + return "DatabaseInfo [tables=" + tables + ", dbMajorVersion=" + dbMajorVersion + ", dbMinorVersion=" + + dbMinorVersion + ", dbProductVersion=" + dbProductVersion + ", dbProductName=" + dbProductName + "]"; + } + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseQueryInfo.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseQueryInfo.java new file mode 100644 index 000000000..e8f1fb8c8 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseQueryInfo.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.model; + +import com.google.refine.extension.database.DatabaseConfiguration; + +public class DatabaseQueryInfo { + + private DatabaseConfiguration dbConfig; + + private String query; + + public DatabaseQueryInfo(DatabaseConfiguration databaseConfig, String query) { + super(); + this.dbConfig = databaseConfig; + this.query = query; + } + + + public DatabaseConfiguration getDbConfig() { + return dbConfig; + } + + + public void setDbConfig(DatabaseConfiguration databaseConfig) { + this.dbConfig = databaseConfig; + } + + + public String getQuery() { + return query; + } + + + public void setQuery(String query) { + this.query = query; + } + + + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseRow.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseRow.java new file mode 100644 index 000000000..3fd6b9979 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseRow.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.model; + +import java.util.List; + +public class DatabaseRow { + + private int index; + + private List values; + + + public int getIndex() { + return index; + } + + + public void setIndex(int index) { + this.index = index; + } + + + public List getValues() { + return values; + } + + + public void setValues(List values) { + this.values = values; + } + + + + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseTable.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseTable.java new file mode 100644 index 000000000..c7758de27 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/model/DatabaseTable.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.model; + +import java.util.ArrayList; +import java.util.List; + +public class DatabaseTable { + + + private List columns = new ArrayList(); + + private String name; + + + public DatabaseTable(String name) { + this.name = name; + } + + + public List getColumns() { + return columns; + } + + + public void setColumns(List columns) { + this.columns = columns; + } + + + public String getName() { + return name; + } + + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "DatabaseTable [columns=" + columns + ", name=" + name + "]"; + } + + + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/mysql/MySQLConnectionManager.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/mysql/MySQLConnectionManager.java new file mode 100644 index 000000000..9e81fd264 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/mysql/MySQLConnectionManager.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.mysql; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.SQLType; + + +public class MySQLConnectionManager { + + private static final Logger logger = LoggerFactory.getLogger("MySQLConnectionManager"); + private Connection connection; + private SQLType type; + + private static MySQLConnectionManager instance; + + /** + * + * @param type + * @param databaseConfiguration + * @throws SQLException + */ + private MySQLConnectionManager() { + type = SQLType.forName(MySQLDatabaseService.DB_NAME); + + } + + + + /** + * Create a new instance of this connection manager. + * + * @return an instance of the manager + * + * @throws DatabaseServiceException + */ + public static MySQLConnectionManager getInstance() throws DatabaseServiceException { + if (instance == null) { + logger.debug("::Creating new MySQLConnectionManager ::"); + instance = new MySQLConnectionManager(); + + } + return instance; + } + + + /** + * Get the SQL Database type. + * + * @return the type + */ + public SQLType getType() { + return this.type; + } + + /** + * testConnection + * @param databaseConfiguration + * @return + */ + public boolean testConnection(DatabaseConfiguration databaseConfiguration) throws DatabaseServiceException{ + + try { + boolean connResult = false; + + Connection conn = getConnection(databaseConfiguration, true); + if(conn != null) { + connResult = true; + conn.close(); + } + + return connResult; + + } + catch (SQLException e) { + logger.error("Test connection Failed!", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + + } + + /** + * Get a connection form the connection pool. + * + * @return connection from the pool + */ + public Connection getConnection(DatabaseConfiguration databaseConfiguration, boolean forceNewConnection) throws DatabaseServiceException{ + try { + + if (connection != null && !forceNewConnection) { + //logger.info("connection closed::{}", connection.isClosed()); + if (!connection.isClosed()) { + if(logger.isDebugEnabled()){ + logger.debug("Returning existing connection::{}", connection); + } + + return connection; + } + } + String dbURL = getDatabaseUrl(databaseConfiguration); + Class.forName(type.getClassPath()); + + //logger.info("*** type.getClassPath() ::{}, {}**** ", type.getClassPath()); + + DriverManager.setLoginTimeout(10); + + connection = DriverManager.getConnection(dbURL, databaseConfiguration.getDatabaseUser(), + databaseConfiguration.getDatabasePassword()); + + if(logger.isDebugEnabled()) { + logger.debug("*** Acquired New connection for ::{} **** ", dbURL); + } + + + return connection; + + + } catch (ClassNotFoundException e) { + logger.error("Jdbc Driver not found", e); + throw new DatabaseServiceException(e.getMessage()); + } catch (SQLException e) { + logger.error("SQLException::Couldn't get a Connection!", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } + + + public void shutdown() { + + if (connection != null) { + try { + connection.close(); + } + catch (SQLException e) { + logger.warn("Non-Managed connection could not be closed. Whoops!", e); + } + } + + } + + + private String getDatabaseUrl(DatabaseConfiguration dbConfig) { + + int port = dbConfig.getDatabasePort(); + return "jdbc:" + dbConfig.getDatabaseType() + "://" + dbConfig.getDatabaseHost() + + ((port == 0) ? "" : (":" + port)) + "/" + dbConfig.getDatabaseName() + "?useSSL=" + dbConfig.isUseSSL(); + + } +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/mysql/MySQLDatabaseService.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/mysql/MySQLDatabaseService.java new file mode 100644 index 000000000..8f4492f0b --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/mysql/MySQLDatabaseService.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.mysql; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.DatabaseUtils; +import com.google.refine.extension.database.SQLType; +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.extension.database.model.DatabaseRow; + +public class MySQLDatabaseService extends DatabaseService { + private static final Logger logger = LoggerFactory.getLogger("MySQLDatabaseService"); + public static final String DB_NAME = "mysql"; + public static final String DB_DRIVER = "com.mysql.jdbc.Driver"; + + private static MySQLDatabaseService instance; + + private MySQLDatabaseService() { + } + + public static MySQLDatabaseService getInstance() { + if (instance == null) { + SQLType.registerSQLDriver(DB_NAME, DB_DRIVER, false); + instance = new MySQLDatabaseService(); + if(logger.isDebugEnabled()) { + logger.debug("MySQLDatabaseService Instance: {}", instance); + } + } + return instance; + } + + @Override + public boolean testConnection(DatabaseConfiguration dbConfig) throws DatabaseServiceException{ + return MySQLConnectionManager.getInstance().testConnection(dbConfig); + + } + + @Override + public DatabaseInfo connect(DatabaseConfiguration dbConfig) throws DatabaseServiceException{ + return getMetadata(dbConfig); + } + + @Override + public DatabaseInfo executeQuery(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException{ + try { + Connection connection = MySQLConnectionManager.getInstance().getConnection(dbConfig, false); + Statement statement = connection.createStatement(); + ResultSet queryResult = statement.executeQuery(query); + java.sql.ResultSetMetaData metadata = queryResult.getMetaData(); + int columnCount = metadata.getColumnCount(); + ArrayList columns = new ArrayList(columnCount); + for (int i = 1; i <= columnCount; i++) { + DatabaseColumn dc = new DatabaseColumn( + metadata.getColumnName(i), + metadata.getColumnLabel(i), + DatabaseUtils.getDbColumnType(metadata.getColumnType(i)), + metadata.getColumnDisplaySize(i)); + columns.add(dc); + } + int index = 0; + List rows = new ArrayList(); + while (queryResult.next()) { + DatabaseRow row = new DatabaseRow(); + row.setIndex(index); + List values = new ArrayList(columnCount); + for (int i = 1; i <= columnCount; i++) { + + values.add(queryResult.getString(i)); + + } + row.setValues(values); + rows.add(row); + index++; + + } + DatabaseInfo dbInfo = new DatabaseInfo(); + dbInfo.setColumns(columns); + dbInfo.setRows(rows); + return dbInfo; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + }finally { + MySQLConnectionManager.getInstance().shutdown(); + } + } + + /** + * @param connectionInfo + * @return + * @throws DatabaseServiceException + */ + private DatabaseInfo getMetadata(DatabaseConfiguration connectionInfo) throws DatabaseServiceException { + try { + Connection connection = MySQLConnectionManager.getInstance().getConnection(connectionInfo, true); + if(connection != null) { + java.sql.DatabaseMetaData metadata; + metadata = connection.getMetaData(); + int dbMajorVersion = metadata.getDatabaseMajorVersion(); + int dbMinorVersion = metadata.getDatabaseMinorVersion(); + String dbProductVersion = metadata.getDatabaseProductVersion(); + String dbProductName = metadata.getDatabaseProductName(); + DatabaseInfo dbInfo = new DatabaseInfo(); + dbInfo.setDatabaseMajorVersion(dbMajorVersion); + dbInfo.setDatabaseMinorVersion(dbMinorVersion); + dbInfo.setDatabaseProductVersion(dbProductVersion); + dbInfo.setDatabaseProductName(dbProductName); + return dbInfo; + } + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + return null; + } + + @Override + public ArrayList getColumns(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException{ + try { + Connection connection = MySQLConnectionManager.getInstance().getConnection(dbConfig, true); + Statement statement = connection.createStatement(); + ResultSet queryResult = statement.executeQuery(query); + java.sql.ResultSetMetaData metadata = queryResult.getMetaData(); + int columnCount = metadata.getColumnCount(); + ArrayList columns = new ArrayList(columnCount); + for (int i = 1; i <= columnCount; i++) { + DatabaseColumn dc = new DatabaseColumn(metadata.getColumnName(i), metadata.getColumnLabel(i), + DatabaseUtils.getDbColumnType(metadata.getColumnType(i)), metadata.getColumnDisplaySize(i)); + columns.add(dc); + } + return columns; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } + + @Override + public List getRows(DatabaseConfiguration dbConfig, String query) + throws DatabaseServiceException { + try { + Connection connection = MySQLConnectionManager.getInstance().getConnection(dbConfig, false); + Statement statement = connection.createStatement(); + statement.setFetchSize(10); + ResultSet queryResult = statement.executeQuery(query); + java.sql.ResultSetMetaData metadata = queryResult.getMetaData(); + int columnCount = metadata.getColumnCount(); + int index = 0; + List rows = new ArrayList(); + while (queryResult.next()) { + DatabaseRow row = new DatabaseRow(); + row.setIndex(index); + List values = new ArrayList(columnCount); + for (int i = 1; i <= columnCount; i++) { + values.add(queryResult.getString(i)); + } + row.setValues(values); + rows.add(row); + index++; + } + return rows; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } + + @Override + protected String getDatabaseUrl(DatabaseConfiguration dbConfig) { + int port = dbConfig.getDatabasePort(); + return "jdbc:" + dbConfig.getDatabaseType() + "://" + dbConfig.getDatabaseHost() + + ((port == 0) ? "" : (":" + port)) + "/" + dbConfig.getDatabaseName() + "?useSSL=" + dbConfig.isUseSSL(); + } + + @Override + public Connection getConnection(DatabaseConfiguration dbConfig) + throws DatabaseServiceException { + // TODO Auto-generated method stub + return MySQLConnectionManager.getInstance().getConnection(dbConfig, true); + } + + @Override + public DatabaseInfo testQuery(DatabaseConfiguration dbConfig, String query) + throws DatabaseServiceException { + Statement statement = null; + ResultSet queryResult = null; + try { + Connection connection = MySQLConnectionManager.getInstance().getConnection(dbConfig, true); + statement = connection.createStatement(); + queryResult = statement.executeQuery(query); + DatabaseInfo dbInfo = new DatabaseInfo(); + return dbInfo; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } finally { + try { + if (queryResult != null) { + queryResult.close(); + } + if (statement != null) { + statement.close(); + } + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + MySQLConnectionManager.getInstance().shutdown(); + } + } +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/pgsql/PgSQLConnectionManager.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/pgsql/PgSQLConnectionManager.java new file mode 100644 index 000000000..bef6c9a69 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/pgsql/PgSQLConnectionManager.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.pgsql; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.SQLType; + + + +public class PgSQLConnectionManager { + + private static final Logger logger = LoggerFactory.getLogger("PgSQLConnectionManager"); + private Connection connection; + private SQLType type; + + private static PgSQLConnectionManager instance; + + + + /** + * + * @param type + * @param databaseConfiguration + * @throws SQLException + */ + private PgSQLConnectionManager() { + type = SQLType.forName(PgSQLDatabaseService.DB_NAME); + + } + + + + + /** + * Create a new instance of this connection manager. + * + * @return an instance of the manager + * + * @throws DatabaseServiceException + */ + public static PgSQLConnectionManager getInstance() throws DatabaseServiceException { + if (instance == null) { + if(logger.isDebugEnabled()) { + logger.debug("::Creating new PgSQL ConnectionManager ::"); + } + + instance = new PgSQLConnectionManager(); + + } + return instance; + } + + + /** + * Get the SQL Database type. + * + * @return the type + */ + public SQLType getType() { + return this.type; + } + + /** + * testConnection + * @param databaseConfiguration + * @return + */ + public boolean testConnection(DatabaseConfiguration databaseConfiguration) throws DatabaseServiceException{ + + try { + boolean connResult = false; + + Connection conn = getConnection(databaseConfiguration, true); + if(conn != null) { + connResult = true; + conn.close(); + } + + return connResult; + + } + catch (SQLException e) { + logger.error("Test connection Failed!", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + + } + + /** + * Get a connection form the connection pool. + * + * @return connection from the pool + */ + public Connection getConnection(DatabaseConfiguration databaseConfiguration, boolean forceNewConnection) throws DatabaseServiceException{ + try { + + // logger.info("connection::{}, forceNewConnection: {}", connection, forceNewConnection); + + if (connection != null && !forceNewConnection) { + // logger.info("connection closed::{}", connection.isClosed()); + if (!connection.isClosed()) { + if(logger.isDebugEnabled()){ + logger.debug("Returning existing connection::{}", connection); + } + return connection; + } + } + + Class.forName(type.getClassPath()); + DriverManager.setLoginTimeout(10); + String dbURL = getDatabaseUrl(databaseConfiguration); + connection = DriverManager.getConnection(dbURL, databaseConfiguration.getDatabaseUser(), + databaseConfiguration.getDatabasePassword()); + + logger.debug("*** Acquired New connection for ::{} **** ", dbURL); + + return connection; + + + } catch (ClassNotFoundException e) { + logger.error("Jdbc Driver not found", e); + throw new DatabaseServiceException(e.getMessage()); + } catch (SQLException e) { + logger.error("SQLException::Couldn't get a Connection!", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } + + + public void shutdown() { + + if (connection != null) { + try { + connection.close(); + } + catch (SQLException e) { + logger.warn("Non-Managed connection could not be closed. Whoops!", e); + } + } + + } + + + private static String getDatabaseUrl(DatabaseConfiguration dbConfig) { + + int port = dbConfig.getDatabasePort(); + return "jdbc:" + dbConfig.getDatabaseType().toLowerCase() + "://" + dbConfig.getDatabaseHost() + + ((port == 0) ? "" : (":" + port)) + "/" + dbConfig.getDatabaseName(); + + } +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/pgsql/PgSQLDatabaseService.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/pgsql/PgSQLDatabaseService.java new file mode 100644 index 000000000..10051ca16 --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/pgsql/PgSQLDatabaseService.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2017, Tony Opara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.refine.extension.database.pgsql; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +import org.postgresql.jdbc.PgResultSetMetaData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.DatabaseUtils; +import com.google.refine.extension.database.SQLType; +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.extension.database.model.DatabaseRow; + +public class PgSQLDatabaseService extends DatabaseService { + private static final Logger logger = LoggerFactory.getLogger("PgSQLDatabaseService"); + public static final String DB_NAME = "postgresql"; + public static final String DB_DRIVER = "org.postgresql.Driver"; + private static PgSQLDatabaseService instance; + + private PgSQLDatabaseService() { + } + + public static PgSQLDatabaseService getInstance() { + if (instance == null) { + SQLType.registerSQLDriver(DB_NAME, DB_DRIVER); + instance = new PgSQLDatabaseService(); + if(logger.isDebugEnabled()) { + logger.debug("PgSQLDatabaseService Instance: {}", instance); + } + } + return instance; + } + + @Override + public boolean testConnection(DatabaseConfiguration dbConfig) throws DatabaseServiceException{ + return PgSQLConnectionManager.getInstance().testConnection(dbConfig); + + } + + @Override + public DatabaseInfo connect(DatabaseConfiguration dbConfig) throws DatabaseServiceException{ + return getMetadata(dbConfig); + } + + @Override + public DatabaseInfo executeQuery(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException{ + try { + Connection connection = PgSQLConnectionManager.getInstance().getConnection(dbConfig, false); + Statement statement = connection.createStatement(); + ResultSet queryResult = statement.executeQuery(query); + PgResultSetMetaData metadata = (PgResultSetMetaData)queryResult.getMetaData(); + int columnCount = metadata.getColumnCount(); + ArrayList columns = new ArrayList(columnCount); + for (int i = 1; i <= columnCount; i++) { + DatabaseColumn dc = new DatabaseColumn( + metadata.getColumnName(i), + metadata.getColumnLabel(i), + DatabaseUtils.getDbColumnType(metadata.getColumnType(i)), + metadata.getColumnDisplaySize(i)); + columns.add(dc); + } + int index = 0; + List rows = new ArrayList(); + while (queryResult.next()) { + DatabaseRow row = new DatabaseRow(); + row.setIndex(index); + List values = new ArrayList(columnCount); + for (int i = 1; i <= columnCount; i++) { + values.add(queryResult.getString(i)); + } + row.setValues(values); + rows.add(row); + index++; + } + DatabaseInfo dbInfo = new DatabaseInfo(); + dbInfo.setColumns(columns); + dbInfo.setRows(rows); + return dbInfo; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + }finally { + PgSQLConnectionManager.getInstance().shutdown(); + } + } + + /** + * @param connectionInfo + * @return + * @throws DatabaseServiceException + */ + private DatabaseInfo getMetadata(DatabaseConfiguration connectionInfo) throws DatabaseServiceException { + try { + Connection connection = PgSQLConnectionManager.getInstance().getConnection(connectionInfo, true); + if(connection != null) { + java.sql.DatabaseMetaData metadata = connection.getMetaData(); + int dbMajorVersion = metadata.getDatabaseMajorVersion(); + int dbMinorVersion = metadata.getDatabaseMinorVersion(); + String dbProductVersion = metadata.getDatabaseProductVersion(); + String dbProductName = metadata.getDatabaseProductName(); + DatabaseInfo dbInfo = new DatabaseInfo(); + dbInfo.setDatabaseMajorVersion(dbMajorVersion); + dbInfo.setDatabaseMinorVersion(dbMinorVersion); + dbInfo.setDatabaseProductVersion(dbProductVersion); + dbInfo.setDatabaseProductName(dbProductName); + return dbInfo; + } + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + return null; + } + + @Override + public ArrayList getColumns(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException{ + try { + Connection connection = PgSQLConnectionManager.getInstance().getConnection(dbConfig, true); + Statement statement = connection.createStatement(); + ResultSet queryResult = statement.executeQuery(query); + PgResultSetMetaData metadata = (PgResultSetMetaData) queryResult.getMetaData(); + int columnCount = metadata.getColumnCount(); + ArrayList columns = new ArrayList(columnCount); + for (int i = 1; i <= columnCount; i++) { + DatabaseColumn dc = new DatabaseColumn(metadata.getColumnName(i), metadata.getColumnLabel(i), + DatabaseUtils.getDbColumnType(metadata.getColumnType(i)), metadata.getColumnDisplaySize(i)); + columns.add(dc); + } + return columns; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } + + @Override + public List getRows(DatabaseConfiguration dbConfig, String query) + throws DatabaseServiceException { + try { + Connection connection = PgSQLConnectionManager.getInstance().getConnection(dbConfig, false); + Statement statement = connection.createStatement(); + statement.setFetchSize(10); + ResultSet queryResult = statement.executeQuery(query); + PgResultSetMetaData metadata = (PgResultSetMetaData)queryResult.getMetaData(); + int columnCount = metadata.getColumnCount(); + int index = 0; + List rows = new ArrayList(); + while (queryResult.next()) { + DatabaseRow row = new DatabaseRow(); + row.setIndex(index); + List values = new ArrayList(columnCount); + for (int i = 1; i <= columnCount; i++) { + values.add(queryResult.getString(i)); + } + row.setValues(values); + rows.add(row); + index++; + } + return rows; + } catch (SQLException e) { + logger.error("SQLException::{}::{}", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } + + @Override + protected String getDatabaseUrl(DatabaseConfiguration dbConfig) { + int port = dbConfig.getDatabasePort(); + return "jdbc:" + dbConfig.getDatabaseType() + "://" + dbConfig.getDatabaseHost() + + ((port == 0) ? "" : (":" + port)) + "/" + dbConfig.getDatabaseName() + "?useSSL=" + dbConfig.isUseSSL(); + } + + @Override + public Connection getConnection(DatabaseConfiguration dbConfig) + throws DatabaseServiceException { + return PgSQLConnectionManager.getInstance().getConnection(dbConfig, true); + } + + @Override + public DatabaseInfo testQuery(DatabaseConfiguration dbConfig, String query) + throws DatabaseServiceException { + Statement statement = null; + ResultSet queryResult = null; + try { + Connection connection = PgSQLConnectionManager.getInstance().getConnection(dbConfig, true); + statement = connection.createStatement(); + queryResult = statement.executeQuery(query); + DatabaseInfo dbInfo = new DatabaseInfo(); + return dbInfo; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } finally { + try { + if (queryResult != null) { + queryResult.close(); + } + if (statement != null) { + statement.close(); + } + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + PgSQLConnectionManager.getInstance().shutdown(); + } + } + +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManager.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManager.java new file mode 100644 index 000000000..5b9b4cfcd --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManager.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2020, Chris Parker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.refine.extension.database.sqlite; + +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.SQLType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class SQLiteConnectionManager { + + private static final Logger logger = LoggerFactory.getLogger("SQLiteConnectionManager"); + private static SQLiteConnectionManager instance; + private final SQLType type; + private Connection connection; + + private SQLiteConnectionManager() { + type = SQLType.forName(SQLiteDatabaseService.DB_NAME); + } + + /** + * Create a new instance of this connection manager. + * + * @return an instance of the manager + */ + public static SQLiteConnectionManager getInstance() { + if (instance == null) { + if (logger.isDebugEnabled()) { + logger.debug("::Creating new SQLite ConnectionManager ::"); + } + instance = new SQLiteConnectionManager(); + } + return instance; + } + + public static String getDatabaseUrl(DatabaseConfiguration dbConfig) { + return "jdbc:" + dbConfig.getDatabaseType().toLowerCase() + ":" + dbConfig.getDatabaseName(); + } + + /** + * Get the SQL Database type. + * + * @return the type + */ + public SQLType getType() { + return this.type; + } + + /** + * testConnection + * + * @param dbConfig + * @return boolean + */ + public boolean testConnection(DatabaseConfiguration dbConfig) throws DatabaseServiceException { + try { + boolean connResult = false; + + Connection conn = getConnection(dbConfig); + if (conn != null) { + connResult = true; + conn.close(); + } + + return connResult; + } catch (SQLException e) { + logger.error("Test connection Failed!", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } + + /** + * Get a connection form the connection pool. + * + * @return connection from the pool + */ + public Connection getConnection(DatabaseConfiguration databaseConfiguration) throws DatabaseServiceException { + try { + if (connection != null) { + connection.close(); + } + + Class.forName(type.getClassPath()); + String dbURL = getDatabaseUrl(databaseConfiguration); + connection = DriverManager.getConnection(dbURL); + + logger.debug("*** Acquired New connection for ::{} **** ", dbURL); + + return connection; + } catch (ClassNotFoundException e) { + logger.error("Jdbc Driver not found", e); + throw new DatabaseServiceException(e.getMessage()); + } catch (SQLException e) { + logger.error("SQLException::Couldn't get a Connection!", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } + + public void shutdown() { + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + logger.warn("Non-Managed connection could not be closed. Whoops!", e); + } + } + } +} diff --git a/OpenRefine/extensions/database/src/com/google/refine/extension/database/sqlite/SQLiteDatabaseService.java b/OpenRefine/extensions/database/src/com/google/refine/extension/database/sqlite/SQLiteDatabaseService.java new file mode 100644 index 000000000..5971a5e3f --- /dev/null +++ b/OpenRefine/extensions/database/src/com/google/refine/extension/database/sqlite/SQLiteDatabaseService.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2020, Chris Parker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.refine.extension.database.sqlite; + +import com.google.refine.extension.database.SQLType; +import com.google.refine.extension.database.*; +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.extension.database.model.DatabaseRow; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +public class SQLiteDatabaseService extends DatabaseService { + + public static final String DB_NAME = "sqlite"; + public static final String DB_DRIVER = "org.sqlite.JDBC"; + private static final Logger logger = LoggerFactory.getLogger("SQLiteDatabaseService"); + private static SQLiteDatabaseService instance; + + public static SQLiteDatabaseService getInstance() { + if (instance == null) { + SQLType.registerSQLDriver(DB_NAME, DB_DRIVER, false); + instance = new SQLiteDatabaseService(); + if (logger.isDebugEnabled()) { + logger.debug("SQLiteDatabaseService Instance: {}", instance); + } + } + return instance; + } + + @Override + protected String getDatabaseUrl(DatabaseConfiguration dbConfig) { + return SQLiteConnectionManager.getDatabaseUrl(dbConfig); + } + + @Override + public Connection getConnection(DatabaseConfiguration dbConfig) throws DatabaseServiceException { + return SQLiteConnectionManager.getInstance().getConnection(dbConfig); + } + + @Override + public boolean testConnection(DatabaseConfiguration dbConfig) throws DatabaseServiceException { + return SQLiteConnectionManager.getInstance().testConnection(dbConfig); + } + + @Override + public DatabaseInfo connect(DatabaseConfiguration dbConfig) throws DatabaseServiceException { + return getMetadata(dbConfig); + } + + /** + * @param dbConfig + * @return + * @throws DatabaseServiceException + */ + private DatabaseInfo getMetadata(DatabaseConfiguration connectionInfo) throws DatabaseServiceException { + try { + Connection connection = SQLiteConnectionManager.getInstance().getConnection(connectionInfo); + if (connection != null) { + java.sql.DatabaseMetaData metadata = connection.getMetaData(); + int dbMajorVersion = metadata.getDatabaseMajorVersion(); + int dbMinorVersion = metadata.getDatabaseMinorVersion(); + String dbProductVersion = metadata.getDatabaseProductVersion(); + String dbProductName = metadata.getDatabaseProductName(); + DatabaseInfo dbInfo = new DatabaseInfo(); + dbInfo.setDatabaseMajorVersion(dbMajorVersion); + dbInfo.setDatabaseMinorVersion(dbMinorVersion); + dbInfo.setDatabaseProductVersion(dbProductVersion); + dbInfo.setDatabaseProductName(dbProductName); + return dbInfo; + } + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + return null; + } + + @Override + public DatabaseInfo executeQuery(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException { + try { + Connection connection = SQLiteConnectionManager.getInstance().getConnection(dbConfig); + Statement statement = connection.createStatement(); + ResultSet queryResult = statement.executeQuery(query); + ResultSetMetaData metadata = queryResult.getMetaData(); + int columnCount = metadata.getColumnCount(); + ArrayList columns = new ArrayList<>(columnCount); + for (int i = 1; i <= columnCount; i++) { + DatabaseColumn dc = new DatabaseColumn(metadata.getColumnName(i), metadata.getColumnLabel(i), + DatabaseUtils.getDbColumnType(metadata.getColumnType(i)), + metadata.getColumnDisplaySize(i)); + columns.add(dc); + } + int index = 0; + List rows = new ArrayList<>(); + while (queryResult.next()) { + DatabaseRow row = new DatabaseRow(); + row.setIndex(index); + List values = new ArrayList<>(columnCount); + for (int i = 1; i <= columnCount; i++) { + values.add(queryResult.getString(i)); + } + row.setValues(values); + rows.add(row); + index++; + } + DatabaseInfo dbInfo = new DatabaseInfo(); + dbInfo.setColumns(columns); + dbInfo.setRows(rows); + return dbInfo; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } finally { + SQLiteConnectionManager.getInstance().shutdown(); + } + } + + @Override + public DatabaseInfo testQuery(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException { + Statement statement = null; + ResultSet queryResult = null; + try { + Connection connection = SQLiteConnectionManager.getInstance().getConnection(dbConfig); + statement = connection.createStatement(); + queryResult = statement.executeQuery(query); + return new DatabaseInfo(); + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } finally { + try { + if (queryResult != null) { + queryResult.close(); + } + if (statement != null) { + statement.close(); + } + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + SQLiteConnectionManager.getInstance().shutdown(); + } + } + + @Override + public List getColumns(DatabaseConfiguration dbConfig, String query) + throws DatabaseServiceException { + try { + Connection connection = SQLiteConnectionManager.getInstance().getConnection(dbConfig); + Statement statement = connection.createStatement(); + ResultSet queryResult = statement.executeQuery(query); + ResultSetMetaData metadata = queryResult.getMetaData(); + int columnCount = metadata.getColumnCount(); + ArrayList columns = new ArrayList<>(columnCount); + for (int i = 1; i <= columnCount; i++) { + DatabaseColumn dc = new DatabaseColumn(metadata.getColumnName(i), metadata.getColumnLabel(i), + DatabaseUtils.getDbColumnType(metadata.getColumnType(i)), + metadata.getColumnDisplaySize(i)); + columns.add(dc); + } + return columns; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } + + @Override + public List getRows(DatabaseConfiguration dbConfig, String query) throws DatabaseServiceException { + try { + Connection connection = SQLiteConnectionManager.getInstance().getConnection(dbConfig); + Statement statement = connection.createStatement(); + statement.setFetchSize(10); + ResultSet queryResult = statement.executeQuery(query); + ResultSetMetaData metadata = queryResult.getMetaData(); + int columnCount = metadata.getColumnCount(); + int index = 0; + List rows = new ArrayList<>(); + while (queryResult.next()) { + DatabaseRow row = new DatabaseRow(); + row.setIndex(index); + List values = new ArrayList<>(columnCount); + for (int i = 1; i <= columnCount; i++) { + values.add(queryResult.getString(i)); + } + row.setValues(values); + rows.add(row); + index++; + } + return rows; + } catch (SQLException e) { + logger.error("SQLException::", e); + throw new DatabaseServiceException(true, e.getSQLState(), e.getErrorCode(), e.getMessage()); + } + } +} diff --git a/OpenRefine/extensions/database/tests/conf/appveyor_tests.xml b/OpenRefine/extensions/database/tests/conf/appveyor_tests.xml new file mode 100644 index 000000000..ecb767fca --- /dev/null +++ b/OpenRefine/extensions/database/tests/conf/appveyor_tests.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenRefine/extensions/database/tests/conf/github_actions_tests.xml b/OpenRefine/extensions/database/tests/conf/github_actions_tests.xml new file mode 100644 index 000000000..3e508e567 --- /dev/null +++ b/OpenRefine/extensions/database/tests/conf/github_actions_tests.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenRefine/extensions/database/tests/conf/test-mariadb.sql b/OpenRefine/extensions/database/tests/conf/test-mariadb.sql new file mode 100644 index 000000000..c5716c5a8 --- /dev/null +++ b/OpenRefine/extensions/database/tests/conf/test-mariadb.sql @@ -0,0 +1,18 @@ +CREATE DATABASE IF NOT EXISTS `test_db` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; +USE test_db; + +CREATE TABLE IF NOT EXISTS `test_table` ( + `id` int(11) NOT NULL, + `ue_id` char(8) NOT NULL, + `start_time` timestamp NOT NULL, + `end_date` date DEFAULT NULL, + `bytes_upload` int(11) NOT NULL, + `bytes_download` int(11) NOT NULL, + `mcc` char(3) DEFAULT NULL, + `mnc` char(3) NOT NULL, + `lac` varchar(11) DEFAULT NULL, + `imei` char(16) NOT NULL +); + +INSERT INTO test_table(id, ue_id, start_time, end_date, bytes_upload, bytes_download, mcc, mnc, lac, imei) + VALUES (1, '11100022', now(), now(), 1024, 2048, 321, 543, 12209823498, 1344498988877487); \ No newline at end of file diff --git a/OpenRefine/extensions/database/tests/conf/test-mysql.sql b/OpenRefine/extensions/database/tests/conf/test-mysql.sql new file mode 100644 index 000000000..d2b53c80e --- /dev/null +++ b/OpenRefine/extensions/database/tests/conf/test-mysql.sql @@ -0,0 +1,17 @@ +USE test_db; + +CREATE TABLE IF NOT EXISTS `test_table` ( + `id` int(11) NOT NULL, + `ue_id` char(8) NOT NULL, + `start_time` timestamp NOT NULL, + `end_date` date DEFAULT NULL, + `bytes_upload` int(11) NOT NULL, + `bytes_download` int(11) NOT NULL, + `mcc` char(3) DEFAULT NULL, + `mnc` char(3) NOT NULL, + `lac` varchar(11) DEFAULT NULL, + `imei` char(16) NOT NULL +); + +INSERT INTO test_table(id, ue_id, start_time, end_date, bytes_upload, bytes_download, mcc, mnc, lac, imei) + VALUES (1, '11100022', now(), now(), 1024, 2048, 321, 543, 12209823498, 1344498988877487); \ No newline at end of file diff --git a/OpenRefine/extensions/database/tests/conf/test-pgsql.sql b/OpenRefine/extensions/database/tests/conf/test-pgsql.sql new file mode 100644 index 000000000..f8299a964 --- /dev/null +++ b/OpenRefine/extensions/database/tests/conf/test-pgsql.sql @@ -0,0 +1,17 @@ +USE test_db; + +CREATE TABLE IF NOT EXISTS test_table ( + id integer NOT NULL, + ue_id char(8) NOT NULL, + start_time timestamp NOT NULL, + end_date date DEFAULT NULL, + bytes_upload integer NOT NULL, + bytes_download integer NOT NULL, + mcc char(3) DEFAULT NULL, + mnc char(3) NOT NULL, + lac varchar(11) DEFAULT NULL, + imei char(16) NOT NULL +); + +INSERT INTO test_table(id, ue_id, start_time, end_date, bytes_upload, bytes_download, mcc, mnc, lac, imei) + VALUES (1, '11100022', now(), now(), 1024, 2048, 321, 543, 12209823498, 1344498988877487); \ No newline at end of file diff --git a/OpenRefine/extensions/database/tests/conf/test-sqlite.sql b/OpenRefine/extensions/database/tests/conf/test-sqlite.sql new file mode 100644 index 000000000..ae48f3db1 --- /dev/null +++ b/OpenRefine/extensions/database/tests/conf/test-sqlite.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOT EXISTS test_table ( + id integer NOT NULL, + ue_id char(8) NOT NULL, + start_time timestamp NOT NULL, + end_date date DEFAULT NULL, + bytes_upload integer NOT NULL, + bytes_download integer NOT NULL, + mcc char(3) DEFAULT NULL, + mnc char(3) NOT NULL, + lac varchar(11) DEFAULT NULL, + imei char(16) NOT NULL +); + +INSERT INTO test_table(id, ue_id, start_time, end_date, bytes_upload, bytes_download, mcc, mnc, lac, imei) + VALUES (1, '11100022', now(), now(), 1024, 2048, 321, 543, 12209823498, 1344498988877487); diff --git a/OpenRefine/extensions/database/tests/conf/tests.xml b/OpenRefine/extensions/database/tests/conf/tests.xml new file mode 100644 index 000000000..7885174bf --- /dev/null +++ b/OpenRefine/extensions/database/tests/conf/tests.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenRefine/extensions/database/tests/log4j-test.properties b/OpenRefine/extensions/database/tests/log4j-test.properties new file mode 100644 index 000000000..0ed0d9f64 --- /dev/null +++ b/OpenRefine/extensions/database/tests/log4j-test.properties @@ -0,0 +1,5 @@ +log4j.rootLogger=ERROR, console +log4j.logger.com.google.refine.extension.database=DEBUG + +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.layout=com.google.refine.logging.IndentingLayout diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DBExtensionTestUtils.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DBExtensionTestUtils.java new file mode 100644 index 000000000..d91ed4f08 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DBExtensionTestUtils.java @@ -0,0 +1,439 @@ + +package com.google.refine.extension.database; + +import java.io.File; +import java.io.IOException; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +import org.apache.commons.text.StringSubstitutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DBExtensionTestUtils { + + private static final Logger logger = LoggerFactory.getLogger("DBExtensionTestUtils"); + + private static final String MYSQL_DB_NAME = "mysql"; + private static final String DEFAULT_MYSQL_HOST = "127.0.0.1"; + private static final int DEFAULT_MYSQL_PORT = 3306; + private static final String DEFAULT_MYSQL_USER = "root"; + private static final String DEFAULT_MYSQL_PASSWORD = "secret"; + private static final String DEFAULT_MYSQL_DB_NAME = "testdb"; + + private static final String PGSQL_DB_NAME = "postgresql"; + private static final String DEFAULT_PGSQL_HOST = "127.0.0.1"; + private static final int DEFAULT_PGSQL_PORT = 5432; + private static final String DEFAULT_PGSQL_USER = "postgres"; + private static final String DEFAULT_PGSQL_PASSWORD = ""; + private static final String DEFAULT_PGSQL_DB_NAME = "openrefine"; + + private static final String DEFAULT_TEST_TABLE = "test_data"; + + private static final int SAMPLE_SIZE = 500000; + private static final int BATCH_SIZE = 1000; + + private static Random rand = new Random(); + + private Map mncMap; + private Map mccMap; + + /** + * Create Test Table with one row of Data + * + * @param dbConfig + * DatabaseConfiguration to test + * @param tableName + * @throws DatabaseServiceException + * @throws SQLException + */ + public static void initTestData(DatabaseConfiguration dbConfig, String tableName) + throws DatabaseServiceException, SQLException { + + Statement stmt = null; + Connection conn = null; + try { + DatabaseService dbService = DatabaseService.get(dbConfig.getDatabaseType()); + conn = dbService.getConnection(dbConfig); + stmt = conn.createStatement(); + + DatabaseMetaData dbm = conn.getMetaData(); + // check if "employee" table is there + ResultSet tables = dbm.getTables(null, null, tableName, null); + boolean dropTable = false; + if (tables.next()) { + dropTable = true; + // System.out.println("Drop Table Result::" + dropResult); + } + tables.close(); + if (dropTable) { + stmt.executeUpdate("DROP TABLE " + tableName); + } + + String createSQL = " CREATE TABLE " + tableName + " ( " + + " ID INT NOT NULL, " + + " NAME VARCHAR (20) NOT NULL, " + + " CITY VARCHAR (20) NOT NULL," + + " PRIMARY KEY (ID) );"; + + stmt.executeUpdate(createSQL); + // System.out.println("Create Table Result::" + createResult); + + String insertTableSQL = "INSERT INTO " + tableName + + "(ID, NAME, CITY) " + "VALUES" + + "(1,'frank lens','Dallas')"; + + stmt.executeUpdate(insertTableSQL); + // System.out.println("Insert Data Result::" + insertResult); + + logger.info("Database Test Init Data Created!!!"); + + } finally { + if (stmt != null) { + try { + stmt.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + if (conn != null) { + try { + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + + } + + public static void initTestData(DatabaseConfiguration dbConfig) + throws DatabaseServiceException, SQLException { + + Statement stmt = null; + Connection conn = null; + try { + DatabaseService dbService = DatabaseService.get(dbConfig.getDatabaseType()); + conn = dbService.getConnection(dbConfig); + stmt = conn.createStatement(); + + DatabaseMetaData dbm = conn.getMetaData(); + // check if "employee" table is there + ResultSet tables = dbm.getTables(null, null, DEFAULT_TEST_TABLE, null); + boolean dropTable = false; + if (tables.next()) { + dropTable = true; + // System.out.println("Drop Table Result::" + dropResult); + } + tables.close(); + if (dropTable) { + stmt.executeUpdate("DROP TABLE " + DEFAULT_TEST_TABLE); + // System.out.println("Drop Table Result::" + dropResult); + } + + String createSQL = " CREATE TABLE TEST_DATA( " + + " ID INT NOT NULL, " + + " NAME VARCHAR (20) NOT NULL, " + + " CITY VARCHAR (20) NOT NULL," + + " PRIMARY KEY (ID) );"; + + stmt.executeUpdate(createSQL); + // System.out.println("Create Table Result::" + createResult); + + String insertTableSQL = "INSERT INTO TEST_DATA" + + "(ID, NAME, CITY) " + "VALUES" + + "(1,'frank lens','Dallas')"; + + stmt.executeUpdate(insertTableSQL); + // System.out.println("Insert Data Result::" + insertResult); + + logger.info("Database Test Init Data Created!!!"); + + } finally { + if (stmt != null) { + try { + stmt.close(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + if (conn != null) { + try { + conn.close(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + } + + /** + * CREATE test data in MySQL Table name: test_data + * + * @param sampleSize + * @param batchSize + * @throws DatabaseServiceException + * @throws SQLException + */ + public void generateMySQLTestData(int sampleSize, int batchSize) + throws DatabaseServiceException, SQLException { + mncMap = new HashMap(); + mccMap = new HashMap(); + mccMap.put(0, 302); + mccMap.put(1, 311); + mccMap.put(2, 730); + mccMap.put(1, 622); + + mncMap.put(0, 006); + mncMap.put(1, 140); + mncMap.put(2, 380); + mncMap.put(3, 710); + + DatabaseConfiguration dc = new DatabaseConfiguration(); + dc.setDatabaseHost(DEFAULT_MYSQL_HOST); + dc.setDatabaseName(DEFAULT_MYSQL_DB_NAME); + dc.setDatabasePassword(DEFAULT_MYSQL_PASSWORD); + dc.setDatabasePort(DEFAULT_MYSQL_PORT); + dc.setDatabaseType(MYSQL_DB_NAME); + dc.setDatabaseUser(DEFAULT_MYSQL_USER); + dc.setUseSSL(false); + + String truncateTableSQL = "TRUNCATE test_data"; + + String insertTableSQL = "INSERT INTO test_data(" + + "id, ue_id, start_time, end_date, bytes_upload, bytes_download, cell_id, mcc, mnc, lac, imei)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; + + Connection conn = DatabaseService.get(MYSQL_DB_NAME).getConnection(dc); + + Statement truncateStmt = conn.createStatement(); + int result = truncateStmt.executeUpdate(truncateTableSQL); + System.out.println("Truncate Table Result::" + result); + truncateStmt.close(); + + conn.setAutoCommit(false); + + PreparedStatement stmt = conn.prepareStatement(insertTableSQL); + + int counter = 1; + for (int i = 0; i < sampleSize; i++) { + stmt.setLong(1, i); + stmt.setString(2, getNextUeId()); + stmt.setDate(3, getNextStartDate()); + stmt.setDate(4, getNextEndDate()); + stmt.setInt(5, rand.nextInt()); + stmt.setInt(6, rand.nextInt()); + stmt.setInt(7, rand.nextInt(10)); + stmt.setInt(8, getMCC()); + stmt.setInt(9, getMNC()); + stmt.setInt(10, rand.nextInt(100)); + stmt.setString(11, getNextIMEI()); + + stmt.addBatch(); + + // Execute batch of 1000 records + if (i % batchSize == 0) { + stmt.executeBatch(); + conn.commit(); + System.out.println("Batch " + (counter++) + " executed successfully"); + } + } + // execute final batch + stmt.executeBatch(); + System.out.println("Final Batch Executed " + (counter++) + " executed successfully"); + conn.commit(); + conn.close(); + } + + /** + * + * @param sampleSize + * @param batchSize + * @throws DatabaseServiceException + * @throws SQLException + */ + public void generatePgSQLTestData(int sampleSize, int batchSize) throws DatabaseServiceException, SQLException { + mncMap = new HashMap(); + mccMap = new HashMap(); + mccMap.put(0, 302); + mccMap.put(1, 311); + mccMap.put(2, 730); + mccMap.put(1, 622); + + mncMap.put(0, 006); + mncMap.put(1, 140); + mncMap.put(2, 380); + mncMap.put(3, 710); + + DatabaseConfiguration dc = new DatabaseConfiguration(); + dc.setDatabaseHost(DEFAULT_PGSQL_HOST); + dc.setDatabaseName(DEFAULT_PGSQL_DB_NAME); + dc.setDatabasePassword(DEFAULT_PGSQL_PASSWORD); + dc.setDatabasePort(DEFAULT_PGSQL_PORT); + dc.setDatabaseType(PGSQL_DB_NAME); + dc.setDatabaseUser(DEFAULT_PGSQL_USER); + dc.setUseSSL(false); + + String truncateTableSQL = "TRUNCATE public.test_data"; + + String insertTableSQL = "INSERT INTO public.test_data(" + + "id, ue_id, start_time, end_date, bytes_upload, bytes_download, cell_id, mcc, mnc, lac, imei)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; + + Connection conn = DatabaseService.get(PGSQL_DB_NAME).getConnection(dc); + + Statement truncateStmt = conn.createStatement(); + int result = truncateStmt.executeUpdate(truncateTableSQL); + System.out.println("Truncate Table Result::" + result); + truncateStmt.close(); + + conn.setAutoCommit(false); + + PreparedStatement stmt = conn.prepareStatement(insertTableSQL); + + int counter = 1; + for (int i = 0; i < sampleSize; i++) { + stmt.setLong(1, i); + stmt.setString(2, getNextUeId()); + stmt.setDate(3, getNextStartDate()); + stmt.setDate(4, getNextEndDate()); + stmt.setInt(5, rand.nextInt()); + stmt.setInt(6, rand.nextInt()); + stmt.setInt(7, rand.nextInt(10)); + stmt.setInt(8, getMCC()); + stmt.setInt(9, getMNC()); + stmt.setInt(10, rand.nextInt(100)); + stmt.setString(11, getNextIMEI()); + + stmt.addBatch(); + + // Execute batch of 1000 records + if (i % batchSize == 0) { + stmt.executeBatch(); + conn.commit(); + System.out.println("Batch " + (counter++) + " executed successfully"); + } + } + // execute final batch + stmt.executeBatch(); + System.out.println("Final Batch Executed " + (counter++) + " executed successfully"); + conn.commit(); + conn.close(); + + } + + private String getNextIMEI() { + int n = 1000000000 + rand.nextInt(900000000); + return "" + n; + } + + private int getMNC() { + + return mncMap.get(rand.nextInt(3)); + } + + private int getMCC() { + + return mccMap.get(rand.nextInt(3)); + } + + private Date getNextEndDate() { + + return new Date(System.currentTimeMillis() + 1); + } + + private Date getNextStartDate() { + + return new Date(System.currentTimeMillis()); + } + + private String getNextUeId() { + + int n = 300000000 + rand.nextInt(900000000); + + return "" + n; + } + + public static void main(String[] args) throws DatabaseServiceException, SQLException { + DBExtensionTestUtils testUtil = new DBExtensionTestUtils(); + testUtil.generatePgSQLTestData(SAMPLE_SIZE, BATCH_SIZE); + // testUtil.generateMySQLTestData(); + } + + public static void cleanUpTestData(DatabaseConfiguration dbConfig) { + Statement stmt = null; + Connection conn = null; + try { + DatabaseService dbService = DatabaseService.get(dbConfig.getDatabaseType()); + conn = dbService.getConnection(dbConfig); + stmt = conn.createStatement(); + + DatabaseMetaData dbm = conn.getMetaData(); + // check if "employee" table is there + ResultSet tables = dbm.getTables(null, null, DEFAULT_TEST_TABLE, null); + if (tables.next()) { + stmt.executeUpdate("DROP TABLE " + DEFAULT_TEST_TABLE); + // System.out.println("Drop Table Result::" + dropResult); + } + + logger.info("Database Test Cleanup Done"); + + } catch (DatabaseServiceException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + if (stmt != null) { + try { + stmt.close(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + if (conn != null) { + try { + conn.close(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + } + + public static File createTempDirectory(String name) + throws IOException { + File dir = File.createTempFile(name, ""); + dir.delete(); + dir.mkdir(); + return dir; + } + + public static String getJDBCUrl(DatabaseConfiguration dbConfig) { + Map substitutes = new HashMap(); + substitutes.put("dbType", dbConfig.getDatabaseType()); + substitutes.put("host", dbConfig.getDatabaseHost()); + substitutes.put("port", "" + dbConfig.getDatabasePort()); + substitutes.put("dbName", dbConfig.getDatabaseName()); + substitutes.put("useSSL", dbConfig.isUseSSL()); + String urlTemplate = "jdbc:${dbType}://${host}:${port}/${dbName}?useSSL=${useSSL}"; + StringSubstitutor strSub = new StringSubstitutor(substitutes); + return strSub.replace(urlTemplate); + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DBExtensionTests.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DBExtensionTests.java new file mode 100644 index 000000000..bd1d0bc11 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DBExtensionTests.java @@ -0,0 +1,72 @@ +/* + +Copyright 2010,2011 Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +package com.google.refine.extension.database; + +import java.util.Properties; + +import org.slf4j.Logger; + +public class DBExtensionTests { + + protected final String MYSQL_DB_NAME = "mysql"; + protected final String DEFAULT_MYSQL_HOST = "127.0.0.1"; + protected final String DEFAULT_MYSQL_PORT = "3306"; + protected final String DEFAULT_MYSQL_USER = "root"; + protected final String DEFAULT_MYSQL_PASSWORD = "secret"; + protected final String DEFAULT_MYSQL_DB_NAME = "testdb"; + + protected final String PGSQL_DB_NAME = "postgresql"; + protected final String DEFAULT_PGSQL_HOST = "127.0.0.1"; + protected final String DEFAULT_PGSQL_PORT = "5432"; + protected final String DEFAULT_PGSQL_USER = "postgres"; + protected final String DEFAULT_PGSQL_PASSWORD = ""; + protected final String DEFAULT_PGSQL_DB_NAME = "testdb"; + + protected final String MARIA_DB_NAME = "mariadb"; + protected final String DEFAULT_MARIADB_HOST = "127.0.0.1"; + protected final String DEFAULT_MARIADB_PORT = "3306"; + protected final String DEFAULT_MARIADB_USER = "root"; + protected final String DEFAULT_MARIADB_PASSWORD = "secret"; + protected final String DEFAULT_MARIADB_NAME = "testdb"; + + protected final String SQLITE_DB_NAME = "sqlite"; + protected final String DEFAULT_SQLITE_DB_NAME = "extension_test_db.sqlite"; + + protected final String DEFAULT_TEST_TABLE = "test_data"; + + protected Properties properties; + + protected Logger logger; + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DatabaseImportControllerTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DatabaseImportControllerTest.java new file mode 100644 index 000000000..561994872 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DatabaseImportControllerTest.java @@ -0,0 +1,247 @@ + +package com.google.refine.extension.database; + +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.refine.ProjectManager; +import com.google.refine.ProjectMetadata; +import com.google.refine.RefineServlet; +import com.google.refine.extension.database.mysql.MySQLDatabaseService; +import com.google.refine.extension.database.stub.RefineDbServletStub; +import com.google.refine.importing.ImportingJob; +import com.google.refine.importing.ImportingManager; +import com.google.refine.io.FileProjectManager; +import com.google.refine.model.Project; +import com.google.refine.util.ParsingUtilities; + +@Test(groups = { "requiresMySQL" }) +public class DatabaseImportControllerTest extends DBExtensionTests { + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + private Project project; + private ProjectMetadata metadata; + private ImportingJob job; + private RefineServlet servlet; + + private String JSON_OPTION = "{\"mode\":\"row-based\"}}"; + + private DatabaseConfiguration testDbConfig; + + private String query; + + // System under test + private DatabaseImportController SUT = null; + + @BeforeMethod + public void setUp() throws IOException { + MockitoAnnotations.initMocks(this); + + File dir = DBExtensionTestUtils.createTempDirectory("OR_DBExtension_Test_WorkspaceDir"); + FileProjectManager.initialize(dir); + + servlet = new RefineDbServletStub(); + ImportingManager.initialize(servlet); + project = new Project(); + metadata = new ProjectMetadata(); + job = ImportingManager.createJob(); + + metadata.setName("Database Import Test Project"); + ProjectManager.singleton.registerProject(project, metadata); + SUT = new DatabaseImportController(); + + } + + @AfterMethod + public void tearDown() { + SUT = null; + request = null; + response = null; + project = null; + metadata = null; + ImportingManager.disposeJob(job.id); + job = null; + // options = null; + } + + @Test + public void testDoGet() { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + try { + when(response.getWriter()).thenReturn(pw); + + SUT.doGet(request, response); + + String result = sw.getBuffer().toString().trim(); + ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class); + String code = json.get("status").asText(); + String message = json.get("message").asText(); + Assert.assertNotNull(code); + Assert.assertNotNull(message); + Assert.assertEquals(code, "error"); + Assert.assertEquals(message, "GET not implemented"); + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testDoPostInvalidSubCommand() throws IOException, ServletException { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + when(request.getQueryString()).thenReturn( + "http://127.0.0.1:3333/command/core/importing-controller?controller=database/database-import-controller&subCommand=invalid-sub-command"); + + when(response.getWriter()).thenReturn(pw); + // test + SUT.doPost(request, response); + + String result = sw.getBuffer().toString().trim(); + ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class); + + String code = json.get("status").asText(); + String message = json.get("message").asText(); + Assert.assertNotNull(code); + Assert.assertNotNull(message); + Assert.assertEquals(code, "error"); + Assert.assertEquals(message, "No such sub command"); + } + + @Test + public void testDoPostInitializeParser() throws ServletException, IOException { + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + when(request.getQueryString()).thenReturn( + "http://127.0.0.1:3333/command/core/importing-controller?controller=database/database-import-controller&subCommand=initialize-parser-ui"); + when(response.getWriter()).thenReturn(pw); + + SUT.doPost(request, response); + + String result = sw.getBuffer().toString().trim(); + ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class); + + String status = json.get("status").asText(); + // System.out.println("json::" + json); + Assert.assertEquals(status, "ok"); + } + + @Test + public void testDoPostParsePreview() throws IOException, ServletException { + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + long jobId = job.id; + + when(request.getQueryString()).thenReturn( + "http://127.0.0.1:3333/command/core/importing-controller?controller=database%2Fdatabase-import-controller&jobID=" + + jobId + "&subCommand=parse-preview"); + when(response.getWriter()).thenReturn(pw); + + when(request.getParameter("databaseType")).thenReturn(testDbConfig.getDatabaseType()); + when(request.getParameter("databaseServer")).thenReturn(testDbConfig.getDatabaseHost()); + when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort()); + when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser()); + when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword()); + when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName()); + when(request.getParameter("query")).thenReturn(query); + when(request.getParameter("options")).thenReturn(JSON_OPTION); + + SUT.doPost(request, response); + + String result = sw.getBuffer().toString().trim(); + ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class); + + String status = json.get("status").asText(); + // System.out.println("json::" + json); + Assert.assertEquals(status, "ok"); + } + + @Test + public void testDoPostCreateProject() throws IOException, ServletException { + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + long jobId = job.id; + + when(request.getQueryString()).thenReturn( + "http://127.0.0.1:3333/command/core/importing-controller?controller=database%2Fdatabase-import-controller&jobID=" + + jobId + "&subCommand=create-project"); + when(response.getWriter()).thenReturn(pw); + + when(request.getParameter("databaseType")).thenReturn(testDbConfig.getDatabaseType()); + when(request.getParameter("databaseServer")).thenReturn(testDbConfig.getDatabaseHost()); + when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort()); + when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser()); + when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword()); + when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName()); + when(request.getParameter("query")).thenReturn(query); + when(request.getParameter("options")).thenReturn(JSON_OPTION); + + SUT.doPost(request, response); + + String result = sw.getBuffer().toString().trim(); + ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class); + + String status = json.get("status").asText(); + // System.out.println("json::" + json); + Assert.assertEquals(status, "ok"); + } + + @BeforeTest + @Parameters({ "mySqlDbName", "mySqlDbHost", "mySqlDbPort", "mySqlDbUser", "mySqlDbPassword", "mySqlTestTable" }) + public void beforeTest( + @Optional(DEFAULT_MYSQL_DB_NAME) String mySqlDbName, @Optional(DEFAULT_MYSQL_HOST) String mySqlDbHost, + @Optional(DEFAULT_MYSQL_PORT) String mySqlDbPort, @Optional(DEFAULT_MYSQL_USER) String mySqlDbUser, + @Optional(DEFAULT_MYSQL_PASSWORD) String mySqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String mySqlTestTable) { + + MockitoAnnotations.initMocks(this); + + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(mySqlDbHost); + testDbConfig.setDatabaseName(mySqlDbName); + testDbConfig.setDatabasePassword(mySqlDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(mySqlDbPort)); + testDbConfig.setDatabaseType(MySQLDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(mySqlDbUser); + testDbConfig.setUseSSL(false); + query = "SELECT count(*) FROM " + mySqlTestTable; + + // testTable = mySqlTestTable; + + DatabaseService.DBType.registerDatabase(MySQLDatabaseService.DB_NAME, MySQLDatabaseService.getInstance()); + + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DatabaseServiceTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DatabaseServiceTest.java new file mode 100644 index 000000000..c43cf7a51 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/DatabaseServiceTest.java @@ -0,0 +1,149 @@ + +package com.google.refine.extension.database; + +import java.sql.Connection; +import java.util.List; + +import com.google.refine.extension.database.sqlite.SQLiteDatabaseService; +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.google.refine.extension.database.mariadb.MariaDBDatabaseService; +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.extension.database.model.DatabaseRow; +import com.google.refine.extension.database.mysql.MySQLDatabaseService; +import com.google.refine.extension.database.pgsql.PgSQLDatabaseService; + +public class DatabaseServiceTest extends DBExtensionTests { + + private DatabaseConfiguration testDbConfig; + private String testTable; + + @BeforeTest + @Parameters({ "mySqlDbName", "mySqlDbHost", "mySqlDbPort", "mySqlDbUser", "mySqlDbPassword", "mySqlTestTable" }) + public void beforeTest(@Optional(DEFAULT_MYSQL_DB_NAME) String mySqlDbName, @Optional(DEFAULT_MYSQL_HOST) String mySqlDbHost, + @Optional(DEFAULT_MYSQL_PORT) String mySqlDbPort, @Optional(DEFAULT_MYSQL_USER) String mySqlDbUser, + @Optional(DEFAULT_MYSQL_PASSWORD) String mySqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String mySqlTestTable) { + + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(mySqlDbHost); + testDbConfig.setDatabaseName(mySqlDbName); + testDbConfig.setDatabasePassword(mySqlDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(mySqlDbPort)); + testDbConfig.setDatabaseType(MySQLDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(mySqlDbUser); + testDbConfig.setUseSSL(false); + + testTable = mySqlTestTable; + // DBExtensionTestUtils.initTestData(testDbConfig); + + DatabaseService.DBType.registerDatabase(MariaDBDatabaseService.DB_NAME, MariaDBDatabaseService.getInstance()); + DatabaseService.DBType.registerDatabase(MySQLDatabaseService.DB_NAME, MySQLDatabaseService.getInstance()); + DatabaseService.DBType.registerDatabase(PgSQLDatabaseService.DB_NAME, PgSQLDatabaseService.getInstance()); + + } + + @Test + public void testGetDatabaseUrl() { + DatabaseService dbService = DatabaseService.get(testDbConfig.getDatabaseType()); + String dbUrl = dbService.getDatabaseUrl(testDbConfig); + Assert.assertNotNull(dbUrl); + Assert.assertEquals(dbUrl, DBExtensionTestUtils.getJDBCUrl(testDbConfig)); + } + + @Test(groups = { "requiresPgSQL" }) + public void testGetPgSQLDBService() { + DatabaseService dbService = DatabaseService.get(PgSQLDatabaseService.DB_NAME); + Assert.assertNotNull(dbService); + Assert.assertEquals(dbService.getClass(), PgSQLDatabaseService.class); + } + + @Test(groups = { "requiresMySQL" }) + public void testGetMySQLDBService() { + + DatabaseService dbService = DatabaseService.get(MySQLDatabaseService.DB_NAME); + Assert.assertNotNull(dbService); + Assert.assertEquals(dbService.getClass(), MySQLDatabaseService.class); + } + + @Test(groups = { "requiresMariaDB" }) + public void testGetMariaDBSQLDBService() { + + DatabaseService dbService = DatabaseService.get(MariaDBDatabaseService.DB_NAME); + Assert.assertNotNull(dbService); + Assert.assertEquals(dbService.getClass(), MariaDBDatabaseService.class); + } + + @Test(groups = { "requiresSQLite" }) + public void testGetSQLiteDBService() { + + DatabaseService dbService = DatabaseService.get(SQLiteDatabaseService.DB_NAME); + Assert.assertNotNull(dbService); + Assert.assertEquals(dbService.getClass(), SQLiteDatabaseService.class); + } + + @Test(groups = { "requiresMySQL" }) + public void testGetConnection() throws DatabaseServiceException { + DatabaseService dbService = DatabaseService.get(testDbConfig.getDatabaseType()); + Connection conn = dbService.getConnection(testDbConfig); + Assert.assertNotNull(conn); + } + + @Test(groups = { "requiresMySQL" }) + public void testTestConnection() throws DatabaseServiceException { + DatabaseService dbService = DatabaseService.get(testDbConfig.getDatabaseType()); + boolean result = dbService.testConnection(testDbConfig); + Assert.assertEquals(result, true); + } + + @Test(groups = { "requiresMySQL" }) + public void testConnect() throws DatabaseServiceException { + DatabaseService dbService = DatabaseService.get(testDbConfig.getDatabaseType()); + DatabaseInfo databaseInfo = dbService.connect(testDbConfig); + Assert.assertNotNull(databaseInfo); + } + + @Test(groups = { "requiresMySQL" }) + public void testExecuteQuery() throws DatabaseServiceException { + DatabaseService dbService = DatabaseService.get(testDbConfig.getDatabaseType()); + DatabaseInfo databaseInfo = dbService.testQuery(testDbConfig, + "SELECT * FROM " + testTable); + + Assert.assertNotNull(databaseInfo); + } + + @Test + public void testBuildLimitQuery() { + DatabaseService dbService = DatabaseService.get(testDbConfig.getDatabaseType()); + String limitQuery = dbService.buildLimitQuery(100, 0, "SELECT * FROM " + testTable); + Assert.assertNotNull(limitQuery); + Assert.assertEquals(limitQuery, "SELECT * FROM (SELECT * FROM " + testTable + ") data LIMIT " + 100 + " OFFSET " + 0 + ";"); + } + + @Test(groups = { "requiresMySQL" }) + public void testGetColumns() throws DatabaseServiceException { + List dbColumns; + + DatabaseService dbService = DatabaseService.get(testDbConfig.getDatabaseType()); + dbColumns = dbService.getColumns(testDbConfig, "SELECT * FROM " + testTable); + Assert.assertNotNull(dbColumns); + + int cols = dbColumns.size(); + Assert.assertEquals(cols, 10); + } + + @Test(groups = { "requiresMySQL" }) + public void testGetRows() throws DatabaseServiceException { + DatabaseService dbService = DatabaseService.get(testDbConfig.getDatabaseType()); + List dbRows = dbService.getRows(testDbConfig, + "SELECT * FROM " + testTable); + + Assert.assertNotNull(dbRows); + Assert.assertEquals(dbRows.size(), 1); + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitMariaDBTestDatabase.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitMariaDBTestDatabase.java new file mode 100644 index 000000000..9a25dc399 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitMariaDBTestDatabase.java @@ -0,0 +1,44 @@ + +package com.google.refine.extension.database; + +import java.sql.SQLException; + +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.google.refine.extension.database.mariadb.MariaDBDatabaseService; + +@Test(groups = { "requiresMariaDB" }) +public class InitMariaDBTestDatabase extends DBExtensionTests { + + private DatabaseConfiguration mariadbDbConfig; + + @BeforeSuite + @Parameters({ "mariadbDbName", "mariadbDbHost", "mariadbDbPort", "mariadbDbUser", "mariadbDbPassword", "mariadbTestTable" }) + public void beforeSuite( + @Optional(DEFAULT_MARIADB_NAME) String mariadbDbName, @Optional(DEFAULT_MARIADB_HOST) String mariadbDbHost, + @Optional(DEFAULT_MARIADB_PORT) String mariadbDbPort, @Optional(DEFAULT_MARIADB_USER) String mariadbDbUser, + @Optional(DEFAULT_MARIADB_PASSWORD) String mariadbDbPassword, @Optional(DEFAULT_TEST_TABLE) String mariadbTestTable) + throws DatabaseServiceException, SQLException { + + mariadbDbConfig = new DatabaseConfiguration(); + mariadbDbConfig.setDatabaseHost(mariadbDbHost); + mariadbDbConfig.setDatabaseName(mariadbDbName); + mariadbDbConfig.setDatabasePassword(mariadbDbPassword); + mariadbDbConfig.setDatabasePort(Integer.parseInt(mariadbDbPort)); + mariadbDbConfig.setDatabaseType(MariaDBDatabaseService.DB_NAME); + mariadbDbConfig.setDatabaseUser(mariadbDbUser); + mariadbDbConfig.setUseSSL(false); + + DBExtensionTestUtils.initTestData(mariadbDbConfig); + } + + @AfterSuite + public void afterSuite() { + DBExtensionTestUtils.cleanUpTestData(mariadbDbConfig); + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitMySQLTestDatabase.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitMySQLTestDatabase.java new file mode 100644 index 000000000..3125fa30b --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitMySQLTestDatabase.java @@ -0,0 +1,44 @@ + +package com.google.refine.extension.database; + +import java.sql.SQLException; + +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.google.refine.extension.database.mysql.MySQLDatabaseService; + +@Test(groups = { "requiresMySQL" }) +public class InitMySQLTestDatabase extends DBExtensionTests { + + private DatabaseConfiguration mysqlDbConfig; + + @BeforeSuite + @Parameters({ "mySqlDbName", "mySqlDbHost", "mySqlDbPort", "mySqlDbUser", "mySqlDbPassword", "mySqlTestTable" }) + public void beforeSuite( + @Optional(DEFAULT_MYSQL_DB_NAME) String mySqlDbName, @Optional(DEFAULT_MYSQL_HOST) String mySqlDbHost, + @Optional(DEFAULT_MYSQL_PORT) String mySqlDbPort, @Optional(DEFAULT_MYSQL_USER) String mySqlDbUser, + @Optional(DEFAULT_MYSQL_PASSWORD) String mySqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String mySqlTestTable) + throws DatabaseServiceException, SQLException { + + // System.out.println("@BeforeSuite\n"); + mysqlDbConfig = new DatabaseConfiguration(); + mysqlDbConfig.setDatabaseHost(mySqlDbHost); + mysqlDbConfig.setDatabaseName(mySqlDbName); + mysqlDbConfig.setDatabasePassword(mySqlDbPassword); + mysqlDbConfig.setDatabasePort(Integer.parseInt(mySqlDbPort)); + mysqlDbConfig.setDatabaseType(MySQLDatabaseService.DB_NAME); + mysqlDbConfig.setDatabaseUser(mySqlDbUser); + mysqlDbConfig.setUseSSL(false); + + DBExtensionTestUtils.initTestData(mysqlDbConfig); + } + + @AfterSuite + public void afterSuite() { + DBExtensionTestUtils.cleanUpTestData(mysqlDbConfig); + } +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitPostgresTestDatabase.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitPostgresTestDatabase.java new file mode 100644 index 000000000..435f608f0 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitPostgresTestDatabase.java @@ -0,0 +1,43 @@ + +package com.google.refine.extension.database; + +import java.sql.SQLException; + +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.google.refine.extension.database.pgsql.PgSQLDatabaseService; + +@Test(groups = { "requiresPgSQL" }) +public class InitPostgresTestDatabase extends DBExtensionTests { + + private DatabaseConfiguration pgsqlDbConfig; + + @BeforeSuite + @Parameters({ "pgSqlDbName", "pgSqlDbHost", "pgSqlDbPort", "pgSqlDbUser", "pgSqlDbPassword", "pgSqlTestTable" }) + public void beforeSuite( + @Optional(DEFAULT_PGSQL_DB_NAME) String pgSqlDbName, @Optional(DEFAULT_PGSQL_HOST) String pgSqlDbHost, + @Optional(DEFAULT_PGSQL_PORT) String pgSqlDbPort, @Optional(DEFAULT_PGSQL_USER) String pgSqlDbUser, + @Optional(DEFAULT_PGSQL_PASSWORD) String pgSqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String pgSqlTestTable) + throws DatabaseServiceException, SQLException { + + pgsqlDbConfig = new DatabaseConfiguration(); + pgsqlDbConfig.setDatabaseHost(pgSqlDbHost); + pgsqlDbConfig.setDatabaseName(pgSqlDbName); + pgsqlDbConfig.setDatabasePassword(pgSqlDbPassword); + pgsqlDbConfig.setDatabasePort(Integer.parseInt(pgSqlDbPort)); + pgsqlDbConfig.setDatabaseType(PgSQLDatabaseService.DB_NAME); + pgsqlDbConfig.setDatabaseUser(pgSqlDbUser); + pgsqlDbConfig.setUseSSL(false); + + DBExtensionTestUtils.initTestData(pgsqlDbConfig); + } + + @AfterSuite + public void afterSuite() { + DBExtensionTestUtils.cleanUpTestData(pgsqlDbConfig); + } +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitSQLiteTestDatabase.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitSQLiteTestDatabase.java new file mode 100644 index 000000000..aadd432f4 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/InitSQLiteTestDatabase.java @@ -0,0 +1,33 @@ + +package com.google.refine.extension.database; + +import java.sql.SQLException; + +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +@Test(groups = { "requiresMariaDB" }) +public class InitSQLiteTestDatabase extends DBExtensionTests { + + private DatabaseConfiguration sqliteDbConfig; + + @BeforeSuite + @Parameters({ "sqliteDbName", "sqliteTestTable" }) + public void beforeSuite( + @Optional(DEFAULT_SQLITE_DB_NAME) String sqliteDbName, @Optional(DEFAULT_TEST_TABLE) String sqliteTestTable) + throws DatabaseServiceException, SQLException { + + sqliteDbConfig = new DatabaseConfiguration(); + sqliteDbConfig.setDatabaseName(sqliteDbName); + + DBExtensionTestUtils.initTestData(sqliteDbConfig); + } + + @AfterSuite + public void afterSuite() { + DBExtensionTestUtils.cleanUpTestData(sqliteDbConfig); + } +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/SimpleTextEncryptorTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/SimpleTextEncryptorTest.java new file mode 100644 index 000000000..db4d15646 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/SimpleTextEncryptorTest.java @@ -0,0 +1,29 @@ + +package com.google.refine.extension.database; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class SimpleTextEncryptorTest { + + @Test + public void encrypt() { + SimpleTextEncryptor textEncryptor = new SimpleTextEncryptor("WEWssa!@d445d"); + String password = "testpass"; + String encPass = textEncryptor.encrypt(password); + Assert.assertNotNull(encPass); + Assert.assertNotEquals(encPass, password); + + } + + @Test + public void decrypt() { + SimpleTextEncryptor textEncryptor = new SimpleTextEncryptor("OOEWssa!@d445d"); + String password = "testpass"; + String encPass = textEncryptor.encrypt(password); + Assert.assertNotNull(encPass); + Assert.assertNotEquals(encPass, password); + String decPass = textEncryptor.decrypt(encPass); + Assert.assertEquals(decPass, password); + } +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/ConnectCommandTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/ConnectCommandTest.java new file mode 100644 index 000000000..ca6c1038b --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/ConnectCommandTest.java @@ -0,0 +1,110 @@ + +package com.google.refine.extension.database.cmd; + +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.refine.commands.Command; +import com.google.refine.extension.database.DBExtensionTests; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.mysql.MySQLDatabaseService; +import com.google.refine.util.ParsingUtilities; + +@Test(groups = { "requiresMySQL" }) +public class ConnectCommandTest extends DBExtensionTests { + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + private DatabaseConfiguration testDbConfig; + // private String testTable; + + @BeforeTest + @Parameters({ "mySqlDbName", "mySqlDbHost", "mySqlDbPort", "mySqlDbUser", "mySqlDbPassword", "mySqlTestTable" }) + public void beforeTest(@Optional(DEFAULT_MYSQL_DB_NAME) String mySqlDbName, @Optional(DEFAULT_MYSQL_HOST) String mySqlDbHost, + @Optional(DEFAULT_MYSQL_PORT) String mySqlDbPort, @Optional(DEFAULT_MYSQL_USER) String mySqlDbUser, + @Optional(DEFAULT_MYSQL_PASSWORD) String mySqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String mySqlTestTable) { + + MockitoAnnotations.initMocks(this); + + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(mySqlDbHost); + testDbConfig.setDatabaseName(mySqlDbName); + testDbConfig.setDatabasePassword(mySqlDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(mySqlDbPort)); + testDbConfig.setDatabaseType(MySQLDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(mySqlDbUser); + testDbConfig.setUseSSL(false); + + // testTable = mySqlTestTable; + // DBExtensionTestUtils.initTestData(testDbConfig); + + DatabaseService.DBType.registerDatabase(MySQLDatabaseService.DB_NAME, MySQLDatabaseService.getInstance()); + + } + + @Test + public void testDoPost() throws IOException, ServletException { + + when(request.getParameter("databaseType")).thenReturn(MySQLDatabaseService.DB_NAME); + when(request.getParameter("databaseServer")).thenReturn(testDbConfig.getDatabaseHost()); + when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort()); + when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser()); + when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword()); + when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName()); + when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken()); + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + ConnectCommand connectCommand = new ConnectCommand(); + + connectCommand.doPost(request, response); + + String result = sw.getBuffer().toString().trim(); + ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class); + + String code = json.get("code").asText(); + Assert.assertEquals(code, "ok"); + + String databaseInfo = json.get("databaseInfo").asText(); + Assert.assertNotNull(databaseInfo); + } + + @Test + public void testCsrfProtection() throws ServletException, IOException { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + ConnectCommand connectCommand = new ConnectCommand(); + + connectCommand.doPost(request, response); + Assert.assertEquals( + ParsingUtilities.mapper.readValue("{\"code\":\"error\",\"message\":\"Missing or invalid csrf_token parameter\"}", + ObjectNode.class), + ParsingUtilities.mapper.readValue(sw.toString(), ObjectNode.class)); + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/ExecuteQueryCommandTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/ExecuteQueryCommandTest.java new file mode 100644 index 000000000..95fbb3d74 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/ExecuteQueryCommandTest.java @@ -0,0 +1,110 @@ + +package com.google.refine.extension.database.cmd; + +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.refine.commands.Command; +import com.google.refine.extension.database.DBExtensionTests; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.mysql.MySQLDatabaseService; +import com.google.refine.util.ParsingUtilities; + +@Test(groups = { "requiresMySQL" }) +public class ExecuteQueryCommandTest extends DBExtensionTests { + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + private DatabaseConfiguration testDbConfig; + private String testTable; + + @BeforeTest + @Parameters({ "mySqlDbName", "mySqlDbHost", "mySqlDbPort", "mySqlDbUser", "mySqlDbPassword", "mySqlTestTable" }) + public void beforeTest(@Optional(DEFAULT_MYSQL_DB_NAME) String mySqlDbName, @Optional(DEFAULT_MYSQL_HOST) String mySqlDbHost, + @Optional(DEFAULT_MYSQL_PORT) String mySqlDbPort, @Optional(DEFAULT_MYSQL_USER) String mySqlDbUser, + @Optional(DEFAULT_MYSQL_PASSWORD) String mySqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String mySqlTestTable) { + + MockitoAnnotations.initMocks(this); + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(mySqlDbHost); + testDbConfig.setDatabaseName(mySqlDbName); + testDbConfig.setDatabasePassword(mySqlDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(mySqlDbPort)); + testDbConfig.setDatabaseType(MySQLDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(mySqlDbUser); + testDbConfig.setUseSSL(false); + + testTable = mySqlTestTable; + // DBExtensionTestUtils.initTestData(testDbConfig); + + DatabaseService.DBType.registerDatabase(MySQLDatabaseService.DB_NAME, MySQLDatabaseService.getInstance()); + + } + + @Test + public void testDoPost() throws IOException, ServletException { + + when(request.getParameter("databaseType")).thenReturn(testDbConfig.getDatabaseType()); + when(request.getParameter("databaseServer")).thenReturn(testDbConfig.getDatabaseHost()); + when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort()); + when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser()); + when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword()); + when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName()); + when(request.getParameter("queryString")).thenReturn("SELECT count(*) FROM " + testTable); + when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken()); + + StringWriter sw = new StringWriter(); + + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + ExecuteQueryCommand executeQueryCommand = new ExecuteQueryCommand(); + + executeQueryCommand.doPost(request, response); + + String result = sw.getBuffer().toString().trim(); + ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class); + + String code = json.get("code").asText(); + Assert.assertEquals(code, "ok"); + + String queryResult = json.get("QueryResult").asText(); + Assert.assertNotNull(queryResult); + } + + @Test + public void testCsrfProtection() throws ServletException, IOException { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + ConnectCommand connectCommand = new ConnectCommand(); + + connectCommand.doPost(request, response); + Assert.assertEquals( + ParsingUtilities.mapper.readValue("{\"code\":\"error\",\"message\":\"Missing or invalid csrf_token parameter\"}", + ObjectNode.class), + ParsingUtilities.mapper.readValue(sw.toString(), ObjectNode.class)); + } +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/SavedConnectionCommandTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/SavedConnectionCommandTest.java new file mode 100644 index 000000000..40f709693 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/SavedConnectionCommandTest.java @@ -0,0 +1,337 @@ + +package com.google.refine.extension.database.cmd; + +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.times; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.http.HttpStatus; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.refine.ProjectManager; +import com.google.refine.ProjectMetadata; +import com.google.refine.RefineServlet; +import com.google.refine.commands.Command; +import com.google.refine.extension.database.DBExtensionTestUtils; +import com.google.refine.extension.database.DBExtensionTests; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.mysql.MySQLDatabaseService; +import com.google.refine.extension.database.stub.RefineDbServletStub; +import com.google.refine.importing.ImportingManager; +import com.google.refine.io.FileProjectManager; +import com.google.refine.model.Project; +import com.google.refine.util.ParsingUtilities; + +public class SavedConnectionCommandTest extends DBExtensionTests { + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + private DatabaseConfiguration testDbConfig; + + private Project project; + private ProjectMetadata metadata; + // private ImportingJob job; + private RefineServlet servlet; + + // private String JSON_OPTION = "{\"mode\":\"row-based\"}}"; + + // System under test + private SavedConnectionCommand SUT = null; + + @BeforeMethod + public void setUp() throws IOException { + MockitoAnnotations.initMocks(this); + + File dir = DBExtensionTestUtils.createTempDirectory("OR_DBExtension_Test_WorkspaceDir"); + FileProjectManager.initialize(dir); + + servlet = new RefineDbServletStub(); + ImportingManager.initialize(servlet); + project = new Project(); + metadata = new ProjectMetadata(); + // job = ImportingManager.createJob(); + + metadata.setName("Save DB Config Test Project"); + ProjectManager.singleton.registerProject(project, metadata); + SUT = new SavedConnectionCommand(); + + } + + @AfterMethod + public void tearDown() { + SUT = null; + request = null; + response = null; + project = null; + metadata = null; + // ImportingManager.disposeJob(job.id); + // job = null; + // options = null; + } + + @BeforeTest + @Parameters({ "mySqlDbName", "mySqlDbHost", "mySqlDbPort", "mySqlDbUser", "mySqlDbPassword", "mySqlTestTable" }) + public void beforeTest(@Optional(DEFAULT_MYSQL_DB_NAME) String mySqlDbName, @Optional(DEFAULT_MYSQL_HOST) String mySqlDbHost, + @Optional(DEFAULT_MYSQL_PORT) String mySqlDbPort, @Optional(DEFAULT_MYSQL_USER) String mySqlDbUser, + @Optional(DEFAULT_MYSQL_PASSWORD) String mySqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String mySqlTestTable) { + + // MockitoAnnotations.initMocks(this); + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(mySqlDbHost); + testDbConfig.setDatabaseName(mySqlDbName); + testDbConfig.setDatabasePassword(mySqlDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(mySqlDbPort)); + testDbConfig.setDatabaseType(MySQLDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(mySqlDbUser); + testDbConfig.setUseSSL(false); + + DatabaseService.DBType.registerDatabase(MySQLDatabaseService.DB_NAME, MySQLDatabaseService.getInstance()); + + } + + private void saveDatabaseConfiguration(String savedDbName) { + + when(request.getParameter("connectionName")).thenReturn(savedDbName); + when(request.getParameter("databaseType")).thenReturn(MySQLDatabaseService.DB_NAME); + when(request.getParameter("databaseServer")).thenReturn(testDbConfig.getDatabaseHost()); + when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort()); + when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser()); + when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword()); + when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName()); + when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken()); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + try { + when(response.getWriter()).thenReturn(pw); + + SUT.doPost(request, response); + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + @Test + public void testDoPost() throws IOException, ServletException { + + when(request.getParameter("connectionName")).thenReturn("test-db-name"); + when(request.getParameter("databaseType")).thenReturn(MySQLDatabaseService.DB_NAME); + when(request.getParameter("databaseServer")).thenReturn(testDbConfig.getDatabaseHost()); + when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort()); + when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser()); + when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword()); + when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName()); + when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken()); + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + + SUT.doPost(request, response); + + String result = sw.getBuffer().toString().trim(); + assertNotNull(result); + assertFalse(result.isEmpty(), "Valid response Message expected!"); + + ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class); + // System.out.println("json:" + json); + + ArrayNode savedConnections = (ArrayNode) json.get("savedConnections"); + Assert.assertNotNull(savedConnections); + + int len = savedConnections.size(); + + Assert.assertEquals(len, 1); + } + + @Test + public void testDoGet() throws IOException, ServletException { + String testDbName = "testLocalDb"; + // add saved connection + saveDatabaseConfiguration(testDbName); + + when(request.getParameter("connectionName")).thenReturn(testDbName); + when(request.getParameter("databaseType")).thenReturn(MySQLDatabaseService.DB_NAME); + when(request.getParameter("databaseServer")).thenReturn(testDbConfig.getDatabaseHost()); + when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort()); + when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser()); + when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword()); + when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName()); + when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken()); + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + + SUT.doGet(request, response); + + ObjectNode json = ParsingUtilities.mapper.readValue(sw.getBuffer().toString().trim(), ObjectNode.class); + + ArrayNode savedConnections = (ArrayNode) json.get("savedConnections"); + Assert.assertNotNull(savedConnections); + + Assert.assertEquals(savedConnections.size(), 1); + + ObjectNode sc = (ObjectNode) savedConnections.get(0); + String connName = sc.get("connectionName").asText(); + Assert.assertEquals(connName, testDbName); + } + + @Test + public void testDoPut() throws IOException, ServletException { + String testDbName = "testLocalDb"; + saveDatabaseConfiguration(testDbName); + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + + // modify database config + String newHost = "localhost"; + when(request.getParameter("connectionName")).thenReturn(testDbName); + when(request.getParameter("databaseType")).thenReturn(MySQLDatabaseService.DB_NAME); + when(request.getParameter("databaseServer")).thenReturn(newHost); + when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort()); + when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser()); + when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword()); + when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName()); + when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken()); + + SUT.doPut(request, response); + + ObjectNode json = ParsingUtilities.mapper.readValue(sw.getBuffer().toString().trim(), ObjectNode.class); + ArrayNode savedConnections = (ArrayNode) json.get("savedConnections"); + Assert.assertNotNull(savedConnections); + + Assert.assertEquals(savedConnections.size(), 1); + + ObjectNode sc = (ObjectNode) savedConnections.get(0); + String newDbHost = sc.get("databaseHost").asText(); + Assert.assertEquals(newDbHost, newHost); + } + + @Test + public void testDoDeleteValidConnectionName() { + String testDbName = "testLocalDb"; + saveDatabaseConfiguration(testDbName); + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + try { + when(response.getWriter()).thenReturn(pw); + when(request.getParameter("connectionName")).thenReturn(testDbName); + SUT.doDelete(request, response); + + ObjectNode json = ParsingUtilities.mapper.readValue(sw.getBuffer().toString().trim(), ObjectNode.class); + ArrayNode savedConnections = (ArrayNode) json.get("savedConnections"); + Assert.assertNotNull(savedConnections); + + Assert.assertEquals(savedConnections.size(), 0); + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void testDoDeleteInValidConnectionName() { + String testDbName = "testLocalDb"; + saveDatabaseConfiguration(testDbName); + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + try { + when(response.getWriter()).thenReturn(pw); + + when(request.getParameter("connectionName")).thenReturn("noDbName"); + + SUT.doDelete(request, response); + + ObjectNode json = ParsingUtilities.mapper.createObjectNode(); + + Assert.assertNotNull(json); + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Added to check XSS invalid tokens + * + * @throws IOException + * @throws ServletException + */ + @Test + public void testDoPostInvalidConnectionName() throws IOException, ServletException { + + when(request.getParameter("connectionName")).thenReturn(""); + when(request.getParameter("databaseType")).thenReturn(MySQLDatabaseService.DB_NAME); + when(request.getParameter("databaseServer")).thenReturn(testDbConfig.getDatabaseHost()); + when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort()); + when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser()); + when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword()); + when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName()); + when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken()); + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + + SUT.doPost(request, response); + + verify(response, times(1)).sendError(HttpStatus.SC_BAD_REQUEST, "Connection Name is Invalid. Expecting [a-zA-Z0-9._-]"); + } + + @Test + public void testCsrfProtection() throws ServletException, IOException { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + + SUT.doPost(request, response); + Assert.assertEquals( + ParsingUtilities.mapper.readValue("{\"code\":\"error\",\"message\":\"Missing or invalid csrf_token parameter\"}", + ObjectNode.class), + ParsingUtilities.mapper.readValue(sw.toString(), ObjectNode.class)); + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/TestConnectCommandTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/TestConnectCommandTest.java new file mode 100644 index 000000000..5221dfe8f --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/TestConnectCommandTest.java @@ -0,0 +1,109 @@ + +package com.google.refine.extension.database.cmd; + +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.refine.commands.Command; +import com.google.refine.extension.database.DBExtensionTests; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.mysql.MySQLDatabaseService; +import com.google.refine.util.ParsingUtilities; + +@Test(groups = { "requiresMySQL" }) +public class TestConnectCommandTest extends DBExtensionTests { + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + private DatabaseConfiguration testDbConfig; + // private String testTable; + + @BeforeTest + @Parameters({ "mySqlDbName", "mySqlDbHost", "mySqlDbPort", "mySqlDbUser", "mySqlDbPassword", "mySqlTestTable" }) + public void beforeTest(@Optional(DEFAULT_MYSQL_DB_NAME) String mySqlDbName, @Optional(DEFAULT_MYSQL_HOST) String mySqlDbHost, + @Optional(DEFAULT_MYSQL_PORT) String mySqlDbPort, @Optional(DEFAULT_MYSQL_USER) String mySqlDbUser, + @Optional(DEFAULT_MYSQL_PASSWORD) String mySqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String mySqlTestTable) { + + MockitoAnnotations.initMocks(this); + + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(mySqlDbHost); + testDbConfig.setDatabaseName(mySqlDbName); + testDbConfig.setDatabasePassword(mySqlDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(mySqlDbPort)); + testDbConfig.setDatabaseType(MySQLDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(mySqlDbUser); + testDbConfig.setUseSSL(false); + + // testTable = mySqlTestTable; + // DBExtensionTestUtils.initTestData(testDbConfig); + + DatabaseService.DBType.registerDatabase(MySQLDatabaseService.DB_NAME, MySQLDatabaseService.getInstance()); + + } + + @Test + public void testDoPost() throws IOException, ServletException { + + when(request.getParameter("databaseType")).thenReturn(MySQLDatabaseService.DB_NAME); + when(request.getParameter("databaseServer")).thenReturn(testDbConfig.getDatabaseHost()); + when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort()); + when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser()); + when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword()); + when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName()); + when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken()); + + StringWriter sw = new StringWriter(); + + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + TestConnectCommand connectCommand = new TestConnectCommand(); + + connectCommand.doPost(request, response); + + String result = sw.getBuffer().toString().trim(); + ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class); + + String code = json.get("code").asText(); + Assert.assertEquals(code, "ok"); + + } + + @Test + public void testCsrfProtection() throws ServletException, IOException { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + ConnectCommand connectCommand = new ConnectCommand(); + + connectCommand.doPost(request, response); + Assert.assertEquals( + ParsingUtilities.mapper.readValue("{\"code\":\"error\",\"message\":\"Missing or invalid csrf_token parameter\"}", + ObjectNode.class), + ParsingUtilities.mapper.readValue(sw.toString(), ObjectNode.class)); + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/TestQueryCommandTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/TestQueryCommandTest.java new file mode 100644 index 000000000..1351095ba --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/cmd/TestQueryCommandTest.java @@ -0,0 +1,112 @@ + +package com.google.refine.extension.database.cmd; + +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.refine.commands.Command; +import com.google.refine.extension.database.DBExtensionTests; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.mysql.MySQLDatabaseService; +import com.google.refine.util.ParsingUtilities; + +@Test(groups = { "requiresMySQL" }) +public class TestQueryCommandTest extends DBExtensionTests { + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + private DatabaseConfiguration testDbConfig; + private String testTable; + + @BeforeTest + @Parameters({ "mySqlDbName", "mySqlDbHost", "mySqlDbPort", "mySqlDbUser", "mySqlDbPassword", "mySqlTestTable" }) + public void beforeTest(@Optional(DEFAULT_MYSQL_DB_NAME) String mySqlDbName, @Optional(DEFAULT_MYSQL_HOST) String mySqlDbHost, + @Optional(DEFAULT_MYSQL_PORT) String mySqlDbPort, @Optional(DEFAULT_MYSQL_USER) String mySqlDbUser, + @Optional(DEFAULT_MYSQL_PASSWORD) String mySqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String mySqlTestTable) { + + MockitoAnnotations.initMocks(this); + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(mySqlDbHost); + testDbConfig.setDatabaseName(mySqlDbName); + testDbConfig.setDatabasePassword(mySqlDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(mySqlDbPort)); + testDbConfig.setDatabaseType(MySQLDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(mySqlDbUser); + testDbConfig.setUseSSL(false); + + testTable = mySqlTestTable; + // DBExtensionTestUtils.initTestData(testDbConfig); + + DatabaseService.DBType.registerDatabase(MySQLDatabaseService.DB_NAME, MySQLDatabaseService.getInstance()); + + } + + @Test + public void testDoPost() throws IOException, ServletException { + + when(request.getParameter("databaseType")).thenReturn(testDbConfig.getDatabaseType()); + when(request.getParameter("databaseServer")).thenReturn(testDbConfig.getDatabaseHost()); + when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort()); + when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser()); + when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword()); + when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName()); + when(request.getParameter("query")).thenReturn("SELECT count(*) FROM " + testTable); + when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken()); + + StringWriter sw = new StringWriter(); + + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + TestQueryCommand executeQueryCommand = new TestQueryCommand(); + + executeQueryCommand.doPost(request, response); + + String result = sw.getBuffer().toString().trim(); + ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class); + + String code = json.get("code").asText(); + Assert.assertEquals(code, "ok"); + + String queryResult = json.get("QueryResult").asText(); + Assert.assertNotNull(queryResult); + + } + + @Test + public void testCsrfProtection() throws ServletException, IOException { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + when(response.getWriter()).thenReturn(pw); + TestQueryCommand connectCommand = new TestQueryCommand(); + + connectCommand.doPost(request, response); + Assert.assertEquals( + ParsingUtilities.mapper.readValue("{\"code\":\"error\",\"message\":\"Missing or invalid csrf_token parameter\"}", + ObjectNode.class), + ParsingUtilities.mapper.readValue(sw.toString(), ObjectNode.class)); + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mariadb/MariaDBConnectionManagerTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mariadb/MariaDBConnectionManagerTest.java new file mode 100644 index 000000000..18824776c --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mariadb/MariaDBConnectionManagerTest.java @@ -0,0 +1,73 @@ + +package com.google.refine.extension.database.mariadb; + +import java.sql.Connection; +import java.sql.SQLException; + +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.google.refine.extension.database.DBExtensionTests; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; + +@Test(groups = { "requiresMariaDB" }) +public class MariaDBConnectionManagerTest extends DBExtensionTests { + + private DatabaseConfiguration testDbConfig; + + @BeforeTest + @Parameters({ "mariadbDbName", "mariadbDbHost", "mariadbDbPort", "mariadbDbUser", "mariadbDbPassword", "mariaTestTable" }) + public void beforeTest(@Optional(DEFAULT_MARIADB_NAME) String mariaDbName, @Optional(DEFAULT_MARIADB_HOST) String mariaDbHost, + @Optional(DEFAULT_MARIADB_PORT) String mariaDbPort, @Optional(DEFAULT_MARIADB_USER) String mariaDbUser, + @Optional(DEFAULT_MARIADB_PASSWORD) String mariaDbPassword, @Optional(DEFAULT_TEST_TABLE) String mariaDbTestTable) { + + MockitoAnnotations.initMocks(this); + + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(mariaDbHost); + testDbConfig.setDatabaseName(mariaDbName); + testDbConfig.setDatabasePassword(mariaDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(mariaDbPort)); + testDbConfig.setDatabaseType(MariaDBDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(mariaDbUser); + testDbConfig.setUseSSL(false); + +// testTable = mariaDbTestTable; + // DBExtensionTestUtils.initTestData(testDbConfig); + + DatabaseService.DBType.registerDatabase(MariaDBDatabaseService.DB_NAME, MariaDBDatabaseService.getInstance()); + + } + + @Test + public void testTestConnection() throws DatabaseServiceException { + boolean conn = MariaDBConnectionManager.getInstance().testConnection(testDbConfig); + Assert.assertEquals(conn, true); + } + + @Test + public void testGetConnection() throws DatabaseServiceException { + Connection conn = MariaDBConnectionManager.getInstance().getConnection(testDbConfig, true); + Assert.assertNotNull(conn); + } + + @Test + public void testShutdown() throws DatabaseServiceException, SQLException { + Connection conn = MariaDBConnectionManager.getInstance().getConnection(testDbConfig, true); + Assert.assertNotNull(conn); + + MariaDBConnectionManager.getInstance().shutdown(); + + if (conn != null) { + Assert.assertEquals(conn.isClosed(), true); + } + + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mariadb/MariaDBDatabaseServiceTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mariadb/MariaDBDatabaseServiceTest.java new file mode 100644 index 000000000..b0844b3cf --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mariadb/MariaDBDatabaseServiceTest.java @@ -0,0 +1,130 @@ + +package com.google.refine.extension.database.mariadb; + +import java.sql.Connection; +import java.util.List; + +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.google.refine.extension.database.DBExtensionTestUtils; +import com.google.refine.extension.database.DBExtensionTests; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.extension.database.model.DatabaseRow; + +@Test(groups = { "requiresMariaDB" }) +public class MariaDBDatabaseServiceTest extends DBExtensionTests { + + private DatabaseConfiguration testDbConfig; + + private String testTable; + + @BeforeTest + @Parameters({ "mariadbDbName", "mariadbDbHost", "mariadbDbPort", "mariadbDbUser", "mariadbDbPassword", "mariadbTestTable" }) + public void beforeTest(@Optional(DEFAULT_MARIADB_NAME) String mariaDbName, @Optional(DEFAULT_MARIADB_HOST) String mariaDbHost, + @Optional(DEFAULT_MARIADB_PORT) String mariaDbPort, @Optional(DEFAULT_MARIADB_USER) String mariaDbUser, + @Optional(DEFAULT_MARIADB_PASSWORD) String mariaDbPassword, @Optional(DEFAULT_TEST_TABLE) String mariaDbTestTable) { + + MockitoAnnotations.initMocks(this); + + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(mariaDbHost); + testDbConfig.setDatabaseName(mariaDbName); + testDbConfig.setDatabasePassword(mariaDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(mariaDbPort)); + testDbConfig.setDatabaseType(MariaDBDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(mariaDbUser); + testDbConfig.setUseSSL(false); + + testTable = mariaDbTestTable; + // DBExtensionTestUtils.initTestData(testDbConfig); + + DatabaseService.DBType.registerDatabase(MariaDBDatabaseService.DB_NAME, MariaDBDatabaseService.getInstance()); + + } + + @Test + public void testGetDatabaseUrl() { + MariaDBDatabaseService pgSqlService = (MariaDBDatabaseService) DatabaseService.get(MariaDBDatabaseService.DB_NAME); + String dbUrl = pgSqlService.getDatabaseUrl(testDbConfig); + // System.out.println("dbUrl:" + dbUrl); + Assert.assertNotNull(dbUrl); + Assert.assertEquals(dbUrl, DBExtensionTestUtils.getJDBCUrl(testDbConfig)); + } + + @Test + public void testGetConnection() throws DatabaseServiceException { + MariaDBDatabaseService pgSqlService = (MariaDBDatabaseService) DatabaseService.get(MariaDBDatabaseService.DB_NAME); + Connection conn = pgSqlService.getConnection(testDbConfig); + + Assert.assertNotNull(conn); + } + + @Test + public void testTestConnection() throws DatabaseServiceException { + MariaDBDatabaseService pgSqlService = (MariaDBDatabaseService) DatabaseService.get(MariaDBDatabaseService.DB_NAME); + + boolean result = pgSqlService.testConnection(testDbConfig); + Assert.assertEquals(result, true); + } + + @Test + public void testConnect() throws DatabaseServiceException { + MariaDBDatabaseService pgSqlService = (MariaDBDatabaseService) DatabaseService.get(MariaDBDatabaseService.DB_NAME); + DatabaseInfo databaseInfo = pgSqlService.connect(testDbConfig); + Assert.assertNotNull(databaseInfo); + } + + @Test + public void testExecuteQuery() throws DatabaseServiceException { + MariaDBDatabaseService pgSqlService = (MariaDBDatabaseService) DatabaseService + .get(MariaDBDatabaseService.DB_NAME); + DatabaseInfo databaseInfo = pgSqlService.testQuery(testDbConfig, "SELECT * FROM " + testTable); + + Assert.assertNotNull(databaseInfo); + } + + @Test + public void testBuildLimitQuery() { + MariaDBDatabaseService pgSqlService = (MariaDBDatabaseService) DatabaseService.get(MariaDBDatabaseService.DB_NAME); + String limitQuery = pgSqlService.buildLimitQuery(100, 0, "SELECT * FROM " + testTable); + Assert.assertNotNull(limitQuery); + Assert.assertEquals(limitQuery, "SELECT * FROM (SELECT * FROM " + testTable + ") data LIMIT " + 100 + " OFFSET " + 0 + ";"); + } + + @Test + public void testGetRows() throws DatabaseServiceException { + MariaDBDatabaseService pgSqlService = (MariaDBDatabaseService) DatabaseService + .get(MariaDBDatabaseService.DB_NAME); + List dbRows = pgSqlService.getRows(testDbConfig, "SELECT * FROM " + testTable); + + Assert.assertNotNull(dbRows); + } + + @Test + public void testGetInstance() { + MariaDBDatabaseService instance = MariaDBDatabaseService.getInstance(); + Assert.assertNotNull(instance); + } + + @Test + public void testGetColumns() throws DatabaseServiceException { + List dbColumns; + + MariaDBDatabaseService pgSqlService = (MariaDBDatabaseService) DatabaseService + .get(MariaDBDatabaseService.DB_NAME); + + dbColumns = pgSqlService.getColumns(testDbConfig, "SELECT * FROM " + testTable); + + Assert.assertNotNull(dbColumns); + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mysql/MySQLConnectionManagerTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mysql/MySQLConnectionManagerTest.java new file mode 100644 index 000000000..f896a69fc --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mysql/MySQLConnectionManagerTest.java @@ -0,0 +1,75 @@ + +package com.google.refine.extension.database.mysql; + +import java.sql.Connection; +import java.sql.SQLException; + +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.google.refine.extension.database.DBExtensionTests; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; + +@Test(groups = { "requiresMySQL" }) +public class MySQLConnectionManagerTest extends DBExtensionTests { + + private DatabaseConfiguration testDbConfig; + + @BeforeTest + @Parameters({ "mySqlDbName", "mySqlDbHost", "mySqlDbPort", "mySqlDbUser", "mySqlDbPassword", "mySqlTestTable" }) + public void beforeTest(@Optional(DEFAULT_MYSQL_DB_NAME) String mySqlDbName, @Optional(DEFAULT_MYSQL_HOST) String mySqlDbHost, + @Optional(DEFAULT_MYSQL_PORT) String mySqlDbPort, @Optional(DEFAULT_MYSQL_USER) String mySqlDbUser, + @Optional(DEFAULT_MYSQL_PASSWORD) String mySqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String mySqlTestTable) { + + MockitoAnnotations.initMocks(this); + + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(mySqlDbHost); + testDbConfig.setDatabaseName(mySqlDbName); + testDbConfig.setDatabasePassword(mySqlDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(mySqlDbPort)); + testDbConfig.setDatabaseType(MySQLDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(mySqlDbUser); + testDbConfig.setUseSSL(false); + + // testTable = mySqlTestTable; + // DBExtensionTestUtils.initTestData(testDbConfig); + + DatabaseService.DBType.registerDatabase(MySQLDatabaseService.DB_NAME, MySQLDatabaseService.getInstance()); + + } + + @Test + public void testTestConnection() throws DatabaseServiceException { + + boolean conn = MySQLConnectionManager.getInstance().testConnection(testDbConfig); + Assert.assertEquals(conn, true); + } + + @Test + public void testGetConnection() throws DatabaseServiceException { + + Connection conn = MySQLConnectionManager.getInstance().getConnection(testDbConfig, true); + Assert.assertNotNull(conn); + } + + @Test + public void testShutdown() throws DatabaseServiceException, SQLException { + + Connection conn = MySQLConnectionManager.getInstance().getConnection(testDbConfig, true); + Assert.assertNotNull(conn); + + MySQLConnectionManager.getInstance().shutdown(); + + if (conn != null) { + Assert.assertEquals(conn.isClosed(), true); + } + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mysql/MySQLDatabaseServiceTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mysql/MySQLDatabaseServiceTest.java new file mode 100644 index 000000000..6c1ba3784 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/mysql/MySQLDatabaseServiceTest.java @@ -0,0 +1,129 @@ + +package com.google.refine.extension.database.mysql; + +import java.sql.Connection; +import java.util.List; + +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.google.refine.extension.database.DBExtensionTestUtils; +import com.google.refine.extension.database.DBExtensionTests; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.extension.database.model.DatabaseRow; + +@Test(groups = { "requiresMySQL" }) +public class MySQLDatabaseServiceTest extends DBExtensionTests { + + private DatabaseConfiguration testDbConfig; + private String testTable; + + @BeforeTest + @Parameters({ "mySqlDbName", "mySqlDbHost", "mySqlDbPort", "mySqlDbUser", "mySqlDbPassword", "mySqlTestTable" }) + public void beforeTest(@Optional(DEFAULT_MYSQL_DB_NAME) String mySqlDbName, @Optional(DEFAULT_MYSQL_HOST) String mySqlDbHost, + @Optional(DEFAULT_MYSQL_PORT) String mySqlDbPort, @Optional(DEFAULT_MYSQL_USER) String mySqlDbUser, + @Optional(DEFAULT_MYSQL_PASSWORD) String mySqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String mySqlTestTable) { + + MockitoAnnotations.initMocks(this); + + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(mySqlDbHost); + testDbConfig.setDatabaseName(mySqlDbName); + testDbConfig.setDatabasePassword(mySqlDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(mySqlDbPort)); + testDbConfig.setDatabaseType(MySQLDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(mySqlDbUser); + testDbConfig.setUseSSL(false); + + testTable = mySqlTestTable; + // DBExtensionTestUtils.initTestData(testDbConfig); + + DatabaseService.DBType.registerDatabase(MySQLDatabaseService.DB_NAME, MySQLDatabaseService.getInstance()); + + } + + @Test + public void testGetDatabaseUrl() { + MySQLDatabaseService pgSqlService = (MySQLDatabaseService) DatabaseService.get(MySQLDatabaseService.DB_NAME); + String dbUrl = pgSqlService.getDatabaseUrl(testDbConfig); + // System.out.println("dbUrl:" + dbUrl); + Assert.assertNotNull(dbUrl); + Assert.assertEquals(dbUrl, DBExtensionTestUtils.getJDBCUrl(testDbConfig)); + } + + @Test + public void testGetConnection() throws DatabaseServiceException { + MySQLDatabaseService pgSqlService = (MySQLDatabaseService) DatabaseService.get(MySQLDatabaseService.DB_NAME); + Connection conn = pgSqlService.getConnection(testDbConfig); + + Assert.assertNotNull(conn); + } + + @Test + public void testTestConnection() throws DatabaseServiceException { + MySQLDatabaseService pgSqlService = (MySQLDatabaseService) DatabaseService.get(MySQLDatabaseService.DB_NAME); + + boolean result = pgSqlService.testConnection(testDbConfig); + Assert.assertEquals(result, true); + } + + @Test + public void testConnect() throws DatabaseServiceException { + MySQLDatabaseService pgSqlService = (MySQLDatabaseService) DatabaseService.get(MySQLDatabaseService.DB_NAME); + DatabaseInfo databaseInfo = pgSqlService.connect(testDbConfig); + Assert.assertNotNull(databaseInfo); + } + + @Test + public void testExecuteQuery() throws DatabaseServiceException { + + MySQLDatabaseService pgSqlService = (MySQLDatabaseService) DatabaseService + .get(MySQLDatabaseService.DB_NAME); + DatabaseInfo databaseInfo = pgSqlService.testQuery(testDbConfig, "SELECT * FROM " + testTable); + + Assert.assertNotNull(databaseInfo); + } + + @Test + public void testBuildLimitQuery() { + MySQLDatabaseService pgSqlService = (MySQLDatabaseService) DatabaseService.get(MySQLDatabaseService.DB_NAME); + String limitQuery = pgSqlService.buildLimitQuery(100, 0, "SELECT * FROM " + testTable); + Assert.assertNotNull(limitQuery); + Assert.assertEquals(limitQuery, "SELECT * FROM (SELECT * FROM " + testTable + ") data LIMIT " + 100 + " OFFSET " + 0 + ";"); + } + + @Test + public void testGetRows() throws DatabaseServiceException { + MySQLDatabaseService pgSqlService = (MySQLDatabaseService) DatabaseService + .get(MySQLDatabaseService.DB_NAME); + List dbRows = pgSqlService.getRows(testDbConfig, "SELECT * FROM " + testTable); + + Assert.assertNotNull(dbRows); + } + + @Test + public void testGetInstance() { + MySQLDatabaseService instance = MySQLDatabaseService.getInstance(); + Assert.assertNotNull(instance); + } + + @Test + public void testGetColumns() throws DatabaseServiceException { + List dbColumns; + MySQLDatabaseService pgSqlService = (MySQLDatabaseService) DatabaseService + .get(MySQLDatabaseService.DB_NAME); + + dbColumns = pgSqlService.getColumns(testDbConfig, "SELECT * FROM " + testTable); + + Assert.assertNotNull(dbColumns); + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/pgsql/PgSQLConnectionManagerTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/pgsql/PgSQLConnectionManagerTest.java new file mode 100644 index 000000000..9f3a85b85 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/pgsql/PgSQLConnectionManagerTest.java @@ -0,0 +1,76 @@ + +package com.google.refine.extension.database.pgsql; + +import java.sql.Connection; +import java.sql.SQLException; + +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.google.refine.extension.database.DBExtensionTests; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; + +@Test(groups = { "requiresPgSQL" }) +public class PgSQLConnectionManagerTest extends DBExtensionTests { + + private DatabaseConfiguration testDbConfig; + + @BeforeTest + @Parameters({ "pgSqlDbName", "pgSqlDbHost", "pgSqlDbPort", "pgSqlDbUser", "pgSqlDbPassword", "pgSqlTestTable" }) + public void beforeTest(@Optional(DEFAULT_PGSQL_DB_NAME) String pgSqlDbName, @Optional(DEFAULT_PGSQL_HOST) String pgSqlDbHost, + @Optional(DEFAULT_PGSQL_PORT) String pgSqlDbPort, @Optional(DEFAULT_PGSQL_USER) String pgSqlDbUser, + @Optional(DEFAULT_PGSQL_PASSWORD) String pgSqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String pgSqlTestTable) { + + MockitoAnnotations.initMocks(this); + + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(pgSqlDbHost); + testDbConfig.setDatabaseName(pgSqlDbName); + testDbConfig.setDatabasePassword(pgSqlDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(pgSqlDbPort)); + testDbConfig.setDatabaseType(PgSQLDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(pgSqlDbUser); + testDbConfig.setUseSSL(false); + + // testTable = mySqlTestTable; + // DBExtensionTestUtils.initTestData(testDbConfig); + + DatabaseService.DBType.registerDatabase(PgSQLDatabaseService.DB_NAME, PgSQLDatabaseService.getInstance()); + + } + + @Test + public void testTestConnection() throws DatabaseServiceException { + + boolean isConnected = PgSQLConnectionManager.getInstance().testConnection(testDbConfig); + Assert.assertEquals(isConnected, true); + } + + @Test + public void testGetConnection() throws DatabaseServiceException { + + Connection conn = PgSQLConnectionManager.getInstance().getConnection(testDbConfig, true); + Assert.assertNotNull(conn); + } + + @Test + public void testShutdown() throws DatabaseServiceException, SQLException { + + Connection conn = PgSQLConnectionManager.getInstance().getConnection(testDbConfig, true); + Assert.assertNotNull(conn); + + PgSQLConnectionManager.getInstance().shutdown(); + + if (conn != null) { + Assert.assertEquals(conn.isClosed(), true); + } + + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/pgsql/PgSQLDatabaseServiceTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/pgsql/PgSQLDatabaseServiceTest.java new file mode 100644 index 000000000..fc5a0306c --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/pgsql/PgSQLDatabaseServiceTest.java @@ -0,0 +1,131 @@ + +package com.google.refine.extension.database.pgsql; + +import java.sql.Connection; +import java.util.List; + +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +import com.google.refine.extension.database.DBExtensionTestUtils; +import com.google.refine.extension.database.DBExtensionTests; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.extension.database.model.DatabaseRow; + +@Test(groups = { "requiresPgSQL" }) +public class PgSQLDatabaseServiceTest extends DBExtensionTests { + + private DatabaseConfiguration testDbConfig; + private String testTable; + + @BeforeTest + @Parameters({ "pgSqlDbName", "pgSqlDbHost", "pgSqlDbPort", "pgSqlDbUser", "pgSqlDbPassword", "pgSqlTestTable" }) + public void beforeTest(@Optional(DEFAULT_PGSQL_DB_NAME) String pgSqlDbName, @Optional(DEFAULT_PGSQL_HOST) String pgSqlDbHost, + @Optional(DEFAULT_PGSQL_PORT) String pgSqlDbPort, @Optional(DEFAULT_PGSQL_USER) String pgSqlDbUser, + @Optional(DEFAULT_PGSQL_PASSWORD) String pgSqlDbPassword, @Optional(DEFAULT_TEST_TABLE) String pgSqlTestTable) { + + MockitoAnnotations.initMocks(this); + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseHost(pgSqlDbHost); + testDbConfig.setDatabaseName(pgSqlDbName); + testDbConfig.setDatabasePassword(pgSqlDbPassword); + testDbConfig.setDatabasePort(Integer.parseInt(pgSqlDbPort)); + testDbConfig.setDatabaseType(PgSQLDatabaseService.DB_NAME); + testDbConfig.setDatabaseUser(pgSqlDbUser); + testDbConfig.setUseSSL(false); + + testTable = pgSqlTestTable; + // DBExtensionTestUtils.initTestData(testDbConfig); + + DatabaseService.DBType.registerDatabase(PgSQLDatabaseService.DB_NAME, PgSQLDatabaseService.getInstance()); + } + + @Test + public void testGetDatabaseUrl() { + PgSQLDatabaseService pgSqlService = (PgSQLDatabaseService) DatabaseService.get(PgSQLDatabaseService.DB_NAME); + String dbUrl = pgSqlService.getDatabaseUrl(testDbConfig); + + Assert.assertNotNull(dbUrl); + Assert.assertEquals(dbUrl, DBExtensionTestUtils.getJDBCUrl(testDbConfig)); + } + + @Test + public void testGetConnection() throws DatabaseServiceException { + + PgSQLDatabaseService pgSqlService = (PgSQLDatabaseService) DatabaseService.get(PgSQLDatabaseService.DB_NAME); + Connection conn = pgSqlService.getConnection(testDbConfig); + + Assert.assertNotNull(conn); + } + + @Test + public void testTestConnection() throws DatabaseServiceException { + PgSQLDatabaseService pgSqlService = (PgSQLDatabaseService) DatabaseService.get(PgSQLDatabaseService.DB_NAME); + + boolean result = pgSqlService.testConnection(testDbConfig); + Assert.assertEquals(result, true); + } + + @Test + public void testConnect() throws DatabaseServiceException { + + PgSQLDatabaseService pgSqlService = (PgSQLDatabaseService) DatabaseService.get(PgSQLDatabaseService.DB_NAME); + DatabaseInfo databaseInfo = pgSqlService.connect(testDbConfig); + Assert.assertNotNull(databaseInfo); + } + + @Test + public void testExecuteQuery() throws DatabaseServiceException { + + PgSQLDatabaseService pgSqlService = (PgSQLDatabaseService) DatabaseService + .get(PgSQLDatabaseService.DB_NAME); + DatabaseInfo databaseInfo = pgSqlService.testQuery(testDbConfig, "SELECT * FROM " + testTable); + + Assert.assertNotNull(databaseInfo); + } + + @Test + public void testBuildLimitQuery() { + PgSQLDatabaseService pgSqlService = (PgSQLDatabaseService) DatabaseService.get(PgSQLDatabaseService.DB_NAME); + String limitQuery = pgSqlService.buildLimitQuery(100, 0, "SELECT * FROM " + testTable); + Assert.assertNotNull(limitQuery); + Assert.assertEquals(limitQuery, "SELECT * FROM (SELECT * FROM " + testTable + ") data LIMIT " + 100 + " OFFSET " + 0 + ";"); + } + + @Test + public void testGetRows() throws DatabaseServiceException { + PgSQLDatabaseService pgSqlService = (PgSQLDatabaseService) DatabaseService + .get(PgSQLDatabaseService.DB_NAME); + List dbRows = pgSqlService.getRows(testDbConfig, "SELECT * FROM " + testTable); + + Assert.assertNotNull(dbRows); + } + + @Test + public void testGetInstance() { + PgSQLDatabaseService instance = PgSQLDatabaseService.getInstance(); + Assert.assertNotNull(instance); + } + + @Test + public void testGetColumns() throws DatabaseServiceException { + List dbColumns; + + PgSQLDatabaseService pgSqlService = (PgSQLDatabaseService) DatabaseService + .get(PgSQLDatabaseService.DB_NAME); + + dbColumns = pgSqlService.getColumns(testDbConfig, "SELECT * FROM " + testTable); + + Assert.assertNotNull(dbColumns); + + } + +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManagerTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManagerTest.java new file mode 100644 index 000000000..2daf059c5 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteConnectionManagerTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020, Chris Parker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.refine.extension.database.sqlite; + +import com.google.refine.extension.database.DBExtensionTests; +import com.google.refine.extension.database.DatabaseConfiguration; +import com.google.refine.extension.database.DatabaseService; +import com.google.refine.extension.database.DatabaseServiceException; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.*; + +import java.io.File; +import java.sql.Connection; +import java.sql.SQLException; + +@Test(groups = { "requiresSQLite" }) +public class SQLiteConnectionManagerTest extends DBExtensionTests { + + private DatabaseConfiguration testDbConfig; + + @BeforeTest + @Parameters({ "sqliteDbName", "sqliteTestTable" }) + public void beforeTest(@Optional(DEFAULT_SQLITE_DB_NAME) String sqliteDbName, + @Optional(DEFAULT_TEST_TABLE) String sqliteTestTable) + throws DatabaseServiceException, SQLException { + + MockitoAnnotations.initMocks(this); + + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseName(sqliteDbName); + testDbConfig.setDatabaseType(SQLiteDatabaseService.DB_NAME); + + DatabaseService.DBType.registerDatabase(SQLiteDatabaseService.DB_NAME, SQLiteDatabaseService.getInstance()); + } + + @AfterTest + @Parameters({ "sqliteDbName" }) + public void afterTest(@Optional(DEFAULT_SQLITE_DB_NAME) String sqliteDbName) { + File f = new File(sqliteDbName); + if (f.exists()) { + f.delete(); + } + } + + @Test + public void testTestConnection() throws DatabaseServiceException { + boolean isConnected = SQLiteConnectionManager.getInstance().testConnection(testDbConfig); + Assert.assertTrue(isConnected); + } + + @Test + public void testGetConnection() throws DatabaseServiceException { + + Connection conn = SQLiteConnectionManager.getInstance().getConnection(testDbConfig); + Assert.assertNotNull(conn); + } + + @Test + public void testShutdown() throws DatabaseServiceException, SQLException { + + Connection conn = SQLiteConnectionManager.getInstance().getConnection(testDbConfig); + Assert.assertNotNull(conn); + + SQLiteConnectionManager.getInstance().shutdown(); + + if (conn != null) { + Assert.assertTrue(conn.isClosed()); + } + + } +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteDatabaseServiceTest.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteDatabaseServiceTest.java new file mode 100644 index 000000000..c29cc82c2 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/sqlite/SQLiteDatabaseServiceTest.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2020, Chris Parker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Google nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.refine.extension.database.sqlite; + +import com.google.refine.extension.database.*; +import com.google.refine.extension.database.model.DatabaseColumn; +import com.google.refine.extension.database.model.DatabaseInfo; +import com.google.refine.extension.database.model.DatabaseRow; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.*; + +import java.io.File; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; + +@Test(groups = { "requiresSQLite" }) +public class SQLiteDatabaseServiceTest extends DBExtensionTests { + + private DatabaseConfiguration testDbConfig; + private String testTable; + + @BeforeTest + @Parameters({ "sqliteDbName", "sqliteTestTable" }) + public void beforeTest(@Optional(DEFAULT_SQLITE_DB_NAME) String sqliteDbName, + @Optional(DEFAULT_TEST_TABLE) String sqliteTestTable) + throws DatabaseServiceException, SQLException { + + MockitoAnnotations.initMocks(this); + testDbConfig = new DatabaseConfiguration(); + testDbConfig.setDatabaseName(sqliteDbName); + testDbConfig.setDatabaseType(SQLiteDatabaseService.DB_NAME); + + testTable = sqliteTestTable; + DBExtensionTestUtils.initTestData(testDbConfig, sqliteTestTable); + + DatabaseService.DBType.registerDatabase(SQLiteDatabaseService.DB_NAME, SQLiteDatabaseService.getInstance()); + } + + @AfterTest + @Parameters({ "sqliteDbName" }) + public void afterTest(@Optional(DEFAULT_SQLITE_DB_NAME) String sqliteDbName) { + File f = new File(sqliteDbName); + if (f.exists()) { + f.delete(); + } + } + + @Test + public void testGetDatabaseUrl() { + SQLiteDatabaseService sqLiteDatabaseService = (SQLiteDatabaseService) DatabaseService + .get(SQLiteDatabaseService.DB_NAME); + String dbUrl = sqLiteDatabaseService.getDatabaseUrl(testDbConfig); + + Assert.assertNotNull(dbUrl); + Assert.assertEquals(dbUrl, "jdbc:sqlite:extension_test_db.sqlite"); + } + + @Test + public void testGetConnection() throws DatabaseServiceException { + + SQLiteDatabaseService sqLiteDatabaseService = (SQLiteDatabaseService) DatabaseService + .get(SQLiteDatabaseService.DB_NAME); + Connection conn = sqLiteDatabaseService.getConnection(testDbConfig); + + Assert.assertNotNull(conn); + } + + @Test + public void testTestConnection() throws DatabaseServiceException { + SQLiteDatabaseService sqLiteDatabaseService = (SQLiteDatabaseService) DatabaseService + .get(SQLiteDatabaseService.DB_NAME); + + boolean result = sqLiteDatabaseService.testConnection(testDbConfig); + Assert.assertTrue(result); + } + + @Test + public void testConnect() throws DatabaseServiceException { + + SQLiteDatabaseService sqLiteDatabaseService = (SQLiteDatabaseService) DatabaseService + .get(SQLiteDatabaseService.DB_NAME); + DatabaseInfo databaseInfo = sqLiteDatabaseService.connect(testDbConfig); + Assert.assertNotNull(databaseInfo); + } + + @Test + public void testExecuteQuery() throws DatabaseServiceException { + SQLiteDatabaseService sqLiteDatabaseService = (SQLiteDatabaseService) DatabaseService + .get(SQLiteDatabaseService.DB_NAME); + DatabaseInfo databaseInfo = sqLiteDatabaseService.testQuery(testDbConfig, "SELECT * FROM " + testTable); + + Assert.assertNotNull(databaseInfo); + } + + @Test + public void testBuildLimitQuery() { + SQLiteDatabaseService sqliteSqlService = (SQLiteDatabaseService) DatabaseService + .get(SQLiteDatabaseService.DB_NAME); + String limitQuery = sqliteSqlService.buildLimitQuery(100, 0, "SELECT * FROM " + testTable); + Assert.assertNotNull(limitQuery); + Assert.assertEquals(limitQuery, + "SELECT * FROM (SELECT * FROM " + testTable + ") data LIMIT " + 100 + " OFFSET " + 0 + ";"); + } + + @Test + public void testGetRows() throws DatabaseServiceException { + SQLiteDatabaseService sqliteSqlService = (SQLiteDatabaseService) DatabaseService + .get(SQLiteDatabaseService.DB_NAME); + List dbRows = sqliteSqlService.getRows(testDbConfig, "SELECT * FROM " + testTable); + + Assert.assertNotNull(dbRows); + } + + @Test + public void testGetInstance() { + SQLiteDatabaseService instance = SQLiteDatabaseService.getInstance(); + Assert.assertNotNull(instance); + } + + @Test + public void testGetColumns() throws DatabaseServiceException { + List dbColumns; + + SQLiteDatabaseService sqliteSqlService = (SQLiteDatabaseService) DatabaseService + .get(SQLiteDatabaseService.DB_NAME); + + dbColumns = sqliteSqlService.getColumns(testDbConfig, "SELECT * FROM " + testTable); + + Assert.assertNotNull(dbColumns); + } +} diff --git a/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/stub/RefineDbServletStub.java b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/stub/RefineDbServletStub.java new file mode 100644 index 000000000..fd5f5a428 --- /dev/null +++ b/OpenRefine/extensions/database/tests/src/com/google/refine/extension/database/stub/RefineDbServletStub.java @@ -0,0 +1,97 @@ +/* + +Copyright 2010, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +package com.google.refine.extension.database.stub; + +import java.io.File; +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.google.refine.RefineServlet; +import com.google.refine.commands.Command; + +/** + * Exposes protected methods of com.google.refine.RefineServlet as public for unit testing + * + */ +public class RefineDbServletStub extends RefineServlet { + + private static File tempDir = null; + + // requirement of extending HttpServlet, not required for testing + private static final long serialVersionUID = 1L; + + public void wrapService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + super.service(request, response); + } + + public String wrapGetCommandName(HttpServletRequest request) { + return super.getCommandKey(request); + } + + @Override + public File getTempDir() { + if (tempDir == null) { + try { + tempDir = File.createTempFile("refine-test-dir", ""); + tempDir.deleteOnExit(); + } catch (IOException e) { + throw new RuntimeException("Failed to create temp directory", e); + } + } + return tempDir; + } + + // -------------------helper methods-------------- + /** + * Helper method for inserting a mock object + * + * @param commandName + * @param command + */ + public void insertCommand(String commandName, Command command) { + registerOneCommand("core/" + commandName, command); + } + + /** + * Helper method for clearing up after testing + * + * @param commandName + */ + public void removeCommand(String commandName) { + unregisterCommand("core/" + commandName); + } +} diff --git a/OpenRefine/extensions/gdata/LICENSE.txt b/OpenRefine/extensions/gdata/LICENSE.txt new file mode 100644 index 000000000..f6982420d --- /dev/null +++ b/OpenRefine/extensions/gdata/LICENSE.txt @@ -0,0 +1,75 @@ +Copyright 2010 Thomas F. Morris + +Licensed under the terms of the Eclipse Public License v1.0 +http://www.eclipse.org/legal/epl-v10.html + +Eclipse Public License - v 1.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and +b) in the case of each subsequent Contributor: +i) changes to the Program, and +ii) additions to the Program; +where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and +b) its license agreement: +i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; +ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; +iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and +iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and +b) a copy of this Agreement must be included with each copy of the Program. +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED 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. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. \ No newline at end of file diff --git a/OpenRefine/extensions/gdata/README.txt b/OpenRefine/extensions/gdata/README.txt new file mode 100644 index 000000000..c3ea8e9d1 --- /dev/null +++ b/OpenRefine/extensions/gdata/README.txt @@ -0,0 +1,23 @@ +OpenRefine extension for Google Spreadsheets +by Tom Morris + +This extension provides Refine with the ability to read Google spreadsheets +directly so you don't have to export them as CSV files first. + +Unpack the contents of this archive (jar, zip, etc) into the extensions folder +of your Refine installation and restart Refine. + +Enter the *public* share URL of a Google Spreadsheet in the "Data File URL" +field of the "Create a New Project" pane of the Refine home page. + +If you end up with a project full of HTML tags and an RSS feed, the extension +isn't installed properly. A properly installed extension should have an About +page available at http://127.0.0.1:3333/extension/gdata/ (the trailing +slash is significant). + + +Known limitations: + +- No write support +- No authentication support. You must use the public share URL for the + the Google spreadsheet you want to load. \ No newline at end of file diff --git a/OpenRefine/extensions/gdata/module/MOD-INF/controller.js b/OpenRefine/extensions/gdata/module/MOD-INF/controller.js new file mode 100644 index 000000000..fc6ff960f --- /dev/null +++ b/OpenRefine/extensions/gdata/module/MOD-INF/controller.js @@ -0,0 +1,130 @@ +/* + +Copyright 2010, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +/* + * Controller for GData extension. + * + * This is run in the Butterfly (ie Refine) server context using the Rhino + * Javascript interpreter. + */ + +var html = "text/html"; +var encoding = "UTF-8"; +var version = "0.3"; +var ClientSideResourceManager = Packages.com.google.refine.ClientSideResourceManager; + +/* + * Function invoked to initialize the extension. + */ +function init() { + var RS = Packages.com.google.refine.RefineServlet; + RS.registerCommand(module, "deauthorize", Packages.com.google.refine.extension.gdata.DeAuthorizeCommand()); + RS.registerCommand(module, "upload", Packages.com.google.refine.extension.gdata.UploadCommand()); + + // Register importer and exporter + var IM = Packages.com.google.refine.importing.ImportingManager; + + IM.registerController( + module, + "gdata-importing-controller", + new Packages.com.google.refine.extension.gdata.GDataImportingController() + ); + + // Script files to inject into /index page + ClientSideResourceManager.addPaths( + "index/scripts", + module, + [ + "scripts/gdata-extension.js", + "scripts/index/importing-controller.js", + "scripts/index/gdata-source-ui.js" + ] + ); + // Style files to inject into /index page + ClientSideResourceManager.addPaths( + "index/styles", + module, + [ + "styles/importing-controller.less" + ] + ); + + // Script files to inject into /project page + ClientSideResourceManager.addPaths( + "project/scripts", + module, + [ + "scripts/gdata-extension.js", + "scripts/project/exporters.js" + ] + ); +} + +/* + * Function invoked to handle each request in a custom way. + */ +function process(path, request, response) { + // Analyze path and handle this request yourself. + if (path == "authorize") { + var context = {}; + context.authorizationUrl = Packages.com.google.refine.extension.gdata.GoogleAPIExtension.getAuthorizationUrl(module, request); + + send(request, response, "authorize.vt", context); + } else if (path == "authorized") { + var context = {}; + context.state = request.getParameter("state"); + + (function() { + if (Packages.com.google.refine.extension.gdata.TokenCookie.getToken(request) !== null) { + return; + } + var tokenAndExpiresInSeconds = Packages.com.google.refine.extension.gdata.GoogleAPIExtension.getTokenFromCode(module,request); + if (tokenAndExpiresInSeconds) { + var tokenInfo = tokenAndExpiresInSeconds.split(","); + Packages.com.google.refine.extension.gdata.TokenCookie.setToken(request, response, tokenInfo[0], tokenInfo[1]); + return; + } + Packages.com.google.refine.extension.gdata.TokenCookie.deleteToken(request, response); + })(); + + send(request, response, "authorized.vt", context); + } else if (path == "/" || path == "") { + var context = {}; + context.version = version; + send(request, response, "index.vt", context); + } +} + +function send(request, response, template, context) { + butterfly.sendTextFromTemplate(request, response, context, template, encoding, html); +} diff --git a/OpenRefine/extensions/gdata/module/MOD-INF/module.properties b/OpenRefine/extensions/gdata/module/MOD-INF/module.properties new file mode 100644 index 000000000..49c1bf4a8 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/MOD-INF/module.properties @@ -0,0 +1,4 @@ +name = gdata +description = Google Data (gData) importer/exporter for OpenRefine +templating.macros = macros.vm +requires = core diff --git a/OpenRefine/extensions/gdata/module/authorize.vt b/OpenRefine/extensions/gdata/module/authorize.vt new file mode 100644 index 000000000..dbb26a585 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/authorize.vt @@ -0,0 +1,46 @@ + + + + + + + + + + + diff --git a/OpenRefine/extensions/gdata/module/authorized.vt b/OpenRefine/extensions/gdata/module/authorized.vt new file mode 100644 index 000000000..67ed3f571 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/authorized.vt @@ -0,0 +1,62 @@ + + + + + + OpenRefine - Authorized + + + + + + + diff --git a/OpenRefine/extensions/gdata/module/index.vt b/OpenRefine/extensions/gdata/module/index.vt new file mode 100644 index 000000000..3b0559794 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/index.vt @@ -0,0 +1,22 @@ +#* + * Access this page at the URL /extension/gdata/ + *# + + + Google Data (gData) Extension v$version + + +

      Google Data Extension v$version

      +

      by Tom Morris

      +

      The Google Spreadsheet/Google Data extension allows OpenRefine to read + (and write, soon) Google Spreadsheets. It should be easily adaptable to + other data sources which implement the gData protocol such as Google Base. +

      +

      Known Limitations

      +
        +
      • No write support
      • +
      • No authentication support. You must use the public share URL for the + the Google spreadsheet you want to load.
      • +
      + + \ No newline at end of file diff --git a/OpenRefine/extensions/gdata/module/langs/translation-bn.json b/OpenRefine/extensions/gdata/module/langs/translation-bn.json new file mode 100644 index 000000000..d7e23aa6a --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-bn.json @@ -0,0 +1,25 @@ +{ + "gdata-import/next->": "পরবরà§à¦¤à§€ »", + "gdata-exporter/uploading": "আপলোড চলছে…", + "gdata-exporter/upload-error": "আপলোড তà§à¦°à§à¦Ÿà¦¿: ", + "gdata-exporter/upload-success": "পà§à¦°à¦•à¦²à§à¦ª সফলভাবে গà§à¦—ল ডà§à¦°à¦¾à¦‡à¦­à§‡ আপলোড করা হয়েছে ", + "gdata-exporter/new-spreadsheet": "à¦à¦•à¦Ÿà¦¿ নতà§à¦¨ গà§à¦—ল সà§à¦ªà§à¦°à§‡à¦¡à¦¶à§€à¦Ÿ", + "gdata-exporter/enter-spreadsheet": "নতà§à¦¨ গà§à¦—ল সà§à¦ªà§à¦°à§‡à¦¡à¦¶à§€à¦Ÿà§‡à¦° নাম দিন", + "gdata-parsing/option": "অপশনস", + "gdata-parsing/worksheet": "ওয়ারà§à¦•à¦¶à¦¿à¦Ÿà¦¸à¦®à§‚হ", + "gdata-parsing/updating-preview": "পà§à¦°à¦¿à¦­à¦¿à¦‰ হালনাগাদ করা হচà§à¦›à§‡ …", + "gdata-import/import-by-url": "à¦à¦•à¦Ÿà¦¿ পাবলিক গà§à¦—ল সà§à¦ªà§à¦°à§‡à¦¡à¦¶à¦¿à¦Ÿ ইমà§à¦ªà§‹à¦°à§à¦Ÿ করà§à¦¨ ইউ আর à¦à¦² :", + "gdata-parsing/create-proj": "পà§à¦°à¦œà§‡à¦•à§à¦Ÿ তৈরি করà§à¦¨ »", + "gdata-parsing/proj-name": "পà§à¦°à¦œà§‡à¦•à§à¦Ÿ à¦¨à¦¾à¦®", + "gdata-parsing/conf-pars": "পারà§à¦¸à¦¿à¦‚ অপশন কনফিগার করà§à¦¨", + "gdata-parsing/start-over": "« নতà§à¦¨ করে শà§à¦°à§ করà§à¦¨", + "gdata-import/re-sign-in-another": "অনà§à¦¯ অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ দিয়ে সাইন ইন করà§à¦¨", + "gdata-import/retrieving": "গà§à¦—ল ডকà§à¦®à§‡à¦¨à§à¦Ÿà¦¸ পà§à¦¨à¦°à§à¦¦à§à¦§à¦¾à¦° করা হচà§à¦›à§‡ …", + "gdata-import/sign-out": "সাইন আউট", + "gdata-import/sign-in": "সাইন ইন", + "gdata-import/please-signin": "দয়া করে সাইন ইন করà§à¦¨ à¦à¦¬à¦‚ অথরাইজ করà§à¦¨ আপনার গà§à¦—ল ডেটা অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ দেয়ার জনà§à¦¯", + "gdata-import/auth-doc": "অনà§à¦®à§‹à¦¦à¦¿à¦¤ ডকà§à¦®à§‡à¦¨à§à¦Ÿà¦¸", + "gdata-import/title": "পাবলিক ডকà§à¦®à§‡à¦¨à§à¦Ÿà¦¸", + "gdata-import/creating": "পà§à¦°à¦œà§‡à¦•à§à¦Ÿ তৈরি করা হচà§à¦›à§‡ …", + "gdata-import/preparing": "পà§à¦°à¦¸à§à¦¤à§à¦¤ করা হচà§à¦›à§‡ …" +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-bn_IN.json b/OpenRefine/extensions/gdata/module/langs/translation-bn_IN.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-bn_IN.json @@ -0,0 +1 @@ +{} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-cs.json b/OpenRefine/extensions/gdata/module/langs/translation-cs.json new file mode 100644 index 000000000..e06c9e151 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-cs.json @@ -0,0 +1,47 @@ +{ + "gdata-auth/authorized-label": "Proces autorizace dokonÄen. ZavÅ™ete toto okno pro návrat do OpenRefine.", + "gdata-auth/authorize-label": "OpenRefine – autorizace", + "gdata-exporter/enter-filename": "Zadejte název souboru pro export projektu na Disk Google", + "gdata-exporter/upload-google-sheets-success": "Projekt se nahrál na Disk Google ", + "gdata-exporter/enter-spreadsheet": "Zadejte název pro tabulku Google", + "gdata-exporter/new-spreadsheet": "Nová tabulka Google", + "gdata-exporter/upload-google-drive-success": "Projekt se nahrál na Disk Google ", + "gdata-exporter/upload-error": "Chyba nahrávání: ", + "gdata-exporter/uploading": "Nahrávání…", + "gdata-exporter/google-sheets": "Tabulky Google", + "gdata-exporter/export-to-google-drive": "Zálohovat projekt OpenRefine na Disk Google…", + "gdata-source/updated": "Aktualizováno", + "gdata-source/authors": "AutoÅ™i", + "gdata-source/title": "Titul", + "gdata-source/type": "Typ", + "gdata-source/alert-url": "Musíte urÄit webovou adresu (URL) pro import.", + "gdata-parsing/store-cell": "Uložit prádné buňky jako null", + "gdata-parsing/store-row": "Uložit prázdné řádky", + "gdata-parsing/limit": "řádek/řádky/řádků dat", + "gdata-parsing/limit-next": "Nahrát nejvýše", + "gdata-parsing/discard": "řádek/řádky/řádků dat", + "gdata-parsing/discard-next": "Vynechat poÄáteÄní(ch)", + "gdata-parsing/parse": "řádek/řádky jako hlaviÄky sloupců", + "gdata-parsing/parse-next": "Analyzuj další(ch)", + "gdata-parsing/ignore": "řádek/řádky/řádků na zaÄátku souboru", + "gdata-parsing/ignore-first": "Vynechat poÄáteÄní(ch)", + "gdata-parsing/preview-button": "Aktualizovat náhled", + "gdata-parsing/option": "Možnosti", + "gdata-parsing/worksheet": "Pracovní listy", + "gdata-parsing/updating-preview": "Aktualizace náhledu…", + "gdata-parsing/create-proj": "VytvoÅ™it projekt »", + "gdata-parsing/proj-name": "Název projektu", + "gdata-parsing/conf-pars": "Nastavit možnosti parsování", + "gdata-parsing/start-over": "« ZaÄít znovu", + "gdata-import/re-sign-in-another": "PÅ™ihlásit se pod jiným úÄtem", + "gdata-import/retrieving": "NaÄítání dokumentů z Google Docs", + "gdata-import/sign-out": "Odhlásit se", + "gdata-import/sign-in": "PÅ™ihlášit se", + "gdata-import/please-signin": "PÅ™ihlaste se a autorizuje přístup k vaÅ¡im datům na Googlu", + "gdata-import/auth-doc": "ZabezpeÄené dokumenty", + "gdata-import/next->": "Další »", + "gdata-import/import-by-url": "Importovat veÅ™ejný seÅ¡it Googlu pomocí URL:", + "gdata-import/title": "VeÅ™ejné dokumenty", + "gdata-import/creating": "Vytváření projektu…", + "gdata-import/preparing": "Příprava…" +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-en.json b/OpenRefine/extensions/gdata/module/langs/translation-en.json new file mode 100644 index 000000000..9b98bdc4d --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-en.json @@ -0,0 +1,48 @@ +{ + "gdata-import/preparing": "Preparing …", + "gdata-import/creating": "Creating project …", + "gdata-import/title": "Public Documents", + "gdata-import/import-by-url": "Import a public Google Spreadsheet by its URL:", + "gdata-import/next->": "Next »", + "gdata-import/auth-doc": "Authorized Documents", + "gdata-import/please-signin": "Please sign in and authorize to access your Google data", + "gdata-import/sign-in": "Sign in", + "gdata-import/sign-out": "Sign out", + "gdata-import/retrieving": "Retrieving Google Docs documents …", + "gdata-import/re-sign-in-another": "Sign in with different account", + "gdata-parsing/start-over": "« Start Over", + "gdata-parsing/conf-pars": "Configure Parsing Options", + "gdata-parsing/proj-name": "Project name", + "gdata-parsing/create-proj": "Create Project »", + "gdata-parsing/updating-preview": "Updating preview …", + "gdata-parsing/worksheet": "Worksheets", + "gdata-parsing/option": "Options", + "gdata-parsing/preview-button": "Update preview", + "gdata-parsing/disable-auto-preview": "Disable auto preview", + "gdata-parsing/ignore-first": "Ignore first", + "gdata-parsing/ignore": "line(s) at beginning of file", + "gdata-parsing/parse-next": "Parse next", + "gdata-parsing/parse": "line(s) as column headers", + "gdata-parsing/discard-next": "Discard initial", + "gdata-parsing/discard": "row(s) of data", + "gdata-parsing/limit-next": "Load at most", + "gdata-parsing/limit": "row(s) of data", + "gdata-parsing/store-row": "Store blank rows", + "gdata-parsing/store-cell": "Store blank cells as nulls", + "gdata-source/alert-url": "You must specify a web address (URL) to import.", + "gdata-source/type": "Type", + "gdata-source/title": "Title", + "gdata-source/authors": "Authors", + "gdata-source/updated": "Updated", + "gdata-exporter/export-to-google-drive": "OpenRefine project archive to Google Drive…", + "gdata-exporter/google-sheets": "Google Sheets", + "gdata-exporter/uploading": "Uploading…", + "gdata-exporter/upload-error": "Upload error: ", + "gdata-exporter/upload-google-drive-success": "Project uploaded to Google Drive ", + "gdata-exporter/new-spreadsheet": "A new Google spreadsheet", + "gdata-exporter/enter-spreadsheet": "Enter a name for the new Google spreadsheet", + "gdata-exporter/upload-google-sheets-success": "Project uploaded to Google Drive ", + "gdata-exporter/enter-filename": "Enter a filename for the project export in Google Drive", + "gdata-auth/authorize-label": "OpenRefine - Authorization", + "gdata-auth/authorized-label": "Authorization process completed. Close this window and return to OpenRefine." +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-en_GB.json b/OpenRefine/extensions/gdata/module/langs/translation-en_GB.json new file mode 100644 index 000000000..f43a17e8f --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-en_GB.json @@ -0,0 +1,6 @@ +{ + "gdata-import/auth-doc": "Authorised Documents", + "gdata-import/sign-in": "sign in and authorise", + "gdata-auth/authorize-label": "OpenRefine - Authorisation", + "gdata-auth/authorized-label": "Authorisation process completed. Close this window and return to OpenRefine." +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-es.json b/OpenRefine/extensions/gdata/module/langs/translation-es.json new file mode 100644 index 000000000..bbbdcbd7f --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-es.json @@ -0,0 +1,51 @@ +{ + "gdata-auth/authorized-label": "Se completó el proceso de autorización. Cierre esta ventana y vuelva a OpenRefine.", + "gdata-auth/authorize-label": "OpenRefine • Autorización", + "gdata-exporter/enter-filename": "Escriba un nombre de archivo para la exportación del proyecto en Google Drive", + "gdata-exporter/upload-google-sheets-success": "Se cargó el proyecto en Google Drive ", + "gdata-exporter/enter-spreadsheet": "Escriba un nombre para la hoja de Google nueva", + "gdata-exporter/new-spreadsheet": "Una hoja de cálculo de Google nueva", + "gdata-exporter/upload-google-drive-success": "Se cargó el proyecto en Google Drive ", + "gdata-exporter/upload-error": "Error de carga: ", + "gdata-exporter/uploading": "Cargando…", + "gdata-exporter/google-sheets": "Google Sheets", + "gdata-exporter/export-to-google-drive": "Archivador de proyecto de OpenRefine a Google Drive…", + "gdata-source/updated": "Actualización el", + "gdata-source/authors": "Autores", + "gdata-source/title": "Título", + "gdata-source/type": "Tipo", + "gdata-source/alert-url": "Debe especificar una dirección web (URL) que importar.", + "gdata-parsing/store-cell": "Almacenar celdas vacías como nulos", + "gdata-parsing/store-row": "Almacenar filas vacías", + "gdata-parsing/limit": "filas de datos", + "gdata-parsing/limit-next": "Cargar como máximo", + "gdata-parsing/discard": "filas de datos iniciales", + "gdata-parsing/discard-next": "Descartar", + "gdata-parsing/parse": "renglones como cabeceras de columnas", + "gdata-parsing/parse-next": "Analizar próximos", + "gdata-parsing/ignore": "renglones al principio del archivo", + "gdata-parsing/ignore-first": "Ignorar primeros", + "gdata-parsing/preview-button": "Actualizar previsualización", + "gdata-parsing/option": "Opciones", + "gdata-parsing/worksheet": "Hojas de trabajo", + "gdata-parsing/updating-preview": "Actualizando previsualización…", + "gdata-parsing/create-proj": "Crear proyecto →", + "gdata-parsing/proj-name": "Nombre del proyecto", + "gdata-parsing/conf-pars": "Configurar opciones de análisis", + "gdata-parsing/start-over": "← Comenzar de cero", + "gdata-import/another-account": "con otra cuenta", + "gdata-import/re-sign-in": "acceder de nuevo", + "gdata-import/retrieving": "Recuperando los documentos de Google Docs…", + "gdata-import/access-data": "el acceso a sus datos de Google.", + "gdata-import/sign-out": "Finalizar sesión", + "gdata-import/sign-in": "Ingrese", + "gdata-import/please": "Rogamos que", + "gdata-import/auth-doc": "Documentos autorizados", + "gdata-import/next->": "Siguiente →", + "gdata-import/import-by-url": "Importe una hoja de cálculo pública de Google mediante su URL:", + "gdata-import/title": "Documentos públicos", + "gdata-import/creating": "Creando proyecto…", + "gdata-import/preparing": "Preparando…", + "gdata-import/re-sign-in-another": "Iniciar sesión con una cuenta diferente", + "gdata-import/please-signin": "Inicie sesión y autorice el acceso a sus datos de Google" +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-fr.json b/OpenRefine/extensions/gdata/module/langs/translation-fr.json new file mode 100644 index 000000000..bffb8f794 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-fr.json @@ -0,0 +1,53 @@ +{ + "gdata-import/preparing": "Préparation…", + "gdata-import/creating": "Création du projet…", + "gdata-import/title": "Documents publics", + "gdata-import/import-by-url": "Importer un tableau public Google Spreadsheet par son URL :", + "gdata-import/next->": "Suivant »", + "gdata-import/auth-doc": "Documents autorisés", + "gdata-import/please": "Merci", + "gdata-import/sign-in": "Se connecter", + "gdata-import/sign-out": "Se déconnecter", + "gdata-import/access-data": "l’accès à vos données Google.", + "gdata-import/retrieving": "Récupération des documents de Google Docs…", + "gdata-import/re-sign-in": "se reconnecter", + "gdata-import/another-account": "avec un autre compte", + "gdata-parsing/start-over": "« Recommencer", + "gdata-parsing/conf-pars": "Configurer les options d’analyse", + "gdata-parsing/proj-name": "Nom du projet", + "gdata-parsing/create-proj": "Créer un projet »", + "gdata-parsing/updating-preview": "Mise à jour de l’aperçu…", + "gdata-parsing/worksheet": "Feuilles", + "gdata-parsing/option": "Options", + "gdata-parsing/preview-button": "Mettre à jour l’aperçu", + "gdata-parsing/ignore-first": "Ignorer la ou les premières", + "gdata-parsing/ignore": "ligne(s) du début du fichier", + "gdata-parsing/parse-next": "Analyser la ou les", + "gdata-parsing/parse": "ligne(s) suivante(s) comme entêtes de colonnes", + "gdata-parsing/discard-next": "Ignorer la ou les", + "gdata-parsing/discard": "première(s) ligne(s) de données", + "gdata-parsing/limit-next": "Charger au plus", + "gdata-parsing/limit": "ligne(s) de données", + "gdata-parsing/store-row": "Conserver les lignes vides", + "gdata-parsing/store-cell": "Enregistrer les cellules vides comme des valeurs nulles", + "gdata-source/alert-url": "Vous devez indiquer une adresse web (URL) à importer.", + "gdata-source/type": "Type", + "gdata-source/title": "Titre", + "gdata-source/authors": "Auteurs", + "gdata-source/updated": "Mis à jour", + "gdata-exporter/uploading": "Téléversement…", + "gdata-exporter/upload-error": "Erreur de téléversement : ", + "gdata-exporter/new-spreadsheet": "Un nouveau tableau Google Spreadsheet", + "gdata-exporter/enter-spreadsheet": "Indiquer un nom pour le nouveau tableau Google Spreadsheet", + "gdata-exporter/upload-success": "Le projet a été chargé avec succès dans Google Drive avec l'identifiant ", + "gdata-auth/authorize-label": "OpenRefine - Autorisation", + "gdata-auth/authorized-label": "Procédure d’autorisation terminée. Fermer cette fenêtre et revenir à OpenRefine.", + "gdata-exporter/enter-filename": "Entrez un nom de fichier pour l'export du projet dans Google Drive", + "gdata-exporter/upload-google-sheets-success": "Projet téléversé sur Google Drive ", + "gdata-exporter/upload-google-drive-success": "Projet téléversé sur Google Drive ", + "gdata-exporter/google-sheets": "Google Sheets", + "gdata-import/re-sign-in-another": "Connectez-vous avec un autre compte", + "gdata-import/please-signin": "Veuillez vous connecter et autoriser l'accès à vos données Google", + "gdata-exporter/export-to-google-drive": "Projet OpenRefine archivé dans Google Drive…", + "gdata-parsing/disable-auto-preview": "Désactiver l'aperçu automatique" +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-he.json b/OpenRefine/extensions/gdata/module/langs/translation-he.json new file mode 100644 index 000000000..670117a08 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-he.json @@ -0,0 +1,52 @@ +{ + "gdata-import/preparing": "בהכנות…", + "gdata-import/creating": "×”×ž×™×–× × ×•×¦×¨â€¦", + "gdata-import/title": "×ž×¡×ž×›×™× ×¦×™×‘×•×¨×™×™×", + "gdata-import/import-by-url": "×™×™×‘×•× ×’×™×œ×™×•×Ÿ × ×ª×•× ×™× ×¦×™×‘×•×¨×™ מ־Google לפי הכתובת שלו:", + "gdata-import/next->": "×”×‘× «", + "gdata-import/auth-doc": "×ž×¡×ž×›×™× ×ž×ושרי×", + "gdata-import/please": "בבקשה", + "gdata-import/sign-in": "כניסה", + "gdata-import/sign-out": "יצי××”", + "gdata-import/access-data": "גישה ×œ× ×ª×•× ×™× ×©×œ×š ב־Google.", + "gdata-import/retrieving": "×ž×ª×§×‘×œ×™× ×ž×¡×ž×›×™× ×žÖ¾Google Docs…", + "gdata-import/re-sign-in": "להיכנס מחדש", + "gdata-import/another-account": "×¢× ×—×©×‘×•×Ÿ ×חר", + "gdata-parsing/start-over": "» להתחיל מההתחלה", + "gdata-parsing/conf-pars": "הגדרת ×פשרויות פענוח", + "gdata-parsing/proj-name": "×©× ×”×ž×™×–×", + "gdata-parsing/create-proj": "יצירת ×ž×™×–× «", + "gdata-parsing/updating-preview": "התצוגה המקדימה מתעדכנת…", + "gdata-parsing/worksheet": "גיליונות נתוני×", + "gdata-parsing/option": "×פשרויות", + "gdata-parsing/preview-button": "עדכון תצוגה מקדימה", + "gdata-parsing/ignore-first": "×œ×”×ª×¢×œ× ×žÖ¾", + "gdata-parsing/ignore": "השורות הר×שונות בתחילת הקובץ", + "gdata-parsing/parse-next": "לפענח ×ת", + "gdata-parsing/parse": "השורות הב×ות ככותרות לעמודות", + "gdata-parsing/discard-next": "התעלמות מ־", + "gdata-parsing/discard": "שורות ×”× ×ª×•× ×™× ×”×¨×שונות", + "gdata-parsing/limit-next": "לטעון", + "gdata-parsing/limit": "שורות × ×ª×•× ×™× ×œ×›×œ היותר", + "gdata-parsing/store-row": "ל×חסן שורות ריקות", + "gdata-parsing/store-cell": "ל×חסן ת××™× ×¨×™×§×™× ×›Ö¾null (ריק)", + "gdata-source/alert-url": "עליך לציין כתובת (URL) לייבו×.", + "gdata-source/type": "סוג", + "gdata-source/title": "כותרת", + "gdata-source/authors": "מחברי×", + "gdata-source/updated": "מעודכן", + "gdata-exporter/uploading": "מתבצעת העל×ה…", + "gdata-exporter/upload-error": "שגי×ת העל××”: ", + "gdata-exporter/new-spreadsheet": "גיליון × ×ª×•× ×™× ×—×“×© ב־Google", + "gdata-exporter/enter-spreadsheet": "× × ×œ×ž×œ× ×©× ×œ×’×™×œ×™×•×Ÿ ×”× ×ª×•× ×™× ×”×—×“×© ב־Google", + "gdata-auth/authorize-label": "OpenRefine - ×ישור", + "gdata-auth/authorized-label": "תהליך ×”×ישור הסתיי×. יש לסגור ×ת החלון ולחזור ל־OpenRefine.", + "gdata-exporter/enter-filename": "× × ×œ×ž×œ× ×©× ×§×•×‘×¥ ×œ×™×™×¦×•× ×”×ž×™×–× ×‘Ö¾Google Drive", + "gdata-exporter/upload-google-sheets-success": "×”×ž×™×–× ×”×•×¢×œ×” ל־Google Drive ", + "gdata-exporter/upload-google-drive-success": "×”×ž×™×–× ×”×•×¢×œ×” ל־Google Drive ", + "gdata-exporter/google-sheets": "Google Sheets", + "gdata-exporter/export-to-google-drive": "×ž×™×–× OpenRefine שומר ב×רכיון ל־Google Drive…", + "gdata-import/re-sign-in-another": "כניסה ×¢× ×—×©×‘×•×Ÿ ×חר", + "gdata-import/please-signin": "× × ×œ×”×™×›× ×¡ כדי ל×שר ×ת הגישה ×œ× ×ª×•× ×™× ×©×œ×š ב־Google", + "gdata-parsing/disable-auto-preview": "השבתת תצוגה מקדימה ×וטומטית" +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-it.json b/OpenRefine/extensions/gdata/module/langs/translation-it.json new file mode 100644 index 000000000..6a57fdd8e --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-it.json @@ -0,0 +1,50 @@ +{ + "gdata-import/preparing": "In preparazione…", + "gdata-import/creating": "Sto creando il progetto…", + "gdata-import/title": "Documenti Pubblici", + "gdata-import/import-by-url": "Importa un Google Spreadsheet pubblico inserendo l'URL:", + "gdata-import/next->": "Avanti »", + "gdata-import/auth-doc": "Documenti Autorizzati", + "gdata-import/please": "Per piacere", + "gdata-import/sign-in": "autenticati ed autorizza", + "gdata-import/sign-out": "esci", + "gdata-import/access-data": "accedi ai tuoi dati Google.", + "gdata-import/retrieving": "Sto recuperando i documenti da Google Docs…", + "gdata-import/re-sign-in": "rieffettua l'autenticazione", + "gdata-import/another-account": "con un altro account", + "gdata-parsing/start-over": "« Ricomincia", + "gdata-parsing/conf-pars": "Configura le opzioni per il parsing", + "gdata-parsing/proj-name": "Nome del progetto", + "gdata-parsing/create-proj": "Crea un progetto »", + "gdata-parsing/updating-preview": "Aggiornamento anteprima…", + "gdata-parsing/worksheet": "Fogli di lavoro", + "gdata-parsing/option": "Opzioni", + "gdata-parsing/preview-button": "Aggiorna la Preview", + "gdata-parsing/ignore-first": "Ignora le prime", + "gdata-parsing/ignore": "linee all'inizio del file", + "gdata-parsing/parse-next": "Parsa le prossime", + "gdata-parsing/parse": "linee come nomi delle colonne", + "gdata-parsing/discard-next": "Scarta le prime", + "gdata-parsing/discard": "righe di dati", + "gdata-parsing/limit-next": "Carica al massimo", + "gdata-parsing/limit": "righe di dati", + "gdata-parsing/store-row": "Salva righe vuote", + "gdata-parsing/store-cell": "Salva le celle vuote come 'null'", + "gdata-source/alert-url": "Devi specificare un indirizzo web (URL) per l'import.", + "gdata-source/type": "Tipo", + "gdata-source/title": "Titolo", + "gdata-source/authors": "Autori", + "gdata-source/updated": "Aggiornato", + "gdata-exporter/uploading": "Caricando…", + "gdata-exporter/upload-error": "Errore durante il caricamento: ", + "gdata-exporter/new-spreadsheet": "Un nuovo Google spreadsheet", + "gdata-exporter/enter-spreadsheet": "Inserisci un nome per il nuovo Google spreadsheet", + "gdata-auth/authorize-label": "OpenRefine - Autorizzazione", + "gdata-auth/authorized-label": "Processo di autorizzazione completato. Chiudi questa finestra e torna ad OpenRefine.", + "gdata-exporter/upload-success": "Il progetto è stato caricato con successo su Google Drive ", + "gdata-exporter/enter-filename": "Inserisci un nome del file per esportare il progetto su Google Drive", + "gdata-exporter/upload-google-sheets-success": "Progetto caricato su Google Drive ", + "gdata-exporter/export-to-google-drive": "Archiviando progetto di OpenRefine su Google Drive…", + "gdata-exporter/upload-google-drive-success": "Progetto caricato su Google Drive ", + "gdata-exporter/google-sheets": "Google Sheets" +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-jp.json b/OpenRefine/extensions/gdata/module/langs/translation-jp.json new file mode 100644 index 000000000..4c4afcfcb --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-jp.json @@ -0,0 +1,52 @@ +{ + "gdata-import/preparing": "準備中…", + "gdata-import/creating": "プロジェクトを作る…", + "gdata-import/title": "一般公開文書(public document)", + "gdata-import/import-by-url": "一般公開ã—ã¦ã„る(public)Google Spreadsheetã®URLを入力ã—ã¦ãã ã•ã„:", + "gdata-import/next->": "次㸠»", + "gdata-import/auth-doc": "制é™ä»˜ã文書(authorized document)", + "gdata-import/please": "ã¾ãš", + "gdata-import/sign-in": "サインイン", + "gdata-import/sign-out": "サインアウト", + "gdata-import/access-data": "ã—ã¦ã‹ã‚‰ã€ã‚ãªãŸã®Google文書ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™.", + "gdata-import/retrieving": "Google Docsã‚’å–り込んã§ã„ã¾ã™â€¦", + "gdata-import/re-sign-in": "サインã—ç›´ã™", + "gdata-import/another-account": "別ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆ", + "gdata-parsing/start-over": "« ã‚„ã‚Šç›´ã—", + "gdata-parsing/conf-pars": "解æžã‚ªãƒ—ションã®è¨­å®š", + "gdata-parsing/proj-name": "プロジェクトå", + "gdata-parsing/create-proj": "プロジェクトを作る »", + "gdata-parsing/updating-preview": "プレビューを更新中…", + "gdata-parsing/worksheet": "シート", + "gdata-parsing/option": "オプション", + "gdata-parsing/preview-button": "プレビューを更新", + "gdata-parsing/ignore-first": "先頭を無視", + "gdata-parsing/ignore": "行分", + "gdata-parsing/parse-next": "カラムåã¨ã—ã¦è§£é‡ˆ", + "gdata-parsing/parse": "行分", + "gdata-parsing/discard-next": "先頭データを破棄", + "gdata-parsing/discard": "行分", + "gdata-parsing/limit-next": "最大読ã¿è¾¼ã¿è¡Œæ•°", + "gdata-parsing/limit": "行分", + "gdata-parsing/store-row": "空白行もä¿å­˜", + "gdata-parsing/store-cell": "nullã¨ã—ã¦ç©ºç™½ã‚»ãƒ«ã‚’ä¿å­˜", + "gdata-source/alert-url": "インãƒãƒ¼ãƒˆã™ã‚‹ã‚¢ãƒ‰ãƒ¬ã‚¹ï¼ˆURL)を入力ã—ã¦ãã ã•ã„.", + "gdata-source/type": "å½¢å¼", + "gdata-source/title": "é¡Œå", + "gdata-source/authors": "著者", + "gdata-source/updated": "更新済ã¿", + "gdata-exporter/uploading": "アップロード中…", + "gdata-exporter/upload-error": "アップロードã§ã‚¨ãƒ©ãƒ¼ : ", + "gdata-exporter/new-spreadsheet": "æ–°ã—ã„Google spreadsheet", + "gdata-exporter/enter-spreadsheet": "æ–°ã—ã„Google spreadsheetã®é¡Œåを入力ã—ã¦ãã ã•ã„", + "gdata-exporter/upload-success": "プロジェクトãŒGoogle Driveã«ã‚¢ãƒƒãƒ—ロードã•ã‚Œã¾ã—㟠", + "gdata-auth/authorize-label": "OpenRefine - èªè¨¼", + "gdata-auth/authorized-label": "èªè¨¼ãŒå®Œäº†ã—ã¾ã—ãŸã€‚ã“ã®ã‚¦ã‚¤ãƒ³ãƒ‰ã‚¦ã‚’é–‰ã˜ã¦OpenRefineã§ä½œæ¥­ã§ãã¾ã™.", + "gdata-exporter/enter-filename": "Google Driveã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«åを入力", + "gdata-exporter/google-sheets": "Googleシート", + "gdata-exporter/upload-google-sheets-success": "Google Driveã«ã‚¢ãƒƒãƒ—ロードã•ã‚ŒãŸãƒ—ロジェクト ", + "gdata-exporter/upload-google-drive-success": "Google Driveã«ã‚¢ãƒƒãƒ—ロードã•ã‚ŒãŸãƒ—ロジェクト ", + "gdata-exporter/export-to-google-drive": "プロジェクトをGoogle Driveã¸â€¦", + "gdata-import/re-sign-in-another": "別ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã§ã‚µã‚¤ãƒ³ã‚¤ãƒ³", + "gdata-import/please-signin": "サインã—ã¦Googleã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©é™ã‚’èªè¨¼ã—ã¦ãã ã•ã„" +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-ko.json b/OpenRefine/extensions/gdata/module/langs/translation-ko.json new file mode 100644 index 000000000..fec6dc8fb --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-ko.json @@ -0,0 +1,45 @@ +{ + "gdata-import/preparing": "준비중 ...", + "gdata-import/creating": "프로ì íŠ¸ ìƒì„±ì¤‘ ...", + "gdata-import/title": "공개 문서", + "gdata-import/import-by-url": "ë‹¤ìŒ URLì„ ê°€ì§€ê³  public Google Spreadsheet ë˜ëŠ” Fusion Table ì„ ìž„í¬íŠ¸í•˜ì„¸ìš”:", + "gdata-import/next->": "ë‹¤ìŒ »", + "gdata-import/auth-doc": "ê²€ì¦ëœ 문서", + "gdata-import/please": "해주세요", + "gdata-import/sign-in": "서명 ë° ê²€ì¦í•´ì£¼ì„¸ìš”", + "gdata-import/sign-out": "로그아웃", + "gdata-import/access-data": "ë‹¹ì‹ ì˜ Google ë°ì´í„°ì— 접근하세요.", + "gdata-import/retrieving": "Google Docs 문서를 가져오는중 ...", + "gdata-import/re-sign-in": "재 로그ì¸", + "gdata-import/another-account": "다른 계정으로", + "gdata-parsing/start-over": "« 다시 시작", + "gdata-parsing/conf-pars": "파싱 옵션 설정", + "gdata-parsing/proj-name": "프로ì íŠ¸ ì´ë¦„", + "gdata-parsing/create-proj": "프로ì íŠ¸ ìƒì„± »", + "gdata-parsing/updating-preview": "미리보기 ì—…ë°ì´íŠ¸ì¤‘ ...", + "gdata-parsing/worksheet": "워í¬ì‹œíŠ¸", + "gdata-parsing/option": "옵션", + "gdata-parsing/preview-button": "ì—…ë°ì´íŠ¸ ë¯¸ë¦¬ë³´ê¸°", + "gdata-parsing/ignore-first": "처ìŒì„ 무시", + "gdata-parsing/ignore": "파ì¼ì˜ 첫번째 줄(들)", + "gdata-parsing/parse-next": "ë‹¤ìŒ íŒŒì‹±", + "gdata-parsing/parse": "컬럼 í—¤ë”ë¡œ ë¼ì¸(들)ì„", + "gdata-parsing/discard-next": "ì´ˆê¸°ê°’ì„ ë¬´ì‹œ", + "gdata-parsing/discard": "ë°ì´í„° 줄수", + "gdata-parsing/limit-next": "최대한 로드하세요", + "gdata-parsing/limit": "ë°ì´í„° 줄수", + "gdata-parsing/store-row": "빈 ì¤„ì„ ì €ìž¥í•˜ì„¸ìš”", + "gdata-parsing/store-cell": "빈 ì…€ì„ nullë¡œ 저장하세요", + "gdata-source/alert-url": "ìž„í¬íŠ¸í•  웹주소(URL)ì„ ì§€ì •í•´ì•¼ 합니다.", + "gdata-source/type": "타입", + "gdata-source/title": "타ì´í‹€", + "gdata-source/authors": "ì €ìž", + "gdata-source/updated": "ì—…ë°ì´íŠ¸", + "gdata-exporter/uploading": "ì—…ë°ì´íŠ¸ì¤‘...", + "gdata-exporter/upload-error": "업로드 ì—러: ", + "gdata-exporter/upload-success": "ë‹¤ìŒ Idë¡œ Google Driveì— í”„ë¡œì íŠ¸ê°€ 성공ì ìœ¼ë¡œ 업로드 ë˜ì—ˆìŠµë‹ˆë‹¤ ", + "gdata-exporter/new-spreadsheet": "새로운 Google speadsheet", + "gdata-exporter/enter-spreadsheet": "새로운 Google Spreadsheet ì´ë¦„ì„ ìž…ë ¥í•˜ì„¸ìš”", + "gdata-auth/authorize-label": "OpenRefine - ê²€ì¦", + "gdata-auth/authorized-label": "ê²€ì¦ í”„ë¡œì„¸ìŠ¤ 완료. ì´ ì°½ì„ ë‹«ê³  OpenRefine으로 ëŒì•„가세요." +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-nb_NO.json b/OpenRefine/extensions/gdata/module/langs/translation-nb_NO.json new file mode 100644 index 000000000..1da4463d2 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-nb_NO.json @@ -0,0 +1,49 @@ +{ + "gdata-import/preparing": "Forbereder …", + "gdata-import/creating": "Oppretter prosjekt …", + "gdata-import/title": "Offentlige dokumenter", + "gdata-import/import-by-url": "Importer et offentlig Google-regneark fra dens nettadresse:", + "gdata-import/next->": "Neste »", + "gdata-import/auth-doc": "Godkjente dokumenter", + "gdata-import/sign-in": "Logg inn og godkjenn", + "gdata-import/sign-out": "Logg ut", + "gdata-import/access-data": "Tilgang til din Google-data.", + "gdata-import/retrieving": "Henter Google Docs-dokumenter …", + "gdata-import/re-sign-in": "Logg inn igjen", + "gdata-import/another-account": "med en annen konto", + "gdata-import/please": "Vær sÃ¥ snill Ã¥", + "gdata-parsing/start-over": "« start om", + "gdata-parsing/conf-pars": "Sett opp fortolkningsvalg", + "gdata-parsing/proj-name": "Prosjektnavn", + "gdata-parsing/create-proj": "Opprett prosjekt »", + "gdata-parsing/updating-preview": "Oppdaterer forhÃ¥ndsvisning …", + "gdata-parsing/worksheet": "Arbeidsdokumenter", + "gdata-parsing/option": "Alternativ", + "gdata-parsing/preview-button": "Oppdater forhÃ¥ndsvisning", + "gdata-parsing/ignore-first": "Ignorer første", + "gdata-parsing/ignore": "linje(ne) i begynnelsen av filen", + "gdata-parsing/parse-next": "Fortolk neste", + "gdata-parsing/parse": "line(r) som kolonnerubrikker", + "gdata-parsing/discard-next": "Forkast innledende", + "gdata-parsing/discard": "rad(er) med data", + "gdata-parsing/limit-next": "Last inn høyst", + "gdata-parsing/limit": "rad(er) med data", + "gdata-parsing/store-row": "Lagre blanke rader", + "gdata-parsing/store-cell": "Lagre blanke celler som null", + "gdata-source/alert-url": "Du mÃ¥ angi en nettadresse Ã¥ importere.", + "gdata-source/type": "Type", + "gdata-source/title": "Tittel", + "gdata-source/authors": "Forfattere", + "gdata-source/updated": "Oppdatert", + "gdata-exporter/uploading": "Laster opp …", + "gdata-exporter/upload-error": "Opplastingsfeil: ", + "gdata-exporter/new-spreadsheet": "Nytt Google-regneark", + "gdata-exporter/enter-spreadsheet": "Navngi det nye Google-regnearket", + "gdata-auth/authorize-label": "OpenRefine - Identitetsbekreftelse", + "gdata-auth/authorized-label": "Identitet bekreftet. Lukk dette vinduet og returner til OpenRefine.", + "gdata-exporter/enter-filename": "Skriv inn et filnavn for prosjekteksporten i Google Drive", + "gdata-exporter/export-to-google-drive": "OpenRefine-prosjekt arkivert til Google Drive…", + "gdata-exporter/google-sheets": "Google Sheets", + "gdata-exporter/upload-google-drive-success": "Prosjekt opplastet til Google Drive ", + "gdata-exporter/upload-google-sheets-success": "Prosjekt opplastet til Google Drive " +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-pl.json b/OpenRefine/extensions/gdata/module/langs/translation-pl.json new file mode 100644 index 000000000..46ceff747 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-pl.json @@ -0,0 +1,18 @@ +{ + "gdata-parsing/start-over": "«Zacznij od nowa", + "gdata-import/re-sign-in-another": "Zaloguj siÄ™ za pomocÄ… innego konta", + "gdata-parsing/create-proj": "Utwórz projekt »", + "gdata-parsing/updating-preview": "Aktualizacja podglÄ…du …", + "gdata-import/title": "Publiczne dokumenty", + "gdata-import/next->": "NastÄ™pny»", + "gdata-import/auth-doc": "Autoryzowane Dokumenty", + "gdata-import/please-signin": "ProszÄ™ zaloguj siÄ™ i autoryzuj, aby otrzymać dostÄ™p do twoich danych Google", + "gdata-import/preparing": "Przygotowanie…", + "gdata-import/creating": "Tworzenie projektu…", + "gdata-import/sign-in": "Zaloguj siÄ™", + "gdata-import/sign-out": "Wyloguj siÄ™", + "gdata-import/retrieving": "Pobieranie dokumentów Google Docs …", + "gdata-parsing/ignore-first": "Najpierw zignoruj", + "gdata-parsing/conf-pars": "Konfiguracja opcji parsowania", + "gdata-parsing/option": "Opcje" +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-pt.json b/OpenRefine/extensions/gdata/module/langs/translation-pt.json new file mode 100644 index 000000000..4b998c9d2 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-pt.json @@ -0,0 +1,51 @@ +{ + "gdata-source/title": "Título", + "gdata-exporter/upload-error": "Erro no carregamento: ", + "gdata-import/sign-out": "Sair", + "gdata-exporter/enter-spreadsheet": "Digite um nome para a nova planilha do Google", + "gdata-import/retrieving": "Recuperando documentos do Google Docs …", + "gdata-auth/authorized-label": "Processo de autorização concluído. Feche esta janela e retorne ao OpenRefine.", + "gdata-exporter/enter-filename": "Digite um nome de ficheiro para exportar o projeto no Google Drive", + "gdata-source/alert-url": "Deve especificar um endereço web (URL) para importar.", + "gdata-parsing/conf-pars": "Configurar opções de análise", + "gdata-import/another-account": "com outra conta", + "gdata-parsing/start-over": "« Recomeçar", + "gdata-parsing/ignore": "linhas(s) no começo do ficheiro", + "gdata-import/please": "Por favor,", + "gdata-parsing/store-cell": "Carregar células em branco como nulas", + "gdata-import/auth-doc": "Documentos autorizados", + "gdata-parsing/option": "Opções", + "gdata-exporter/upload-google-sheets-success": "Projeto enviado para o Google Drive ", + "gdata-parsing/parse-next": "Analisar próximo", + "gdata-parsing/worksheet": "Planilhas", + "gdata-import/title": "Documentos públicos", + "gdata-parsing/limit": "linhas(s) de dados", + "gdata-exporter/export-to-google-drive": "Ficheiro de projeto do OpenRefine para Google Drive…", + "gdata-import/sign-in": "Iniciar sessão", + "gdata-import/import-by-url": "Importar uma Planilha Google pública a partir de sua URL:", + "gdata-parsing/ignore-first": "Ignorar primeira(s)", + "gdata-auth/authorize-label": "OpenRefine - Autorização", + "gdata-import/access-data": "acesso aos seus dados do Google.", + "gdata-exporter/upload-google-drive-success": "Projeto enviado para o Google Drive ", + "gdata-source/authors": "Autores", + "gdata-exporter/uploading": "Carregando…", + "gdata-parsing/create-proj": "Criar projeto »", + "gdata-parsing/parse": "linha(s) como nomes das colunas", + "gdata-parsing/store-row": "Carregar linhas em branco", + "gdata-parsing/proj-name": "Nome do projeto", + "gdata-exporter/new-spreadsheet": "Uma nova planilha do Google", + "gdata-import/preparing": "Preparando …", + "gdata-parsing/preview-button": "Atualizar Pré-visualização", + "gdata-import/next->": "Próximo »", + "gdata-import/creating": "Criando projeto …", + "gdata-parsing/discard": "linhas(s) de dados", + "gdata-source/type": "Tipo", + "gdata-source/updated": "Atualizado", + "gdata-import/re-sign-in": "entrar novamente", + "gdata-exporter/google-sheets": "Planilhas Google", + "gdata-parsing/discard-next": "Descartar primeira(s)", + "gdata-parsing/updating-preview": "Atualizando pré-visualização …", + "gdata-parsing/limit-next": "Carregar ao menos", + "gdata-import/re-sign-in-another": "Faça login com conta diferente", + "gdata-import/please-signin": "Faça login e autorize o acesso aos seus dados do Google" +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-pt_BR.json b/OpenRefine/extensions/gdata/module/langs/translation-pt_BR.json new file mode 100644 index 000000000..da88c685d --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-pt_BR.json @@ -0,0 +1,49 @@ +{ + "gdata-parsing/start-over": "« Recomeçar", + "gdata-import/please": "Por favor,", + "gdata-import/access-data": "acesso aos seus dados do Google.", + "gdata-auth/authorized-label": "Processo de autorização concluído. Feche esta janela e retorne ao OpenRefine.", + "gdata-auth/authorize-label": "OpenRefine - Autorização", + "gdata-exporter/enter-filename": "Digite um nome de arquivo para exportar o projeto no Google Drive", + "gdata-exporter/upload-google-sheets-success": "Projeto enviado para o Google Drive ", + "gdata-exporter/enter-spreadsheet": "Digite um nome para a nova planilha do Google", + "gdata-exporter/upload-google-drive-success": "Projeto enviado para o Google Drive ", + "gdata-exporter/new-spreadsheet": "Uma nova planilha do Google", + "gdata-exporter/upload-error": "Erro no carregamento: ", + "gdata-exporter/uploading": "Carregando…", + "gdata-exporter/google-sheets": "Planilhas Google", + "gdata-exporter/export-to-google-drive": "Arquivo de projeto do OpenRefine para Google Drive…", + "gdata-source/updated": "Atualizado", + "gdata-source/authors": "Autores", + "gdata-source/title": "Título", + "gdata-source/type": "Tipo", + "gdata-source/alert-url": "Você deve especificar um endereço web (URL) para importar.", + "gdata-parsing/store-cell": "Carregar células em branco como nulas", + "gdata-parsing/store-row": "Carregar linhas em branco", + "gdata-parsing/limit": "linhas(s) de dados", + "gdata-parsing/limit-next": "Carregar ao menos", + "gdata-parsing/discard": "linhas(s) de dados", + "gdata-parsing/discard-next": "Descartar primeira(s)", + "gdata-parsing/parse": "linha(s) como nomes das colunas", + "gdata-parsing/parse-next": "Analisar próximo", + "gdata-parsing/ignore": "linhas(s) no começo do arquivo", + "gdata-parsing/ignore-first": "Ignorar primeira(s)", + "gdata-parsing/preview-button": "Atualizar Pré-visualização", + "gdata-parsing/option": "Opções", + "gdata-parsing/worksheet": "Planilhas", + "gdata-parsing/updating-preview": "Atualizando pré-visualização …", + "gdata-parsing/create-proj": "Criar projeto »", + "gdata-parsing/proj-name": "Nome do projeto", + "gdata-parsing/conf-pars": "Configurar opções de análise", + "gdata-import/another-account": "com outra conta", + "gdata-import/re-sign-in": "entrar novamente", + "gdata-import/retrieving": "Recuperando documentos do Google Docs …", + "gdata-import/sign-out": "sair", + "gdata-import/sign-in": "entrar e autorizar", + "gdata-import/auth-doc": "Documentos autorizados", + "gdata-import/next->": "Próximo »", + "gdata-import/import-by-url": "Importar uma Planilha Google pública a partir de sua URL:", + "gdata-import/title": "Documentos públicos", + "gdata-import/creating": "Criando projeto …", + "gdata-import/preparing": "Preparando …" +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-pt_PT.json b/OpenRefine/extensions/gdata/module/langs/translation-pt_PT.json new file mode 100644 index 000000000..4b998c9d2 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-pt_PT.json @@ -0,0 +1,51 @@ +{ + "gdata-source/title": "Título", + "gdata-exporter/upload-error": "Erro no carregamento: ", + "gdata-import/sign-out": "Sair", + "gdata-exporter/enter-spreadsheet": "Digite um nome para a nova planilha do Google", + "gdata-import/retrieving": "Recuperando documentos do Google Docs …", + "gdata-auth/authorized-label": "Processo de autorização concluído. Feche esta janela e retorne ao OpenRefine.", + "gdata-exporter/enter-filename": "Digite um nome de ficheiro para exportar o projeto no Google Drive", + "gdata-source/alert-url": "Deve especificar um endereço web (URL) para importar.", + "gdata-parsing/conf-pars": "Configurar opções de análise", + "gdata-import/another-account": "com outra conta", + "gdata-parsing/start-over": "« Recomeçar", + "gdata-parsing/ignore": "linhas(s) no começo do ficheiro", + "gdata-import/please": "Por favor,", + "gdata-parsing/store-cell": "Carregar células em branco como nulas", + "gdata-import/auth-doc": "Documentos autorizados", + "gdata-parsing/option": "Opções", + "gdata-exporter/upload-google-sheets-success": "Projeto enviado para o Google Drive ", + "gdata-parsing/parse-next": "Analisar próximo", + "gdata-parsing/worksheet": "Planilhas", + "gdata-import/title": "Documentos públicos", + "gdata-parsing/limit": "linhas(s) de dados", + "gdata-exporter/export-to-google-drive": "Ficheiro de projeto do OpenRefine para Google Drive…", + "gdata-import/sign-in": "Iniciar sessão", + "gdata-import/import-by-url": "Importar uma Planilha Google pública a partir de sua URL:", + "gdata-parsing/ignore-first": "Ignorar primeira(s)", + "gdata-auth/authorize-label": "OpenRefine - Autorização", + "gdata-import/access-data": "acesso aos seus dados do Google.", + "gdata-exporter/upload-google-drive-success": "Projeto enviado para o Google Drive ", + "gdata-source/authors": "Autores", + "gdata-exporter/uploading": "Carregando…", + "gdata-parsing/create-proj": "Criar projeto »", + "gdata-parsing/parse": "linha(s) como nomes das colunas", + "gdata-parsing/store-row": "Carregar linhas em branco", + "gdata-parsing/proj-name": "Nome do projeto", + "gdata-exporter/new-spreadsheet": "Uma nova planilha do Google", + "gdata-import/preparing": "Preparando …", + "gdata-parsing/preview-button": "Atualizar Pré-visualização", + "gdata-import/next->": "Próximo »", + "gdata-import/creating": "Criando projeto …", + "gdata-parsing/discard": "linhas(s) de dados", + "gdata-source/type": "Tipo", + "gdata-source/updated": "Atualizado", + "gdata-import/re-sign-in": "entrar novamente", + "gdata-exporter/google-sheets": "Planilhas Google", + "gdata-parsing/discard-next": "Descartar primeira(s)", + "gdata-parsing/updating-preview": "Atualizando pré-visualização …", + "gdata-parsing/limit-next": "Carregar ao menos", + "gdata-import/re-sign-in-another": "Faça login com conta diferente", + "gdata-import/please-signin": "Faça login e autorize o acesso aos seus dados do Google" +} diff --git a/OpenRefine/extensions/gdata/module/langs/translation-sv.json b/OpenRefine/extensions/gdata/module/langs/translation-sv.json new file mode 100644 index 000000000..5a9945428 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/langs/translation-sv.json @@ -0,0 +1,45 @@ +{ + "gdata-import/preparing": "Förbereder…", + "gdata-import/creating": "Skapar projekt…", + "gdata-import/title": "Offentliga dokument", + "gdata-import/import-by-url": "Importera ett publikt Google-kalkylblad eller fusionstabell med dess URL:", + "gdata-import/next->": "Nästa »", + "gdata-import/auth-doc": "Godkända dokument", + "gdata-import/please": "Var god", + "gdata-import/sign-in": "logga in och godkänn", + "gdata-import/sign-out": "logga ut", + "gdata-import/access-data": "tillgÃ¥ng till dina Google-data.", + "gdata-import/retrieving": "Hämtar Google Docs-dokument…", + "gdata-import/re-sign-in": "logga in igen", + "gdata-import/another-account": "med ett annat konto", + "gdata-parsing/start-over": "« Börja om", + "gdata-parsing/conf-pars": "Konfigurera parsningsalternativ", + "gdata-parsing/proj-name": "Projektnamn", + "gdata-parsing/create-proj": "Skapa projekt »", + "gdata-parsing/updating-preview": "Uppdatera förhandsgranskning…", + "gdata-parsing/worksheet": "kalkylblad", + "gdata-parsing/option": "Alternativ", + "gdata-parsing/preview-button": "Uppdatera förhandsgranskning", + "gdata-parsing/ignore-first": "Ignorera första", + "gdata-parsing/ignore": "raden(-erna) i början pÃ¥ filen", + "gdata-parsing/parse-next": "Parsa nästa", + "gdata-parsing/parse": "rad(er) som kolumnrubriker", + "gdata-parsing/discard-next": "Släng första", + "gdata-parsing/discard": "rad(er) av data", + "gdata-parsing/limit-next": "Ladda högst", + "gdata-parsing/limit": "rad(er) av data", + "gdata-parsing/store-row": "Spara tomma rader", + "gdata-parsing/store-cell": "Spara tomma celler som null", + "gdata-source/alert-url": "Du mÃ¥ste ange en webbadress (URL) att importera.", + "gdata-source/type": "Typ", + "gdata-source/title": "Titel", + "gdata-source/authors": "Författare", + "gdata-source/updated": "Uppdaterad", + "gdata-exporter/uploading": "Laddar upp…", + "gdata-exporter/upload-error": "Uppladdningsfel: ", + "gdata-exporter/upload-success": "Projektet laddades upp till Google Drive med ID ", + "gdata-exporter/new-spreadsheet": "Ett nytt Google-kalkylblad", + "gdata-exporter/enter-spreadsheet": "Ange ett namn för det nya Google-kalkylbladet", + "gdata-auth/authorize-label": "OpenRefine - godkännande", + "gdata-auth/authorized-label": "Godkännandeprocessen avslutad. Stäng det här fönstret och Ã¥tergÃ¥ till OpenRefine." +} diff --git a/OpenRefine/extensions/gdata/module/macros.vm b/OpenRefine/extensions/gdata/module/macros.vm new file mode 100644 index 000000000..18a83bfce --- /dev/null +++ b/OpenRefine/extensions/gdata/module/macros.vm @@ -0,0 +1,14 @@ +#* + This file contains common velocity macros used in all .vt files. + For Velocity documentation, see: + + http://velocity.apache.org/engine/releases/velocity-1.5/user-guide.html +*# + +#macro( makeAList $list ) +
        + #foreach($item in $list) +
      • $item
      • + #end +
      +#end \ No newline at end of file diff --git a/OpenRefine/extensions/gdata/module/scripts/gdata-extension.js b/OpenRefine/extensions/gdata/module/scripts/gdata-extension.js new file mode 100644 index 000000000..dd332616d --- /dev/null +++ b/OpenRefine/extensions/gdata/module/scripts/gdata-extension.js @@ -0,0 +1,63 @@ +/* + +Copyright 2010, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +var GdataExtension = {}; + +GdataExtension.isAuthorized = function() { + // TODO: Unreliable - just means that we were authorized at one point + return Cookies.get('oauth2_token') != null; +}; + +GdataExtension.showAuthorizationDialog = function(onAuthorized, onNotAuthorized) { + if (window.name) { + var windowName = window.name; + } else { + var windowName = "openrefine" + new Date().getTime(); + window.name = windowName; + } + + var callbackName = "cb" + new Date().getTime(); + var callback = function(evt) { + delete window[callbackName]; + if (GdataExtension.isAuthorized()) { + onAuthorized(); + } else if (onNotAuthorized) { + onNotAuthorized(); + } + window.setTimeout(function() { win.close(); }, 100); + }; + window[callbackName] = callback; + + var url = ModuleWirings['gdata'] + "authorize?winname=" + escape(windowName) + "&cb=" + escape(callbackName); + var win = window.open(url, "openrefinegdataauth", "resizable=1,width=800,height=600"); +}; diff --git a/OpenRefine/extensions/gdata/module/scripts/index/gdata-parsing-panel.html b/OpenRefine/extensions/gdata/module/scripts/index/gdata-parsing-panel.html new file mode 100644 index 000000000..ef5f949f1 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/scripts/index/gdata-parsing-panel.html @@ -0,0 +1,56 @@ +
      + + + + + +
      + +
      + +
      + +
      + +
      + + + + + + + + + + + + + + +
        +
      + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      +
      \ No newline at end of file diff --git a/OpenRefine/extensions/gdata/module/scripts/index/gdata-source-ui.js b/OpenRefine/extensions/gdata/module/scripts/index/gdata-source-ui.js new file mode 100644 index 000000000..76b9caf1b --- /dev/null +++ b/OpenRefine/extensions/gdata/module/scripts/index/gdata-source-ui.js @@ -0,0 +1,197 @@ +/* + +Copyright 2011, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +Refine.GDataSourceUI = function(controller) { + this._controller = controller; +}; + +Refine.GDataSourceUI.prototype.attachUI = function(body) { + this._body = body; + + this._body.html(DOM.loadHTML("gdata", "scripts/index/import-from-gdata-form.html")); + this._elmts = DOM.bind(this._body); + + $('#gdata-title').text($.i18n('gdata-import/title')); + $('#gdata-import').html($.i18n('gdata-import/import-by-url')); + $('#gdata-next').html($.i18n('gdata-import/next->')); + $('#gdata-auth-doc').text($.i18n('gdata-import/auth-doc')); + $('#gdata-please-signin').text($.i18n('gdata-import/please-signin')); + $('#gdata-signin-btn').text($.i18n('gdata-import/sign-in')); + $('#gdata-retrieving').text($.i18n('gdata-import/retrieving')); + $('#gdata-signout').text($.i18n('gdata-import/sign-out')); + $('#gdata-resignin').text($.i18n('gdata-import/sign-in')); + $('#gdata-re-signin-another').text($.i18n('gdata-import/re-sign-in-another')); + + var self = this; + this._body.find('.gdata-signin.button').click(function() { + GdataExtension.showAuthorizationDialog( + function() { + self._listDocuments(); + }, + function() { + self._body.find('.gdata-page').hide(); + self._elmts.signinPage.show(); + } + ); + }); + this._body.find('.gdata-signout.button').click(function() { + $.get("command/gdata/deauthorize" ); + self._body.find('.gdata-page').hide(); + self._elmts.signinPage.show(); + }); + + this._elmts.urlNextButton.click(function(evt) { + var url = $.trim(self._elmts.urlInput[0].value); + if (url.length === 0) { + window.alert($.i18n('gdata-source/alert-url')); + } else { + var doc = {}; + doc.docSelfLink = url; + if (doc.docSelfLink.contains('spreadsheet')) { // TODO: fragile? + doc.type = 'spreadsheet'; + } else { + doc.type = 'table'; + } + self._controller.startImportingDocument(doc); + } + }); + + this._body.find('.gdata-page').hide(); + this._elmts.signinPage.show(); + + if (GdataExtension.isAuthorized()) { + this._listDocuments(); + } +}; + +Refine.GDataSourceUI.prototype.focus = function() { +}; + +Refine.GDataSourceUI.prototype._listDocuments = function() { + this._body.find('.gdata-page').hide(); + this._elmts.progressPage.show(); + + var self = this; + Refine.wrapCSRF(function(token) { + $.post( + "command/core/importing-controller?" + $.param({ + "controller": "gdata/gdata-importing-controller", + "subCommand": "list-documents", + "csrf_token": token + }), + null, + function(o) { + self._renderDocuments(o); + }, + "json" + ); + }); +}; + +Refine.GDataSourceUI.prototype._renderDocuments = function(o) { + var self = this; + + this._elmts.listingContainer.empty(); + + var table = $( + '' + + '' + // starred + '' + + '' + + '' + + '' + + '
      '+$.i18n('gdata-source/type')+''+$.i18n('gdata-source/title')+''+$.i18n('gdata-source/authors')+''+$.i18n('gdata-source/updated')+'
      ' + ).appendTo(this._elmts.listingContainer)[0]; + + var renderDocument = function(doc) { + var tr = table.insertRow(table.rows.length); + + var td = tr.insertCell(tr.cells.length); + if (doc.isStarred) { + $('').attr('src', 'images/star.png').appendTo(td); + } + + td = tr.insertCell(tr.cells.length); + $('').text(doc.type).appendTo(td); + + td = tr.insertCell(tr.cells.length); + $('') + .addClass('gdata-doc-title') + .attr('href', 'javascript:{}') + .text(doc.title) + .appendTo(td) + .click(function(evt) { + self._controller.startImportingDocument(doc); + }); + + $('') + .addClass('gdata-doc-preview') + .attr('href', doc.docLink) + .attr('target', '_blank') + .text('preview') + .appendTo(td); + + td = tr.insertCell(tr.cells.length); + $('') + .addClass('gdata-doc-authors') + .text((doc.authors) ? doc.authors.join(', ') : '') + .appendTo(td); + + td = tr.insertCell(tr.cells.length); + $('') + .addClass('gdata-doc-date') + .text((doc.updated) ? formatRelativeDate(doc.updated) : '') + .attr('title', (doc.updated) ? doc.updated : '') + .appendTo(td); + }; + + if (o.status === 'error') { + // We're probably not logged in, even though we thought we were. Show signin page + this._body.find('.gdata-page').hide(); + this._elmts.signinPage.show(); + } else { + var docs = o.documents; + $.each(docs, function() { + this.updatedDate = (this.updated) ? new Date(this.updated) : null; + this.updatedDateTime = (this.updatedDate) ? this.updatedDate.getTime() : 0; + }); + docs.sort(function(a, b) { return b.updatedDateTime - a.updatedDateTime; }); + + for (var i = 0; i < docs.length; i++) { + renderDocument(docs[i]); + } + + this._body.find('.gdata-page').hide(); + this._elmts.listingPage.show(); + } +}; diff --git a/OpenRefine/extensions/gdata/module/scripts/index/import-from-gdata-form.html b/OpenRefine/extensions/gdata/module/scripts/index/import-from-gdata-form.html new file mode 100644 index 000000000..61e9c1ca8 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/scripts/index/import-from-gdata-form.html @@ -0,0 +1,30 @@ +
      +
      +

      +
      + + + + + +
      +
      + +
      +

      + +
      +

      +
      +
      +

      +
      +
      + + + +
      + +
      +
      +
      \ No newline at end of file diff --git a/OpenRefine/extensions/gdata/module/scripts/index/importing-controller.js b/OpenRefine/extensions/gdata/module/scripts/index/importing-controller.js new file mode 100644 index 000000000..30644a8e8 --- /dev/null +++ b/OpenRefine/extensions/gdata/module/scripts/index/importing-controller.js @@ -0,0 +1,453 @@ +/* + +Copyright 2011, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +//Internationalization init +var lang = navigator.language.split("-")[0] + || navigator.userLanguage.split("-")[0]; +var dictionary = ""; +$.ajax({ + url : "command/core/load-language?", + type : "POST", + async : false, + data : { + module : "gdata", +// lang : lang + }, + success : function(data) { + dictionary = data['dictionary']; + lang = data['lang']; + } +}); +$.i18n().load(dictionary, lang); +// End internationalization + +Refine.GDataImportingController = function(createProjectUI) { + this._createProjectUI = createProjectUI; + + this._parsingPanel = createProjectUI.addCustomPanel(); + + createProjectUI.addSourceSelectionUI({ + label: "Google Data", + id: "gdata-source", + ui: new Refine.GDataSourceUI(this) + }); + + $('#gdata-authorize').text($.i18n('gdata-auth/authorize-label')); + $('#gdata-authorized').text($.i18n('gdata-auth/authorized-label')); +}; +Refine.CreateProjectUI.controllers.push(Refine.GDataImportingController); + +Refine.GDataImportingController.prototype.startImportingDocument = function(doc) { + var dismiss = DialogSystem.showBusy($.i18n('gdata-import/preparing')); + + var self = this; + Refine.postCSRF( + "command/core/create-importing-job", + null, + function(data) { + Refine.wrapCSRF(function(token) { + $.post( + "command/core/importing-controller?" + $.param({ + "controller": "gdata/gdata-importing-controller", + "subCommand": "initialize-parser-ui", + "docUrl": doc.docSelfLink, + "docType": doc.type, + "csrf_token": token + }), + null, + function(data2) { + dismiss(); + + if (data2.status == 'ok') { + self._doc = doc; + self._jobID = data.jobID; + self._options = data2.options; + + self._showParsingPanel(); + } else { + alert(data2.message); + } + }, + "json" + ); + }); + }, + "json" + ); +}; + +Refine.GDataImportingController.prototype.getOptions = function() { + var options = { + docUrl: this._doc.docSelfLink, + docType: this._doc.type, + }; + + var parseIntDefault = function(s, def) { + try { + var n = parseInt(s); + if (!isNaN(n)) { + return n; + } + } catch (e) { + // Ignore + } + return def; + }; + + if (this._doc.type != 'table') { + this._parsingPanelElmts.sheetRecordContainer.find('input').each(function() { + if (this.checked) { + options.sheetUrl = this.getAttribute('sheetUrl'); + options.worksheetIndex = this.getAttribute('worksheetIndex'); + } + }); + + if (this._parsingPanelElmts.ignoreCheckbox[0].checked) { + options.ignoreLines = parseIntDefault(this._parsingPanelElmts.ignoreInput[0].value, -1); + } else { + options.ignoreLines = -1; + } + if (this._parsingPanelElmts.headerLinesCheckbox[0].checked) { + options.headerLines = parseIntDefault(this._parsingPanelElmts.headerLinesInput[0].value, 0); + } else { + options.headerLines = 0; + } + } + + if (this._parsingPanelElmts.skipCheckbox[0].checked) { + options.skipDataLines = parseIntDefault(this._parsingPanelElmts.skipInput[0].value, 0); + } else { + options.skipDataLines = 0; + } + if (this._parsingPanelElmts.limitCheckbox[0].checked) { + options.limit = parseIntDefault(this._parsingPanelElmts.limitInput[0].value, -1); + } else { + options.limit = -1; + } + options.storeBlankRows = this._parsingPanelElmts.storeBlankRowsCheckbox[0].checked; + options.storeBlankCellsAsNulls = this._parsingPanelElmts.storeBlankCellsAsNullsCheckbox[0].checked; + + options.disableAutoPreview = this._parsingPanelElmts.disableAutoPreviewCheckbox[0].checked; + + return options; +}; + +Refine.GDataImportingController.prototype._showParsingPanel = function() { + var self = this; + + this._parsingPanel.unbind().empty().html( + DOM.loadHTML("gdata", 'scripts/index/gdata-parsing-panel.html')); + this._parsingPanelElmts = DOM.bind(this._parsingPanel); + + this._parsingPanelElmts.gdata_worksheet.html($.i18n('gdata-parsing/worksheet')); + this._parsingPanelElmts.gdata_ignore_first.html($.i18n('gdata-parsing/ignore-first')); + this._parsingPanelElmts.gdata_ignore.html($.i18n('gdata-parsing/ignore')); + this._parsingPanelElmts.gdata_parse_next.html($.i18n('gdata-parsing/parse-next')); + this._parsingPanelElmts.gdata_parse.html($.i18n('gdata-parsing/parse')); + this._parsingPanelElmts.startOverButton.html($.i18n('gdata-parsing/start-over')); + this._parsingPanelElmts.gdata_conf_pars.html($.i18n('gdata-parsing/conf-pars')); + this._parsingPanelElmts.gdata_proj_name.html($.i18n('gdata-parsing/proj-name')); + this._parsingPanelElmts.createProjectButton.html($.i18n('gdata-parsing/create-proj')); + this._parsingPanelElmts.gdata_options.html($.i18n('gdata-parsing/option')); + this._parsingPanelElmts.gdata_disable_auto_preview.text($.i18n('gdata-parsing/disable-auto-preview')); + this._parsingPanelElmts.previewButton.html($.i18n('gdata-parsing/preview-button')); + this._parsingPanelElmts.gdata_updating.html($.i18n('gdata-parsing/updating-preview')); + this._parsingPanelElmts.gdata_discard_next.html($.i18n('gdata-parsing/discard-next')); + this._parsingPanelElmts.gdata_discard.html($.i18n('gdata-parsing/discard')); + this._parsingPanelElmts.gdata_limit_next.html($.i18n('gdata-parsing/limit-next')); + this._parsingPanelElmts.gdata_limit.html($.i18n('gdata-parsing/limit')); + this._parsingPanelElmts.gdata_store_row.html($.i18n('gdata-parsing/store-row')); + this._parsingPanelElmts.gdata_store_cell.html($.i18n('gdata-parsing/store-cell')); + + if (this._parsingPanelResizer) { + $(window).unbind('resize', this._parsingPanelResizer); + } + + this._parsingPanelResizer = function() { + var elmts = self._parsingPanelElmts; + var width = self._parsingPanel.width(); + var height = self._parsingPanel.height(); + var headerHeight = elmts.wizardHeader.outerHeight(true); + var controlPanelHeight = 250; + + elmts.dataPanel + .css("left", "0px") + .css("top", headerHeight + "px") + .css("width", (width - DOM.getHPaddings(elmts.dataPanel)) + "px") + .css("height", (height - headerHeight - controlPanelHeight - DOM.getVPaddings(elmts.dataPanel)) + "px"); + elmts.progressPanel + .css("left", "0px") + .css("top", headerHeight + "px") + .css("width", (width - DOM.getHPaddings(elmts.progressPanel)) + "px") + .css("height", (height - headerHeight - controlPanelHeight - DOM.getVPaddings(elmts.progressPanel)) + "px"); + + elmts.controlPanel + .css("left", "0px") + .css("top", (height - controlPanelHeight) + "px") + .css("width", (width - DOM.getHPaddings(elmts.controlPanel)) + "px") + .css("height", (controlPanelHeight - DOM.getVPaddings(elmts.controlPanel)) + "px"); + }; + $(window).resize(this._parsingPanelResizer); + this._parsingPanelResizer(); + + this._parsingPanelElmts.startOverButton.click(function() { + // explicitly cancel the import job + Refine.CreateProjectUI.cancelImportingJob(self._jobID); + + delete self._doc; + delete self._jobID; + delete self._options; + + self._createProjectUI.showSourceSelectionPanel(); + }); + this._parsingPanelElmts.createProjectButton.click(function() { self._createProject(); }); + this._parsingPanelElmts.previewButton.click(function() { self._updatePreview(); }); + + this._parsingPanelElmts.projectNameInput[0].value = this._doc.title; + + if (this._doc.type != 'table') { + var sheetTable = this._parsingPanelElmts.sheetRecordContainer[0]; + $.each(this._options.worksheets, function(i, v) { + var id = 'gdata_worksheet-' + Math.round(Math.random() * 1000000); + + var tr = sheetTable.insertRow(sheetTable.rows.length); + var td0 = $(tr.insertCell(0)).attr('width', '1%'); + var checkbox = $('') + .attr('id', id) + .attr('type', 'radio') + .attr('name', 'gdata-importing-parsing-worksheet') + .attr('sheetUrl', this.link) + .attr('worksheetIndex', this.worksheetIndex) + .appendTo(td0); + if (i === 0) { + checkbox.prop("checked", true); + } + + $('
    • ' + + '' + savedConnection.connectionName + '' + + '