{"id":16176117,"url":"https://github.com/piotr-kalanski/spark-local","last_synced_at":"2026-01-30T12:33:10.297Z","repository":{"id":57722100,"uuid":"89135324","full_name":"piotr-kalanski/spark-local","owner":"piotr-kalanski","description":"API enabling switching between Spark execution engine and local fast implementation based on Scala collections.","archived":false,"fork":false,"pushed_at":"2017-07-06T19:10:55.000Z","size":3701,"stargazers_count":2,"open_issues_count":31,"forks_count":0,"subscribers_count":1,"default_branch":"development","last_synced_at":"2025-06-10T12:09:29.577Z","etag":null,"topics":["scala","spark","unit-testing"],"latest_commit_sha":null,"homepage":null,"language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/piotr-kalanski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-04-23T10:57:43.000Z","updated_at":"2018-07-16T11:00:48.000Z","dependencies_parsed_at":"2022-08-29T22:32:04.308Z","dependency_job_id":null,"html_url":"https://github.com/piotr-kalanski/spark-local","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/piotr-kalanski/spark-local","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotr-kalanski%2Fspark-local","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotr-kalanski%2Fspark-local/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotr-kalanski%2Fspark-local/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotr-kalanski%2Fspark-local/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/piotr-kalanski","download_url":"https://codeload.github.com/piotr-kalanski/spark-local/tar.gz/refs/heads/development","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotr-kalanski%2Fspark-local/sbom","scorecard":{"id":734721,"data":{"date":"2025-08-11","repo":{"name":"github.com/piotr-kalanski/spark-local","commit":"7154cf5759c0bfa9fd7b7f41473091e2f2ce4a1a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/9 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during GetBranch(master): error during branchesHandler.query: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-22T15:26:53.747Z","repository_id":57722100,"created_at":"2025-08-22T15:26:53.747Z","updated_at":"2025-08-22T15:26:53.747Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28912911,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T12:13:43.263Z","status":"ssl_error","status_checked_at":"2026-01-30T12:13:22.389Z","response_time":66,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["scala","spark","unit-testing"],"created_at":"2024-10-10T04:47:44.396Z","updated_at":"2026-01-30T12:33:10.276Z","avatar_url":"https://github.com/piotr-kalanski.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# spark-local\n\nAPI enabling switching between Spark execution engine and local implementation based on Scala collections.\n\n[![Build Status](https://api.travis-ci.org/piotr-kalanski/spark-local.png?branch=development)](https://api.travis-ci.org/piotr-kalanski/spark-local.png?branch=development)\n[![codecov.io](http://codecov.io/github/piotr-kalanski/spark-local/coverage.svg?branch=development)](http://codecov.io/github/piotr-kalanski/spark-local/coverage.svg?branch=development)\n[\u003cimg src=\"https://img.shields.io/maven-central/v/com.github.piotr-kalanski/spark-local_2.11.svg?label=latest%20release\"/\u003e](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22spark-local_2.11%22)\n[![Stories in Ready](https://badge.waffle.io/piotr-kalanski/spark-local.png?label=Ready)](https://waffle.io/piotr-kalanski/spark-local)\n[![License](http://img.shields.io/:license-Apache%202-red.svg)](http://www.apache.org/licenses/LICENSE-2.0.txt)\n\n# Table of contents\n\n- [Goals](#goals)\n- [Getting started](#getting-started)\n- [Examples](#examples)\n- [IO operations](#io-operations)\n  - [Supported formats](#supported-formats)\n  - [Data model versioning](#data-model-versioning)\n  - [Column mapping](#column-mapping)\n- [Aggregations](#aggregations)\n- [Supported Spark versions](#supported-spark-versions)\n- [Supported Spark operations](doc/SupportedOperations.md)\n- [Benchmarks](benchmarks/Benchmarks.md)\n- [Contributing](CONTRIBUTING.md)\n\n# Goals\n\n- Speed up unit testing for Spark applications\n- Enable switching between Spark execution engine and Scala collections depending on use case, especially size of data without changing implementation\n\n# Getting started\n\n## Spark 2.1.1\n\nInclude dependency:\n\n```scala\n\"com.github.piotr-kalanski\" % \"spark-local_2.1.1_2.11\" % \"0.6.0\"\n```\n\nor\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.piotr-kalanski\u003c/groupId\u003e\n    \u003cartifactId\u003espark-local_2.1.1_2.11\u003c/artifactId\u003e\n    \u003cversion\u003e0.6.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Spark 2.1.0\n\nInclude dependency:\n\n```scala\n\"com.github.piotr-kalanski\" % \"spark-local_2.1.0_2.11\" % \"0.6.0\"\n```\n\nor\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.piotr-kalanski\u003c/groupId\u003e\n    \u003cartifactId\u003espark-local_2.1.0_2.11\u003c/artifactId\u003e\n    \u003cversion\u003e0.6.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n# Examples\n\n## Creating Session\n\nEntry point for library is session object which is similar to SparkSession object from Apache Spark.\n\nProcess of creating Session is also similar to Apache Spark.\n\nWhen creating Session object you can choose between different execution engines. Currently supported:\n\n- Spark - wrapper on Spark, which can be used at production data volumes\n- ScalaEager - implementation based on Scala collection with eager transformations, which makes it fast for unit testing\n- ScalaLazy - implementation based on Scala collection with lazy transformations, dedicated for working with small/mid size data\n- ScalaParallel - implementation based on Scala parallel collection with eager transformations\n- ScalaParallelLazy - implementation based on Scala parallel collection with lazy transformations\n\n```scala\nimport com.datawizards.sparklocal.session.ExecutionEngine.ExecutionEngine\nimport com.datawizards.sparklocal.session.{ExecutionEngine, SparkSessionAPI}\n\n// just change this value to start using different execution engine\nval engine = ExecutionEngine.ScalaEager\n\nval session = SparkSessionAPI\n      .builder(engine)\n      .master(\"local\")\n      .getOrCreate()\n\nval ds = session.read[Person](CSVDataStore(file))\n```\n\n## RDD API\n\n```scala\nimport com.datawizards.sparklocal.rdd.RDDAPI\nimport org.apache.spark.sql.SparkSession\n\nobject ExampleRDD1 {\n\n  def main(args: Array[String]): Unit = {\n    val spark = SparkSession.builder().master(\"local\").getOrCreate()\n\n    val data = Seq(1,2,3)\n    val rdd = spark.sparkContext.parallelize(data)\n\n    assertEquals(\n      calculateSum(RDDAPI(data)),\n      calculateSum(RDDAPI(rdd))\n    )\n\n    assertEquals(\n      calculateSumOfSquares(RDDAPI(data)),\n      calculateSumOfSquares(RDDAPI(rdd))\n    )\n\n  }\n\n  def assertEquals[T](r1:T, r2:T): Unit = {\n    println(r1)\n    assert(r1 == r2)\n  }\n\n  def calculateSum(ds: RDDAPI[Int]): Int = ds.reduce(_ + _)\n  def calculateSumOfSquares(ds: RDDAPI[Int]): Int = ds.map(x=\u003ex*x).reduce(_ + _)\n\n}\n```\n\n## Dataset API\n\n### Simple example\n\n```scala\nimport com.datawizards.sparklocal.dataset.DataSetAPI\nimport org.apache.spark.sql.SparkSession\n\nobject ExampleDataset1 {\n\n  def main(args: Array[String]): Unit = {\n    val spark = SparkSession.builder().master(\"local\").getOrCreate()\n    import spark.implicits._\n\n    val data = Seq(1,2,3)\n    val ds = data.toDS()\n\n    assertEquals(\n      calculateSum(DataSetAPI(data)),\n      calculateSum(DataSetAPI(ds))\n    )\n\n    assertEquals(\n      calculateSumOfSquares(DataSetAPI(data)),\n      calculateSumOfSquares(DataSetAPI(ds))\n    )\n\n  }\n\n  def assertEquals[T](r1:T, r2:T): Unit = {\n    println(r1)\n    assert(r1 == r2)\n  }\n\n  def calculateSum(ds: DataSetAPI[Int]): Int = ds.reduce(_ + _)\n  def calculateSumOfSquares(ds: DataSetAPI[Int]): Int = ds.map(x=\u003ex*x).reduce(_ + _)\n\n}\n```\n\n### Example report\n\n```scala\ncase class Person(id: Int, name: String, gender: String)\ncase class WorkExperience(personId: Int, year: Int, title: String)\ncase class HRReport(year: Int, title: String, gender: String, count: Int)\n\nobject ExampleHRReport {\n\n  def main(args: Array[String]): Unit = {\n    val spark = SparkSession.builder().master(\"local\").getOrCreate()\n    import spark.implicits._\n\n    val people = SampleData.people\n    val peopleDs = people.toDS()\n    val experience = SampleData.experience\n    val experienceDs = experience.toDS()\n\n\n    calculateReport(DataSetAPI(people), DataSetAPI(experience))\n    calculateReport(DataSetAPI(peopleDs), DataSetAPI(experienceDs))\n  }\n\n  def calculateReport(people: DataSetAPI[Person], workExperience: DataSetAPI[WorkExperience]): DataSetAPI[HRReport] = {\n    workExperience\n      .join(people)(_.personId, _.id)\n      .groupByKey(wp =\u003e (wp._1.year, wp._1.title, wp._2.gender))\n      .mapGroups{case ((year, title, gender), vals) =\u003e HRReport(year, title, gender, vals.size)}\n  }\n\n}\n```\n\n# IO operations\n\nLibrary provides dedicated API for input/output operations with implementation for Spark and Scala collections.\n\n## Supported formats\n\nSupported formats:\n- CSV\n- JSON\n- Parquet\n- Avro\n- Hive\n- JDBC\n  - H2\n  - MySQL\n- Elasticsearch\n\n### CSV\n\n#### Read CSV file\n\n```scala\nval reader: Reader = ReaderScalaImpl // Scala implementation\n//val reader: Reader = ReaderSparkImpl // Spark implementation\n\nreader.read[Person](\n    CSVDataStore(\n        path = \"people.csv\",\n        delimiter = ';',\n        header = false,\n        columns = Seq(\"name\",\"age\")\n    )\n)\n```\n\n#### Write to CSV file\n\n```scala\nds.write(CSVDataStore(file), SaveMode.Overwrite)\n```\n\n### JSON\n\n#### Read JSON file\n\n```scala\nreader.read[Person](JsonDataStore(\"people.json\"))\n```\n\n#### Write to JSON file\n\n```scala\nds.write(JsonDataStore(\"people.json\"), SaveMode.Overwrite)\n```\n\n### Avro\n\nCurrent implementation produces different binary files for Spark and Scala.\nSpark by default compress files with snappy and spark-local implementation is based on: https://github.com/sksamuel/avro4s, which saves data without compression.\n\n#### Read Avro file\n\n```scala\nreader.read[Person](AvroDataStore(\"people.avro\"))\n```\n\n#### Write to Avro file\n\n```scala\nds.write(AvroDataStore(\"people.avro\"), SaveMode.Overwrite)\n```\n\n### Parquet\n\n#### Read Parquet file\n\n```scala\nreader.read[Person](ParquetDataStore(\"people.parquet\"))\n```\n\n#### Write to Parquet file\n\n```scala\nds.write(ParquetDataStore(\"people.parquet\"), SaveMode.Overwrite)\n```\n\n### Hive\n\n#### Read Hive table\n\n```scala\nreader.read[Person](HiveDataStore(\"db\", \"table\"))\n```\n\n#### Write to Hive table\n\n```scala\nds.write(HiveDataStore(\"db\", \"table\"), SaveMode.Overwrite)\n```\n\n### JDBC\n\n#### Read JDBC table\n\n```scala\n\nval database = \"public\"\nval table = \"people\"\nval properties = new java.util.Properties()\nreader.read[Person](H2DataStore(connectionString, database, table, properties))\n```\n\n#### Write to JDBC table\n\n```scala\nds.write(H2DataStore(connectionString, database, table, properties), SaveMode.Append)\n```\n\n### Elasticsearch\n\n#### Write to Elasticsearch index\n\n```scala\nval indexName = \"people\"\nval typeName = \"person\"\nds.write(ElasticsearchSimpleIndexDataStore(\"localhost\", indexName, typeName), SaveMode.Append)\n```\n\n## Data model versioning\n\nLibrary supports reading data using old and new version of data model.\n\nReading with old version of data model is straightforward, just existing fields will be read.\nOn other hand, when reading with new version of data model, new columns should be `Option` type and value `None` is assigned to those fields.\n\n**Example**\n\n```scala\nimport com.datawizards.sparklocal.datastore.CSVDataStore\nimport com.datawizards.sparklocal.session.{ExecutionEngine, SparkSessionAPI}\nimport org.apache.spark.sql.SaveMode\n\ncase class Person(name: String, age: Int)\ncase class PersonV2(name: String, age: Int, title: Option[String])\ncase class PersonV3(name: String, age: Int, title: Option[String], salary: Option[Long])\n\nval session = SparkSessionAPI\n      .builder(ExecutionEngine.ScalaEager)\n      .master(\"local\")\n      .getOrCreate()\n\nimport session.implicits._\n\nval peopleV2 = session.createDataset(Seq(\n    PersonV2(\"p1\", 10, Some(\"Mr\")),\n    PersonV2(\"p2\", 20, Some(\"Ms\")),\n    PersonV2(\"p3\", 30, None),\n    PersonV2(\"p4\", 40, Some(\"Mr\"))\n))\n\nval dataStore = CSVDataStore(\"people_v2.csv\")\npeopleV2.write(dataStore, SaveMode.Overwrite)\n\n// Read old version:\nval peopleV1 = session.read[Person](dataStore)\n\n// Read new version:\nval peopleV3 = session.read[PersonV3](dataStore)\n\npeopleV1.show()\npeopleV3.show()\n```\n\n```\n+----+---+\n|name|age|\n+----+---+\n|p1  |10 |\n|p2  |20 |\n|p3  |30 |\n|p4  |40 |\n+----+---+\n\n+----+---+-----+------+\n|name|age|title|salary|\n+----+---+-----+------+\n|p1  |10 |Mr   |      |\n|p2  |20 |Ms   |      |\n|p3  |30 |     |      |\n|p4  |40 |Mr   |      |\n+----+---+-----+------+\n```\n\n## Column mapping\n\nLibrary supports changing name of fields when writing and reading data.\n\nMapping is provided using `column` annotation from project: https://github.com/piotr-kalanski/data-model-generator.\n\n**Example**\n\n```scala\nimport com.datawizards.dmg.annotations.column\nimport com.datawizards.sparklocal.dataset.io.ModelDialects\nimport com.datawizards.sparklocal.datastore.JsonDataStore\nimport com.datawizards.sparklocal.session.{ExecutionEngine, SparkSessionAPI}\nimport org.apache.spark.sql.SaveMode\n\ncase class PersonWithMapping(\n    @column(\"personName\", dialect = ModelDialects.JSON)\n    name: String,\n    @column(\"personAge\", dialect = ModelDialects.JSON)\n    age: Int\n)\n\nval session = SparkSessionAPI\n      .builder(ExecutionEngine.ScalaEager)\n      .master(\"local\")\n      .getOrCreate()\n\nimport session.implicits._\n\nval people = session.createDataset(Seq(\n    PersonWithMapping(\"p1\", 10),\n    PersonWithMapping(\"p2\", 20),\n    PersonWithMapping(\"p3\", 30),\n    PersonWithMapping(\"p4\", 40)\n))\n\nval dataStore = JsonDataStore(\"people_mapping.json\")\npeople.write(dataStore, SaveMode.Overwrite)\n\n```\n\nName of fields in JSON file are consistent with column names provided in annotations:\n\n```json\n{\"personName\":\"p1\",\"personAge\":10}\n{\"personName\":\"p2\",\"personAge\":20}\n{\"personName\":\"p3\",\"personAge\":30}\n{\"personName\":\"p4\",\"personAge\":40}\n```\n\nReading data:\n```scala\nval people2 = session.read[PersonWithMapping](dataStore)\npeople2.show()\n```\n\nNames of columns are the same as case class fields:\n```\n+----+---+\n|name|age|\n+----+---+\n|p1  |10 |\n|p2  |20 |\n|p3  |30 |\n|p4  |40 |\n+----+---+\n```\n\n# Aggregations\n\nLibrary provides custom type-safe API for aggregations.\n\nExample operations:\n\n```scala\nimport com.datawizards.sparklocal.dataset.agg._\n\nds\n    .groupByKey(_.name)\n    .agg(sum(_.age), count(), mean(_.age), max(_.age))\n```\n\n# Supported Spark versions\n\n|spark-local|Spark version|\n|-----------|-------------|\n|0.7        |2.1.1\u003cbr/\u003e2.1.0  |\n|0.6        |2.1.1\u003cbr/\u003e2.1.0  |\n|0.5        |2.1.0        |\n|0.4        |2.1.0        |\n|0.3        |2.1.0        |\n|0.2        |2.1.0        |\n|0.1        |2.1.0        |\n\n# Bugs\n\nPlease report any bugs to [spark-local Github issue tracker](https://github.com/piotr-kalanski/spark-local/issues).\n\n# Continuous Integration\n\n[Build History](https://travis-ci.org/piotr-kalanski/spark-local/builds)\n\n# Contact\n\npiotr.kalanski@gmail.com\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiotr-kalanski%2Fspark-local","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpiotr-kalanski%2Fspark-local","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiotr-kalanski%2Fspark-local/lists"}