From 626ceb3690431831a8b733e78c708768b0d98219 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:08:42 +0100 Subject: [PATCH 01/50] Fix import --- tests/test_parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_parser.rs b/tests/test_parser.rs index fa6d39e..5084729 100644 --- a/tests/test_parser.rs +++ b/tests/test_parser.rs @@ -1,4 +1,4 @@ -use analyzer::Parser; +use codeprints_analyzer::Parser; use serde_json; use std::fs; From 975b7fbb7362e97a5a7e37f079b6b94f09aef821 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:09:00 +0100 Subject: [PATCH 02/50] Add subcommand for merge --- src/bin/analyzer/main.rs | 40 +++++++++++++++++++++++++++---------- src/bin/analyzer/options.rs | 37 ++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/bin/analyzer/main.rs b/src/bin/analyzer/main.rs index 0dcd288..a740879 100644 --- a/src/bin/analyzer/main.rs +++ b/src/bin/analyzer/main.rs @@ -16,21 +16,39 @@ use std::fs; use structopt::StructOpt; mod options; -use options::Opt; +use options::Command; const OUTPUT_FILE: &'static str = "codeprints.json"; fn main() -> Result<()> { - let opt = Opt::from_args(); + let opt = Command::from_args(); - print!("Analyzing commits in current repository..."); - let input = count_commits(opt.before, opt.after, opt.author, opt.committer) - .context("Cannot read project history. Make sure there is no typo in the command")?; - let mut parser = Parser::new(input); - let timeline = parser.parse()?; - let output = serde_json::to_string_pretty(&timeline)?; - fs::write(OUTPUT_FILE, output)?; - println!("done!"); - println!("Output file: {}", OUTPUT_FILE); + match opt { + Command::Run { + before, + after, + author, + committer, + } => { + print!("Analyzing commits in current repository..."); + let input = count_commits(before, after, author, committer).context( + "Cannot read project history. Make sure there is no typo in the command", + )?; + let mut parser = Parser::new(input); + let timeline = parser.parse()?; + let output = serde_json::to_string_pretty(&timeline)?; + fs::write(OUTPUT_FILE, output)?; + println!("done!"); + println!("Output file: {}", OUTPUT_FILE); + } + Command::Merge {} => { + // Find all `codeprints*.json` files in the current directory + // using glob. + // Read each one into memory + // Merge the results together + // Write a `codeprints_merged.json` file + unimplemented!(); + } + }; Ok(()) } diff --git a/src/bin/analyzer/options.rs b/src/bin/analyzer/options.rs index 0605b3c..9300ffd 100644 --- a/src/bin/analyzer/options.rs +++ b/src/bin/analyzer/options.rs @@ -2,24 +2,27 @@ use structopt::StructOpt; #[derive(StructOpt, Debug)] #[structopt(name = "codeprints-analyzer")] -pub struct Opt { - /// Limit the commits output to ones with author header lines - /// that match the specified pattern. - /// This is passed verbatim to git. See `git log --help` for more info. - #[structopt(short, long)] - pub author: Vec, +pub enum Command { + Run { + /// Limit the commits output to ones with author header lines + /// that match the specified pattern. + /// This is passed verbatim to git. See `git log --help` for more info. + #[structopt(short, long)] + author: Vec, - /// Limit the commits output to ones with committer header lines - /// that match the specified pattern. - /// This is passed verbatim to git. See `git log --help` for more info. - #[structopt(short, long)] - pub committer: Vec, + /// Limit the commits output to ones with committer header lines + /// that match the specified pattern. + /// This is passed verbatim to git. See `git log --help` for more info. + #[structopt(short, long)] + committer: Vec, - // Show commits older than a specific date. - #[structopt(alias = "until", long)] - pub before: Option, + // Show commits older than a specific date. + #[structopt(alias = "until", long)] + before: Option, - // Show commits more recent than a specific date. - #[structopt(alias = "since", long)] - pub after: Option, + // Show commits more recent than a specific date. + #[structopt(alias = "since", long)] + after: Option, + }, + Merge {}, } From 214a2f9b8591406fc3556e6e58c9079153e3309f Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:09:38 +0100 Subject: [PATCH 03/50] impl Default for Year (generating empty timelines) --- src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types.rs b/src/types.rs index 70e3df2..e137791 100644 --- a/src/types.rs +++ b/src/types.rs @@ -7,7 +7,7 @@ pub struct Day { pub date: NaiveDate, } -#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Year { pub year: String, From 5ad51fce81fba565a19576b675be3748a455dbe0 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:10:39 +0100 Subject: [PATCH 04/50] Split up parser into ParseState and core Parser This decouples the data representation from the parsing process, making the internal data format usable for other use-cases, such as merging timelines --- src/parser.rs | 242 ++++++++++++++++++++++++++++---------------------- 1 file changed, 137 insertions(+), 105 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index d92be0b..8aff260 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,96 +2,16 @@ use crate::quartiles::quartiles; use crate::types::{Contribution, Contributions, Range, Timeline, Year}; use anyhow::{Context, Result}; use chrono::prelude::*; -use std::collections::HashMap; +use std::{collections::HashMap, convert::TryFrom}; -/// A parser that converts git log output -/// into the JSON format understood by the -/// API of codeprints.dev. -#[derive(Debug)] -pub struct Parser { - input: String, +/// The internal state of the parser +#[derive(Debug, Default)] +pub struct ParseState { years_map: HashMap, days: HashMap, } -impl Parser { - /// Create a new parser that analyzes the given input - pub fn new(input: String) -> Self { - let years_map = HashMap::new(); - let days = HashMap::new(); - - Parser { - input, - years_map, - days, - } - } - - // Each cell in the timeline is shaded with one of 5 possible colors. These - // colors correspond to the quartiles of the normal distribution over the range - // [0, max(v)] where v is the sum of issues opened, pull requests proposed and - // commits authored per day. - // https://bd808.com/blog/2013/04/17/hacking-github-contributions-calendar/ - // https://github.community/t/the-color-coding-of-contribution-graph-is-showing-wrong-information/18572 - fn get_intensity(quartiles: &[usize], commits: usize) -> usize { - for (index, quartile) in quartiles.iter().enumerate() { - if commits < *quartile { - return index - 1; - } - } - quartiles.len() - 1 - } - - fn map_color(intensity: usize) -> String { - match intensity { - 1 => "var(--color-calendar-graph-day-L1-bg)", - 2 => "var(--color-calendar-graph-day-L2-bg)", - 3 => "var(--color-calendar-graph-day-L3-bg)", - 4 => "var(--color-calendar-graph-day-L4-bg)", - _ => "var(--color-calendar-graph-day-bg)", - } - .to_string() - } - - /// Backfill missing days with zero commits - fn backfill(year: i32, days: &mut HashMap) { - for d in NaiveDate::from_ymd(year, 1, 1).iter_days() { - if d.year() != year { - break; - } - days.entry(d).or_insert(0); - } - } - - fn create_contributions( - &self, - days: &HashMap, - quartiles: &[usize], - ) -> Vec { - let mut contributions = Vec::new(); - for (date, commits) in days { - let intensity = Self::get_intensity(&quartiles, *commits); - let color = Self::map_color(intensity); - - contributions.push(Contribution { - date: date.format("%Y-%m-%d").to_string(), - count: *commits, - color, - intensity, - }); - } - contributions - } - - fn parse_date(&self, line: &str) -> Result> { - if line.trim().is_empty() { - // Empty lines are allowed, but skipped - return Ok(None); - } - let date: NaiveDate = line.parse().context(format!("Invalid date {}", line))?; - Ok(Some(date)) - } - +impl ParseState { /// Add a single day to the map of years fn update_years(&mut self, date: NaiveDate) { let y = date.year(); @@ -116,34 +36,113 @@ impl Parser { *self.days.entry(date).or_insert(0) += 1; } - /// Execute the parsing step - pub fn parse(&mut self) -> Result { - let input = self.input.clone(); - for line in input.lines() { - let day = self.parse_date(&line)?; - if let Some(d) = day { - self.update_days(d); - self.update_years(d); + fn parse_date(&self, line: &str) -> Result> { + if line.trim().is_empty() { + // Empty lines are allowed, but skipped + return Ok(None); + } + let date: NaiveDate = line.parse().context(format!("Invalid date {}", line))?; + Ok(Some(date)) + } +} + +impl TryFrom for ParseState { + type Error = anyhow::Error; + + fn try_from(timeline: Timeline) -> Result { + let mut state = ParseState::default(); + for contribution in timeline.contributions { + let date = contribution.date; + let date = state.parse_date(&date)?; + let count = contribution.count; + + if let Some(date) = date { + // Kinda ineffective to call these update functions in a loop + for _ in 0..count { + state.update_years(date); + state.update_days(date); + } } } + Ok(state) + } +} + +/// Backfill missing days with zero commits +fn backfill(year: i32, days: &mut HashMap) { + for d in NaiveDate::from_ymd(year, 1, 1).iter_days() { + if d.year() != year { + break; + } + days.entry(d).or_insert(0); + } +} + +// Each cell in the timeline is shaded with one of 5 possible colors. These +// colors correspond to the quartiles of the normal distribution over the range +// [0, max(v)] where v is the sum of issues opened, pull requests proposed and +// commits authored per day. +// https://bd808.com/blog/2013/04/17/hacking-github-contributions-calendar/ +// https://github.community/t/the-color-coding-of-contribution-graph-is-showing-wrong-information/18572 +fn get_intensity(quartiles: &[usize], commits: usize) -> usize { + for (index, quartile) in quartiles.iter().enumerate() { + if commits < *quartile { + return index - 1; + } + } + quartiles.len() - 1 +} + +fn map_color(intensity: usize) -> String { + match intensity { + 1 => "var(--color-calendar-graph-day-L1-bg)", + 2 => "var(--color-calendar-graph-day-L2-bg)", + 3 => "var(--color-calendar-graph-day-L3-bg)", + 4 => "var(--color-calendar-graph-day-L4-bg)", + _ => "var(--color-calendar-graph-day-bg)", + } + .to_string() +} + +fn create_contributions( + days: &HashMap, + quartiles: &[usize], +) -> Vec { + let mut contributions = Vec::new(); + for (date, commits) in days { + let intensity = get_intensity(&quartiles, *commits); + let color = map_color(intensity); + + contributions.push(Contribution { + date: date.format("%Y-%m-%d").to_string(), + count: *commits, + color, + intensity, + }); + } + contributions +} - let mut years: Vec = self.years_map.values().cloned().collect(); +impl TryFrom<&ParseState> for Timeline { + type Error = anyhow::Error; + fn try_from(state: &ParseState) -> Result { + let mut years: Vec = state.years_map.values().cloned().collect(); years.sort(); years.reverse(); let mut contributions = Contributions::new(); for year in &years { - let mut year_contribs: HashMap = self + let mut year_contribs: HashMap = state .days .clone() .into_iter() .filter(|(date, _commits)| date.year().to_string() == year.year) .collect(); - Self::backfill(year.year.parse::()?, &mut year_contribs); + backfill(year.year.parse::()?, &mut year_contribs); let commits: Vec = year_contribs.values().cloned().collect(); let quartiles = quartiles(&commits)?; - let mut contribs = self.create_contributions(&year_contribs, &quartiles); + let mut contribs = create_contributions(&year_contribs, &quartiles); contributions.append(&mut contribs); } contributions.sort(); @@ -155,8 +154,41 @@ impl Parser { } } +/// A parser that converts git log output +/// into the JSON format understood by the +/// API of codeprints.dev. +#[derive(Debug, Default)] +pub struct Parser { + input: String, + state: ParseState, +} + +impl Parser { + /// Create a new parser that analyzes the given input + pub fn new(input: String) -> Self { + Parser { + input, + ..Default::default() + } + } + + /// Execute the parsing step + pub fn parse(&mut self) -> Result { + let input = self.input.clone(); + for line in input.lines() { + let day = self.state.parse_date(&line)?; + if let Some(d) = day { + self.state.update_days(d); + self.state.update_years(d); + } + } + + Ok(Timeline::try_from(&self.state)?) + } +} + #[cfg(test)] -mod test_super { +mod test { use super::*; @@ -188,12 +220,12 @@ mod test_super { #[test] fn test_intensities() { let quartiles = [0, 1, 11, 22, 32]; - assert_eq!(0, Parser::get_intensity(&quartiles, 0)); - assert_eq!(1, Parser::get_intensity(&quartiles, 1)); - assert_eq!(1, Parser::get_intensity(&quartiles, 10)); - assert_eq!(2, Parser::get_intensity(&quartiles, 18)); - assert_eq!(3, Parser::get_intensity(&quartiles, 22)); - assert_eq!(4, Parser::get_intensity(&quartiles, 32)); - assert_eq!(4, Parser::get_intensity(&quartiles, 100)); + assert_eq!(0, get_intensity(&quartiles, 0)); + assert_eq!(1, get_intensity(&quartiles, 1)); + assert_eq!(1, get_intensity(&quartiles, 10)); + assert_eq!(2, get_intensity(&quartiles, 18)); + assert_eq!(3, get_intensity(&quartiles, 22)); + assert_eq!(4, get_intensity(&quartiles, 32)); + assert_eq!(4, get_intensity(&quartiles, 100)); } } From 1fa6d45e29211cbe8bf785cc2d77ae36f981a829 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:11:03 +0100 Subject: [PATCH 05/50] Work on merge setup --- src/lib.rs | 2 ++ src/merge.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 src/merge.rs diff --git a/src/lib.rs b/src/lib.rs index c1f346c..1c97056 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,9 +13,11 @@ )] mod git; +mod merge; mod parser; mod quartiles; mod types; pub use crate::git::count_commits; +pub use crate::merge::Merger; pub use crate::parser::Parser; diff --git a/src/merge.rs b/src/merge.rs new file mode 100644 index 0000000..48b16fb --- /dev/null +++ b/src/merge.rs @@ -0,0 +1,82 @@ +use std::convert::TryFrom; + +use crate::{parser::ParseState, types::Timeline}; +use anyhow::Result; + +/// Merger merges multiple timelines into one +#[derive(Debug)] +pub struct Merger { + state: ParseState, +} + +impl Merger { + /// Create a new merger with a clean state (no timeline merged) + pub fn new() -> Self { + let state = ParseState::default(); + Merger { state } + } + + fn merge_single(&mut self, single: ParseState) -> Result<()> { + self.state = single; + Ok(()) + } + + /// Merge multiple timelines together into one + /// This is helpful when analyzing multiple repositories and trying to combine + /// the individual results. + pub fn merge(&mut self, timelines: &[Timeline]) -> Result { + for timeline in timelines { + let single = ParseState::try_from(timeline.clone())?; + self.merge_single(single)?; + } + Ok(Timeline::try_from(&self.state)?) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::types::{Contribution, Range, Year}; + + #[test] + fn test_merge_none() { + let mut merger = Merger::new(); + assert_eq!(merger.merge(&[]).unwrap(), Timeline::default()); + } + + #[test] + fn test_merge_one() { + let mut timeline = Timeline::default(); + + let year = "2020".into(); + let total = 1234; + let range = Range { + start: "2020-02-01".into(), + end: "2020-03-02".into(), + }; + + let year1 = Year { year, total, range }; + let years = vec![year1]; + timeline.years = years; + + let contributions = vec![ + Contribution { + date: "2020-01-01".into(), + count: 1000, + color: "".into(), + intensity: 4, + }, + Contribution { + date: "2020-01-02".into(), + count: 234, + color: "".into(), + intensity: 4, + }, + ]; + + timeline.contributions = contributions; + + let mut merger = Merger::new(); + assert_eq!(merger.merge(&[timeline.clone()]).unwrap(), timeline); + } +} From c48f9bb2a96927836bc8f9e87e01938809128852 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:11:23 +0100 Subject: [PATCH 06/50] Execute `run` by default if there are no additional arguments --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index ef8f113..a446d52 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,3 +15,5 @@ RUN apt-get update \ COPY --from=builder /analyzer/target/release/codeprints-analyzer /usr/local/bin/codeprints-analyzer WORKDIR /repo ENTRYPOINT [ "codeprints-analyzer" ] +# The standard command parses the commits of a repository +CMD ["run"] From 38a27da1861a1e7c28a88c9d1904fc2bb4cb2841 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:11:27 +0100 Subject: [PATCH 07/50] Update docs --- README.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 323e766..3d4a3a3 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ codeprints-analyzer You can set the start- and end-date of the output. ``` -docker run -v `pwd`:/repo codeprints/analyzer --after "2020-12-24" --before "2021-02-10" +docker run -v `pwd`:/repo codeprints/analyzer run --after "2020-12-24" --before "2021-02-10" ``` The syntax is exactly the same that `git` also uses. @@ -53,7 +53,7 @@ If you work in a bigger team, you might want to filter the contributions by author. Here is how: ``` -docker run -v `pwd`:/repo codeprints/analyzer --author "Matthias" --author "Octocat" +docker run -v `pwd`:/repo codeprints/analyzer run --author "Matthias" --author "Octocat" ``` To get a list of all author names, run `git shortlog --summary --numbered --email`. @@ -61,6 +61,19 @@ To get a list of all author names, run `git shortlog --summary --numbered --emai (You can also filter by committers. The difference is subtle, but in contrast to authors, these are the contributors who pushed/committed a patch to the repository.) +## Merging multiple codeprints output files + +Do you have multiple repositories that you want to analyze? +No problem! Just run the tool in every repository folder. +After that, copy the files into a single folder and run the following command: + +``` +docker run -v `pwd`:/repo codeprints/analyzer merge +``` + +This will merge all codeprints\_\*.json files in the `repo` directory into one file. +(It will accumulate all contribution counts for each day.) + ## More options To get an exhaustive list of options, run From 1695eee1602b9cd1d1b92598229a53f5b6ee6bb4 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:33:14 +0100 Subject: [PATCH 08/50] Work on merger --- src/merge.rs | 19 +++++++++++++++---- src/parser.rs | 6 +++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/merge.rs b/src/merge.rs index 48b16fb..58cf223 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -16,8 +16,20 @@ impl Merger { Merger { state } } - fn merge_single(&mut self, single: ParseState) -> Result<()> { - self.state = single; + fn merge_timeline(&mut self, timeline: &Timeline) -> Result<()> { + for contribution in &timeline.contributions { + let date = contribution.date.clone(); + let date = self.state.parse_date(&date)?; + let count = contribution.count; + + if let Some(date) = date { + // Kinda ineffective to call these update functions in a loop + for _ in 0..count { + self.state.update_years(date); + self.state.update_days(date); + } + } + } Ok(()) } @@ -26,8 +38,7 @@ impl Merger { /// the individual results. pub fn merge(&mut self, timelines: &[Timeline]) -> Result { for timeline in timelines { - let single = ParseState::try_from(timeline.clone())?; - self.merge_single(single)?; + self.merge_timeline(timeline)? } Ok(Timeline::try_from(&self.state)?) } diff --git a/src/parser.rs b/src/parser.rs index 8aff260..0b0822f 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -13,7 +13,7 @@ pub struct ParseState { impl ParseState { /// Add a single day to the map of years - fn update_years(&mut self, date: NaiveDate) { + pub fn update_years(&mut self, date: NaiveDate) { let y = date.year(); let mut year = self.years_map.entry(y).or_insert(Year { year: y.to_string(), @@ -32,11 +32,11 @@ impl ParseState { } /// Add a single day to the map of days - fn update_days(&mut self, date: NaiveDate) { + pub fn update_days(&mut self, date: NaiveDate) { *self.days.entry(date).or_insert(0) += 1; } - fn parse_date(&self, line: &str) -> Result> { + pub fn parse_date(&self, line: &str) -> Result> { if line.trim().is_empty() { // Empty lines are allowed, but skipped return Ok(None); From 598df77f731cabbc3fd16753d04796ebcddf73ed Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:33:57 +0100 Subject: [PATCH 09/50] Remove unused TryFrom --- src/parser.rs | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 0b0822f..ee90fbb 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -46,28 +46,6 @@ impl ParseState { } } -impl TryFrom for ParseState { - type Error = anyhow::Error; - - fn try_from(timeline: Timeline) -> Result { - let mut state = ParseState::default(); - for contribution in timeline.contributions { - let date = contribution.date; - let date = state.parse_date(&date)?; - let count = contribution.count; - - if let Some(date) = date { - // Kinda ineffective to call these update functions in a loop - for _ in 0..count { - state.update_years(date); - state.update_days(date); - } - } - } - Ok(state) - } -} - /// Backfill missing days with zero commits fn backfill(year: i32, days: &mut HashMap) { for d in NaiveDate::from_ymd(year, 1, 1).iter_days() { From 0777aa3da558cb3bbe6cdf44a18fb822583a37c9 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Sat, 20 Feb 2021 00:15:29 +0100 Subject: [PATCH 10/50] Show full year --- src/parser.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index ee90fbb..80961ce 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -18,17 +18,22 @@ impl ParseState { let mut year = self.years_map.entry(y).or_insert(Year { year: y.to_string(), total: 0, - range: Range::default(), + // range: Range::default, + // Always show full year + range: Range { + start: format!("{}-01-01", y), + end: format!("{}-12-31", y), + }, }); year.total += 1; - let date = date.format("%Y-%m-%d").to_string(); - if year.range.start.is_empty() || date < year.range.start { - year.range.start = date.clone(); - } - if year.range.end.is_empty() || date > year.range.end { - year.range.end = date - } + // let date = date.format("%Y-%m-%d").to_string(); + // if year.range.start.is_empty() || date < year.range.start { + // year.range.start = date.clone(); + // } + // if year.range.end.is_empty() || date > year.range.end { + // year.range.end = date + // } } /// Add a single day to the map of days From 1b3610f3227100576ebd5f83186679aa4907ae3f Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 3 Mar 2021 15:06:51 +0100 Subject: [PATCH 11/50] handle start and end date in output --- src/bin/analyzer/main.rs | 8 ++++- src/git.rs | 17 ++++++++-- src/merge.rs | 4 +-- src/parser.rs | 68 +++++++++++++++++++++++++++++++--------- 4 files changed, 76 insertions(+), 21 deletions(-) diff --git a/src/bin/analyzer/main.rs b/src/bin/analyzer/main.rs index a740879..eb0e945 100644 --- a/src/bin/analyzer/main.rs +++ b/src/bin/analyzer/main.rs @@ -31,10 +31,16 @@ fn main() -> Result<()> { committer, } => { print!("Analyzing commits in current repository..."); - let input = count_commits(before, after, author, committer).context( + let input = count_commits(&before, &after, author, committer).context( "Cannot read project history. Make sure there is no typo in the command", )?; let mut parser = Parser::new(input); + if let Some(before) = before { + parser.set_before(before)?; + } + if let Some(after) = after { + parser.set_after(after)?; + } let timeline = parser.parse()?; let output = serde_json::to_string_pretty(&timeline)?; fs::write(OUTPUT_FILE, output)?; diff --git a/src/git.rs b/src/git.rs index 6a7f92c..3beec19 100644 --- a/src/git.rs +++ b/src/git.rs @@ -1,10 +1,11 @@ -use anyhow::Result; +use anyhow::{Context, Result}; +use chrono::NaiveDate; use duct::cmd; /// Get the count of commits for each day from the git logs pub fn count_commits( - before: Option, - after: Option, + before: &Option, + after: &Option, authors: Vec, committers: Vec, ) -> Result { @@ -28,3 +29,13 @@ pub fn count_commits( let commits = cmd("git", &args).read()?; Ok(commits) } + +// Parse a date from the git log +pub fn parse_date(line: &str) -> Result> { + if line.trim().is_empty() { + // Empty lines are allowed, but skipped + return Ok(None); + } + let date: NaiveDate = line.parse().context(format!("Invalid date {}", line))?; + Ok(Some(date)) +} diff --git a/src/merge.rs b/src/merge.rs index 58cf223..fbe2b30 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -1,6 +1,6 @@ use std::convert::TryFrom; -use crate::{parser::ParseState, types::Timeline}; +use crate::{git, parser::ParseState, types::Timeline}; use anyhow::Result; /// Merger merges multiple timelines into one @@ -19,7 +19,7 @@ impl Merger { fn merge_timeline(&mut self, timeline: &Timeline) -> Result<()> { for contribution in &timeline.contributions { let date = contribution.date.clone(); - let date = self.state.parse_date(&date)?; + let date = git::parse_date(&date)?; let count = contribution.count; if let Some(date) = date { diff --git a/src/parser.rs b/src/parser.rs index 80961ce..81d5bd5 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,28 +1,38 @@ -use crate::quartiles::quartiles; use crate::types::{Contribution, Contributions, Range, Timeline, Year}; -use anyhow::{Context, Result}; +use crate::{git, quartiles::quartiles}; +use anyhow::Result; use chrono::prelude::*; -use std::{collections::HashMap, convert::TryFrom}; +use std::{cmp::{max, min}, collections::HashMap, convert::TryFrom}; /// The internal state of the parser #[derive(Debug, Default)] pub struct ParseState { years_map: HashMap, days: HashMap, + before: Option, + after: Option, } impl ParseState { /// Add a single day to the map of years pub fn update_years(&mut self, date: NaiveDate) { let y = date.year(); + let start = match self.before { + Some(before) => max(before, date), + None => date, + }; + let end = match self.after { + Some(after) => min(after, date), + None => date, + }; let mut year = self.years_map.entry(y).or_insert(Year { year: y.to_string(), total: 0, // range: Range::default, // Always show full year range: Range { - start: format!("{}-01-01", y), - end: format!("{}-12-31", y), + start: start.format("%y-%m-%d").to_string(), + end: end.format("%y-%m-%d").to_string(), }, }); year.total += 1; @@ -40,15 +50,6 @@ impl ParseState { pub fn update_days(&mut self, date: NaiveDate) { *self.days.entry(date).or_insert(0) += 1; } - - pub fn parse_date(&self, line: &str) -> Result> { - if line.trim().is_empty() { - // Empty lines are allowed, but skipped - return Ok(None); - } - let date: NaiveDate = line.parse().context(format!("Invalid date {}", line))?; - Ok(Some(date)) - } } /// Backfill missing days with zero commits @@ -155,12 +156,49 @@ impl Parser { } } + /// Set the minimum date of the timeline. Commits older than the given date + /// will not be counted and won't be in the final output + pub fn set_before(&mut self, before: String) -> Result<&mut Self> { + let before = git::parse_date(&before)?; + if let Some(before) = before { + self.state.before = Some(before); + } + Ok(self) + } + + /// Set the maximum date of the timeline. Commits newer than the given date + /// will not be counted and won't be in the final output + pub fn set_after(&mut self, after: String) -> Result<&mut Self> { + let after = git::parse_date(&after)?; + if let Some(after) = after { + self.state.after = Some(after); + } + Ok(self) + } + + fn outside_date_range(&self, day: NaiveDate) -> bool { + if let Some(before) = self.state.before { + if day < before { + return true; + } + } + if let Some(after) = self.state.after { + if day > after { + return true; + } + } + false + } + /// Execute the parsing step pub fn parse(&mut self) -> Result { let input = self.input.clone(); for line in input.lines() { - let day = self.state.parse_date(&line)?; + let day = git::parse_date(&line)?; if let Some(d) = day { + if self.outside_date_range(d) { + continue; + } self.state.update_days(d); self.state.update_years(d); } From 6149ac91acdc6c9140664873f58c95d46b748afa Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Mon, 8 Mar 2021 21:57:02 +0100 Subject: [PATCH 12/50] Fix test --- src/merge.rs | 12 ++++++-- src/parser.rs | 82 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 64 insertions(+), 30 deletions(-) diff --git a/src/merge.rs b/src/merge.rs index fbe2b30..49d7caa 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -62,8 +62,8 @@ mod test { let year = "2020".into(); let total = 1234; let range = Range { - start: "2020-02-01".into(), - end: "2020-03-02".into(), + start: "2020-01-01".into(), + end: "2020-01-02".into(), }; let year1 = Year { year, total, range }; @@ -88,6 +88,12 @@ mod test { timeline.contributions = contributions; let mut merger = Merger::new(); - assert_eq!(merger.merge(&[timeline.clone()]).unwrap(), timeline); + let merged = merger.merge(&[timeline.clone()]).unwrap(); + assert_eq!(merged.years.len(), 1); + let year = &merged.years[0]; + assert_eq!(year.year, "2020"); + assert_eq!(year.total, 1234); + assert_eq!(year.range.start, "2020-01-01"); + assert_eq!(year.range.end, "2020-01-02"); } } diff --git a/src/parser.rs b/src/parser.rs index 81d5bd5..bea3b03 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,8 +1,12 @@ use crate::types::{Contribution, Contributions, Range, Timeline, Year}; use crate::{git, quartiles::quartiles}; -use anyhow::Result; +use anyhow::{Context, Result}; use chrono::prelude::*; -use std::{cmp::{max, min}, collections::HashMap, convert::TryFrom}; +use std::{ + cmp::{max, min}, + collections::HashMap, + convert::TryFrom, +}; /// The internal state of the parser #[derive(Debug, Default)] @@ -17,33 +21,23 @@ impl ParseState { /// Add a single day to the map of years pub fn update_years(&mut self, date: NaiveDate) { let y = date.year(); - let start = match self.before { - Some(before) => max(before, date), - None => date, - }; - let end = match self.after { - Some(after) => min(after, date), - None => date, - }; + let date_str = date.format("%Y-%m-%d").to_string(); + let mut year = self.years_map.entry(y).or_insert(Year { year: y.to_string(), total: 0, // range: Range::default, // Always show full year range: Range { - start: start.format("%y-%m-%d").to_string(), - end: end.format("%y-%m-%d").to_string(), + start: date_str.clone(), + end: date_str.clone(), }, }); - year.total += 1; - // let date = date.format("%Y-%m-%d").to_string(); - // if year.range.start.is_empty() || date < year.range.start { - // year.range.start = date.clone(); - // } - // if year.range.end.is_empty() || date > year.range.end { - // year.range.end = date - // } + year.range.start = min(year.range.start.clone(), date_str.clone()); + year.range.end = max(year.range.end.clone(), date_str); + + year.total += 1; } /// Add a single day to the map of days @@ -53,13 +47,19 @@ impl ParseState { } /// Backfill missing days with zero commits -fn backfill(year: i32, days: &mut HashMap) { +fn backfill(year: i32, days: &mut HashMap) -> Result<()> { + let last_day = days + .keys() + .max_by_key(|key| *key) + .cloned() + .context("cannot get last day for backfilling")?; for d in NaiveDate::from_ymd(year, 1, 1).iter_days() { - if d.year() != year { + if d > last_day { break; } days.entry(d).or_insert(0); } + Ok(()) } // Each cell in the timeline is shaded with one of 5 possible colors. These @@ -122,7 +122,7 @@ impl TryFrom<&ParseState> for Timeline { .into_iter() .filter(|(date, _commits)| date.year().to_string() == year.year) .collect(); - backfill(year.year.parse::()?, &mut year_contribs); + backfill(year.year.parse::()?, &mut year_contribs)?; let commits: Vec = year_contribs.values().cloned().collect(); let quartiles = quartiles(&commits)?; @@ -176,14 +176,14 @@ impl Parser { Ok(self) } - fn outside_date_range(&self, day: NaiveDate) -> bool { + fn out_of_range(&self, day: NaiveDate) -> bool { if let Some(before) = self.state.before { - if day < before { + if day >= before { return true; } } if let Some(after) = self.state.after { - if day > after { + if day <= after { return true; } } @@ -196,7 +196,7 @@ impl Parser { for line in input.lines() { let day = git::parse_date(&line)?; if let Some(d) = day { - if self.outside_date_range(d) { + if self.out_of_range(d) { continue; } self.state.update_days(d); @@ -238,6 +238,34 @@ mod test { assert_eq!(parser.parse().unwrap().years, expected); } + #[test] + fn test_parse_years_range() { + let input = r###" + 2020-04-15 + 2020-04-15 + 2020-04-16 + 2020-04-17 + 2020-04-17 + 2020-04-17 + 2020-04-17 + 2020-04-18 + "###; + + let range = Range { + start: "2020-04-16".to_string(), + end: "2020-04-17".to_string(), + }; + let expected = vec![Year { + year: "2020".to_string(), + total: 5, + range: range, + }]; + let mut parser = Parser::new(input.to_string()); + parser.set_before("2020-04-18".into()).unwrap(); + parser.set_after("2020-04-15".into()).unwrap(); + assert_eq!(parser.parse().unwrap().years, expected); + } + #[test] fn test_intensities() { let quartiles = [0, 1, 11, 22, 32]; From 24d6f577124f191ffa7b6d493614828f596299ad Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Mon, 8 Mar 2021 22:22:10 +0100 Subject: [PATCH 13/50] work on merge --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/bin/analyzer/main.rs | 36 ++++++++++++++++++++++++++---------- src/lib.rs | 1 + src/merge.rs | 9 ++++++++- src/types.rs | 1 + 6 files changed, 44 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec05e8a..a8bcd00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,6 +75,7 @@ dependencies = [ "anyhow", "chrono", "duct", + "glob", "quantiles", "serde", "serde_json", @@ -93,6 +94,12 @@ dependencies = [ "shared_child", ] +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + [[package]] name = "heck" version = "0.3.2" diff --git a/Cargo.toml b/Cargo.toml index cd245d9..b23e57e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,3 +29,4 @@ serde_json = "1.0.62" chrono = "0.4.19" quantiles = "0.7.1" structopt = "0.3.21" +glob = "0.3.0" diff --git a/src/bin/analyzer/main.rs b/src/bin/analyzer/main.rs index eb0e945..01c1cdc 100644 --- a/src/bin/analyzer/main.rs +++ b/src/bin/analyzer/main.rs @@ -10,15 +10,23 @@ )] use anyhow::{Context, Result}; -use codeprints_analyzer::count_commits; use codeprints_analyzer::Parser; +use codeprints_analyzer::Timeline; +use codeprints_analyzer::{count_commits, Merger}; +use glob::glob; use std::fs; use structopt::StructOpt; mod options; use options::Command; -const OUTPUT_FILE: &'static str = "codeprints.json"; +fn write(timeline: &Timeline, output_file: &str) -> Result<()> { + let output = serde_json::to_string_pretty(&timeline)?; + fs::write(output_file, output)?; + println!("done!"); + println!("Output file: {}", output_file); + Ok(()) +} fn main() -> Result<()> { let opt = Command::from_args(); @@ -42,18 +50,26 @@ fn main() -> Result<()> { parser.set_after(after)?; } let timeline = parser.parse()?; - let output = serde_json::to_string_pretty(&timeline)?; - fs::write(OUTPUT_FILE, output)?; - println!("done!"); - println!("Output file: {}", OUTPUT_FILE); + + write(&timeline, "codeprints.json")?; } Command::Merge {} => { // Find all `codeprints*.json` files in the current directory // using glob. - // Read each one into memory - // Merge the results together - // Write a `codeprints_merged.json` file - unimplemented!(); + let mut merger = Merger::new(); + for entry in glob("codeprints*.json")? { + match entry { + Ok(path) => { + println!("Merging {}", path.display()); + let input = fs::read_to_string(path)?; + let mut parser = Parser::new(input); + let timeline = parser.parse()?; + merger.merge_timeline(&timeline)?; + } + Err(e) => println!("{:?}", e), + } + } + write(&merger.timeline()?, "codeprints_merged.json")?; } }; Ok(()) diff --git a/src/lib.rs b/src/lib.rs index 1c97056..a27ca0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,3 +21,4 @@ mod types; pub use crate::git::count_commits; pub use crate::merge::Merger; pub use crate::parser::Parser; +pub use crate::types::Timeline as Timeline; diff --git a/src/merge.rs b/src/merge.rs index 49d7caa..f007d3f 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -16,7 +16,8 @@ impl Merger { Merger { state } } - fn merge_timeline(&mut self, timeline: &Timeline) -> Result<()> { + /// Merge a single timeline + pub fn merge_timeline(&mut self, timeline: &Timeline) -> Result<()> { for contribution in &timeline.contributions { let date = contribution.date.clone(); let date = git::parse_date(&date)?; @@ -42,8 +43,14 @@ impl Merger { } Ok(Timeline::try_from(&self.state)?) } + + /// Return the merged timeline of all inputs + pub fn timeline(&self) -> Result { + Ok(Timeline::try_from(&self.state)?) + } } + #[cfg(test)] mod test { use super::*; diff --git a/src/types.rs b/src/types.rs index e137791..cbb3bcb 100644 --- a/src/types.rs +++ b/src/types.rs @@ -18,6 +18,7 @@ pub struct Year { pub type Years = Vec; pub type Contributions = Vec; +/// A timeline represents a codeprints.json file's contents #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Timeline { From 6cf9f12d53f116566159f61ed237f270292ea435 Mon Sep 17 00:00:00 2001 From: Wolfgang Gassler Date: Mon, 8 Mar 2021 23:57:05 +0100 Subject: [PATCH 14/50] WIP: merge multiple timeslines - adds a test for multiple timelines (is failing) - adds a parameter update methods of a year --- src/merge.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++++----- src/parser.rs | 12 +++++------ 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/merge.rs b/src/merge.rs index f007d3f..9d1bb4d 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -18,17 +18,15 @@ impl Merger { /// Merge a single timeline pub fn merge_timeline(&mut self, timeline: &Timeline) -> Result<()> { + ///TODO: make sure that all days are filled with 0 between start and end for contribution in &timeline.contributions { let date = contribution.date.clone(); let date = git::parse_date(&date)?; let count = contribution.count; if let Some(date) = date { - // Kinda ineffective to call these update functions in a loop - for _ in 0..count { - self.state.update_years(date); - self.state.update_days(date); - } + self.state.update_years(date, count); + self.state.update_days(date, count); } } Ok(()) @@ -103,4 +101,51 @@ mod test { assert_eq!(year.range.start, "2020-01-01"); assert_eq!(year.range.end, "2020-01-02"); } + + #[test] + fn test_merge_multiple() { + let mut timeline1 = Timeline::default(); + let mut timeline2 = Timeline::default(); + + let range1 = Range { + start: "2020-01-01".into(), + end: "2020-01-02".into(), + }; + let range2 = Range { + start: "2020-01-01".into(), + end: "2020-01-03".into(), + }; + + let year2 = Year { year: "2020".into(), total: 0, range: range2 }; + let year1 = Year { year: "2020".into(), total: 123, range: range1 }; + timeline1.years = vec![year1]; + timeline2.years = vec![year2]; + + let contributions = vec![ + Contribution { + date: "2020-01-01".into(), + count: 1000, + color: "".into(), + intensity: 4, + }, + Contribution { + date: "2020-01-02".into(), + count: 234, + color: "".into(), + intensity: 4, + }, + ]; + + timeline1.contributions = contributions.clone(); + timeline2.contributions = contributions.clone(); + + let mut merger = Merger::new(); + let merged = merger.merge(&[timeline1.clone(),timeline2.clone()]).unwrap(); + assert_eq!(merged.years.len(), 1); + let year = &merged.years[0]; + assert_eq!(year.year, "2020"); + assert_eq!(year.total, 2468); + assert_eq!(year.range.start, "2020-01-01"); + assert_eq!(year.range.end, "2020-01-03"); + } } diff --git a/src/parser.rs b/src/parser.rs index bea3b03..db84fca 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -19,7 +19,7 @@ pub struct ParseState { impl ParseState { /// Add a single day to the map of years - pub fn update_years(&mut self, date: NaiveDate) { + pub fn update_years(&mut self, date: NaiveDate, contributions_to_add: usize) { let y = date.year(); let date_str = date.format("%Y-%m-%d").to_string(); @@ -37,12 +37,12 @@ impl ParseState { year.range.start = min(year.range.start.clone(), date_str.clone()); year.range.end = max(year.range.end.clone(), date_str); - year.total += 1; + year.total += contributions_to_add; } /// Add a single day to the map of days - pub fn update_days(&mut self, date: NaiveDate) { - *self.days.entry(date).or_insert(0) += 1; + pub fn update_days(&mut self, date: NaiveDate, contributions_to_add: usize) { + *self.days.entry(date).or_insert(0) += contributions_to_add; } } @@ -199,8 +199,8 @@ impl Parser { if self.out_of_range(d) { continue; } - self.state.update_days(d); - self.state.update_years(d); + self.state.update_days(d, 1); + self.state.update_years(d, 1); } } From babfe9211f76aa14cac4d726d0fcfeaee739ce43 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 01:30:09 +0100 Subject: [PATCH 15/50] fix merge 2 test --- src/merge.rs | 51 +++++++++++++++++++++++++++++++++++++++++---------- src/types.rs | 2 ++ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/merge.rs b/src/merge.rs index 9d1bb4d..3e43448 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -18,7 +18,7 @@ impl Merger { /// Merge a single timeline pub fn merge_timeline(&mut self, timeline: &Timeline) -> Result<()> { - ///TODO: make sure that all days are filled with 0 between start and end + // TODO: make sure that all days are filled with 0 between start and end for contribution in &timeline.contributions { let date = contribution.date.clone(); let date = git::parse_date(&date)?; @@ -48,7 +48,6 @@ impl Merger { } } - #[cfg(test)] mod test { use super::*; @@ -116,12 +115,21 @@ mod test { end: "2020-01-03".into(), }; - let year2 = Year { year: "2020".into(), total: 0, range: range2 }; - let year1 = Year { year: "2020".into(), total: 123, range: range1 }; + let year1 = Year { + year: "2020".into(), + total: 1234, + range: range1, + }; timeline1.years = vec![year1]; + + let year2 = Year { + year: "2020".into(), + total: 6, + range: range2, + }; timeline2.years = vec![year2]; - let contributions = vec![ + let contributions1 = vec![ Contribution { date: "2020-01-01".into(), count: 1000, @@ -136,16 +144,39 @@ mod test { }, ]; - timeline1.contributions = contributions.clone(); - timeline2.contributions = contributions.clone(); + let contributions2 = vec![ + Contribution { + date: "2020-01-01".into(), + count: 0, + color: "".into(), + intensity: 0, + }, + Contribution { + date: "2020-01-02".into(), + count: 5, + color: "".into(), + intensity: 4, + }, + Contribution { + date: "2020-01-03".into(), + count: 1, + color: "".into(), + intensity: 1, + }, + ]; + + timeline1.contributions = contributions1.clone(); + timeline2.contributions = contributions2.clone(); let mut merger = Merger::new(); - let merged = merger.merge(&[timeline1.clone(),timeline2.clone()]).unwrap(); + let merged = merger + .merge(&[timeline1.clone(), timeline2.clone()]) + .unwrap(); assert_eq!(merged.years.len(), 1); let year = &merged.years[0]; assert_eq!(year.year, "2020"); - assert_eq!(year.total, 2468); + assert_eq!(year.total, 1240); assert_eq!(year.range.start, "2020-01-01"); assert_eq!(year.range.end, "2020-01-03"); - } + } } diff --git a/src/types.rs b/src/types.rs index cbb3bcb..9e3a4e8 100644 --- a/src/types.rs +++ b/src/types.rs @@ -22,7 +22,9 @@ pub type Contributions = Vec; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Timeline { + /// Years belonging to the timeline pub years: Years, + /// Contributions belonging to the timeline pub contributions: Contributions, } From 2085384dfefa46398424ddcff8697fb0b9b092df Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 01:37:25 +0100 Subject: [PATCH 16/50] Fix clippy warnings --- src/merge.rs | 6 +++--- src/parser.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/merge.rs b/src/merge.rs index 3e43448..c56abdf 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -4,7 +4,7 @@ use crate::{git, parser::ParseState, types::Timeline}; use anyhow::Result; /// Merger merges multiple timelines into one -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Merger { state: ParseState, } @@ -39,12 +39,12 @@ impl Merger { for timeline in timelines { self.merge_timeline(timeline)? } - Ok(Timeline::try_from(&self.state)?) + Timeline::try_from(&self.state) } /// Return the merged timeline of all inputs pub fn timeline(&self) -> Result { - Ok(Timeline::try_from(&self.state)?) + Timeline::try_from(&self.state) } } diff --git a/src/parser.rs b/src/parser.rs index db84fca..e82f903 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -204,7 +204,7 @@ impl Parser { } } - Ok(Timeline::try_from(&self.state)?) + Timeline::try_from(&self.state) } } From 1443239eca4ae483be07641789d78f196ea1a6b9 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 01:45:18 +0100 Subject: [PATCH 17/50] Add hash to timeline --- src/bin/analyzer/main.rs | 8 +++++--- src/git.rs | 8 +++++++- src/lib.rs | 7 ++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/bin/analyzer/main.rs b/src/bin/analyzer/main.rs index 01c1cdc..88cd0c7 100644 --- a/src/bin/analyzer/main.rs +++ b/src/bin/analyzer/main.rs @@ -10,9 +10,10 @@ )] use anyhow::{Context, Result}; +use codeprints_analyzer::git; +use codeprints_analyzer::Merger; use codeprints_analyzer::Parser; use codeprints_analyzer::Timeline; -use codeprints_analyzer::{count_commits, Merger}; use glob::glob; use std::fs; use structopt::StructOpt; @@ -39,7 +40,7 @@ fn main() -> Result<()> { committer, } => { print!("Analyzing commits in current repository..."); - let input = count_commits(&before, &after, author, committer).context( + let input = git::count_commits(&before, &after, author, committer).context( "Cannot read project history. Make sure there is no typo in the command", )?; let mut parser = Parser::new(input); @@ -51,7 +52,8 @@ fn main() -> Result<()> { } let timeline = parser.parse()?; - write(&timeline, "codeprints.json")?; + let sha = git::sha()?; + write(&timeline, &format!("codeprints_{}.json", sha))?; } Command::Merge {} => { // Find all `codeprints*.json` files in the current directory diff --git a/src/git.rs b/src/git.rs index 3beec19..4953046 100644 --- a/src/git.rs +++ b/src/git.rs @@ -30,7 +30,7 @@ pub fn count_commits( Ok(commits) } -// Parse a date from the git log +/// Parse a date from the git log pub fn parse_date(line: &str) -> Result> { if line.trim().is_empty() { // Empty lines are allowed, but skipped @@ -39,3 +39,9 @@ pub fn parse_date(line: &str) -> Result> { let date: NaiveDate = line.parse().context(format!("Invalid date {}", line))?; Ok(Some(date)) } + +/// Get the current git commit sha +pub fn sha() -> Result { + let sha = cmd("git", &["rev-parse", "--short", "HEAD"]).read()?; + Ok(sha) +} diff --git a/src/lib.rs b/src/lib.rs index a27ca0d..bf65370 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,13 +12,14 @@ unused_qualifications )] -mod git; +/// Git helper functions +pub mod git; + mod merge; mod parser; mod quartiles; mod types; -pub use crate::git::count_commits; pub use crate::merge::Merger; pub use crate::parser::Parser; -pub use crate::types::Timeline as Timeline; +pub use crate::types::Timeline; From d01be81f92c37ef6739f0cff0254b910b43374e4 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 02:06:34 +0100 Subject: [PATCH 18/50] fix lints --- src/parser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index e82f903..4900418 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -232,7 +232,7 @@ mod test { let expected = vec![Year { year: "2020".to_string(), total: 7, - range: range, + range, }]; let mut parser = Parser::new(input.to_string()); assert_eq!(parser.parse().unwrap().years, expected); @@ -258,7 +258,7 @@ mod test { let expected = vec![Year { year: "2020".to_string(), total: 5, - range: range, + range, }]; let mut parser = Parser::new(input.to_string()); parser.set_before("2020-04-18".into()).unwrap(); From a48ee27ccdec37d56da1568be4c8939c604353a1 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 02:11:07 +0100 Subject: [PATCH 19/50] Less clones --- src/merge.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/merge.rs b/src/merge.rs index c56abdf..9580ec2 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -92,7 +92,7 @@ mod test { timeline.contributions = contributions; let mut merger = Merger::new(); - let merged = merger.merge(&[timeline.clone()]).unwrap(); + let merged = merger.merge(&[timeline]).unwrap(); assert_eq!(merged.years.len(), 1); let year = &merged.years[0]; assert_eq!(year.year, "2020"); @@ -165,13 +165,11 @@ mod test { }, ]; - timeline1.contributions = contributions1.clone(); - timeline2.contributions = contributions2.clone(); + timeline1.contributions = contributions1; + timeline2.contributions = contributions2; let mut merger = Merger::new(); - let merged = merger - .merge(&[timeline1.clone(), timeline2.clone()]) - .unwrap(); + let merged = merger.merge(&[timeline1, timeline2]).unwrap(); assert_eq!(merged.years.len(), 1); let year = &merged.years[0]; assert_eq!(year.year, "2020"); From ee203c18ed2fd6244fa5e0307c593dd3813a3088 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 02:13:47 +0100 Subject: [PATCH 20/50] Remove unused import --- tests/test_parser.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_parser.rs b/tests/test_parser.rs index 5084729..c8502a7 100644 --- a/tests/test_parser.rs +++ b/tests/test_parser.rs @@ -1,5 +1,4 @@ use codeprints_analyzer::Parser; -use serde_json; use std::fs; fn ignore_whitespace(s: &str) -> String { From fa390bc64f596d78f834b8afd60d9b878e39f58b Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 02:21:14 +0100 Subject: [PATCH 21/50] fix merge call --- src/bin/analyzer/main.rs | 3 +-- src/git.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bin/analyzer/main.rs b/src/bin/analyzer/main.rs index 88cd0c7..740ee52 100644 --- a/src/bin/analyzer/main.rs +++ b/src/bin/analyzer/main.rs @@ -64,8 +64,7 @@ fn main() -> Result<()> { Ok(path) => { println!("Merging {}", path.display()); let input = fs::read_to_string(path)?; - let mut parser = Parser::new(input); - let timeline = parser.parse()?; + let timeline: Timeline = serde_json::from_str(&input)?; merger.merge_timeline(&timeline)?; } Err(e) => println!("{:?}", e), diff --git a/src/git.rs b/src/git.rs index 4953046..d02070f 100644 --- a/src/git.rs +++ b/src/git.rs @@ -36,7 +36,7 @@ pub fn parse_date(line: &str) -> Result> { // Empty lines are allowed, but skipped return Ok(None); } - let date: NaiveDate = line.parse().context(format!("Invalid date {}", line))?; + let date: NaiveDate = line.parse().context(format!("Invalid date: {}", line))?; Ok(Some(date)) } From 2a553a26d688e88603398c122074c099358c5238 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:08:42 +0100 Subject: [PATCH 22/50] Fix import --- tests/test_parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_parser.rs b/tests/test_parser.rs index fa6d39e..5084729 100644 --- a/tests/test_parser.rs +++ b/tests/test_parser.rs @@ -1,4 +1,4 @@ -use analyzer::Parser; +use codeprints_analyzer::Parser; use serde_json; use std::fs; From 250b815d6e14d7263250a41c17b92e63c15d0f7b Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:09:00 +0100 Subject: [PATCH 23/50] Add subcommand for merge --- src/bin/analyzer/main.rs | 40 +++++++++++++++++++++++++++---------- src/bin/analyzer/options.rs | 37 ++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/bin/analyzer/main.rs b/src/bin/analyzer/main.rs index 0dcd288..a740879 100644 --- a/src/bin/analyzer/main.rs +++ b/src/bin/analyzer/main.rs @@ -16,21 +16,39 @@ use std::fs; use structopt::StructOpt; mod options; -use options::Opt; +use options::Command; const OUTPUT_FILE: &'static str = "codeprints.json"; fn main() -> Result<()> { - let opt = Opt::from_args(); + let opt = Command::from_args(); - print!("Analyzing commits in current repository..."); - let input = count_commits(opt.before, opt.after, opt.author, opt.committer) - .context("Cannot read project history. Make sure there is no typo in the command")?; - let mut parser = Parser::new(input); - let timeline = parser.parse()?; - let output = serde_json::to_string_pretty(&timeline)?; - fs::write(OUTPUT_FILE, output)?; - println!("done!"); - println!("Output file: {}", OUTPUT_FILE); + match opt { + Command::Run { + before, + after, + author, + committer, + } => { + print!("Analyzing commits in current repository..."); + let input = count_commits(before, after, author, committer).context( + "Cannot read project history. Make sure there is no typo in the command", + )?; + let mut parser = Parser::new(input); + let timeline = parser.parse()?; + let output = serde_json::to_string_pretty(&timeline)?; + fs::write(OUTPUT_FILE, output)?; + println!("done!"); + println!("Output file: {}", OUTPUT_FILE); + } + Command::Merge {} => { + // Find all `codeprints*.json` files in the current directory + // using glob. + // Read each one into memory + // Merge the results together + // Write a `codeprints_merged.json` file + unimplemented!(); + } + }; Ok(()) } diff --git a/src/bin/analyzer/options.rs b/src/bin/analyzer/options.rs index 0605b3c..9300ffd 100644 --- a/src/bin/analyzer/options.rs +++ b/src/bin/analyzer/options.rs @@ -2,24 +2,27 @@ use structopt::StructOpt; #[derive(StructOpt, Debug)] #[structopt(name = "codeprints-analyzer")] -pub struct Opt { - /// Limit the commits output to ones with author header lines - /// that match the specified pattern. - /// This is passed verbatim to git. See `git log --help` for more info. - #[structopt(short, long)] - pub author: Vec, +pub enum Command { + Run { + /// Limit the commits output to ones with author header lines + /// that match the specified pattern. + /// This is passed verbatim to git. See `git log --help` for more info. + #[structopt(short, long)] + author: Vec, - /// Limit the commits output to ones with committer header lines - /// that match the specified pattern. - /// This is passed verbatim to git. See `git log --help` for more info. - #[structopt(short, long)] - pub committer: Vec, + /// Limit the commits output to ones with committer header lines + /// that match the specified pattern. + /// This is passed verbatim to git. See `git log --help` for more info. + #[structopt(short, long)] + committer: Vec, - // Show commits older than a specific date. - #[structopt(alias = "until", long)] - pub before: Option, + // Show commits older than a specific date. + #[structopt(alias = "until", long)] + before: Option, - // Show commits more recent than a specific date. - #[structopt(alias = "since", long)] - pub after: Option, + // Show commits more recent than a specific date. + #[structopt(alias = "since", long)] + after: Option, + }, + Merge {}, } From 27adefe331c4adb0b5408431c9069cc17455c379 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:09:38 +0100 Subject: [PATCH 24/50] impl Default for Year (generating empty timelines) --- src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types.rs b/src/types.rs index 70e3df2..e137791 100644 --- a/src/types.rs +++ b/src/types.rs @@ -7,7 +7,7 @@ pub struct Day { pub date: NaiveDate, } -#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Year { pub year: String, From 42ca666de27cc02705f20e47f5b2e0c9358c8a35 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:10:39 +0100 Subject: [PATCH 25/50] Split up parser into ParseState and core Parser This decouples the data representation from the parsing process, making the internal data format usable for other use-cases, such as merging timelines --- src/parser.rs | 242 ++++++++++++++++++++++++++++---------------------- 1 file changed, 137 insertions(+), 105 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index d92be0b..8aff260 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,96 +2,16 @@ use crate::quartiles::quartiles; use crate::types::{Contribution, Contributions, Range, Timeline, Year}; use anyhow::{Context, Result}; use chrono::prelude::*; -use std::collections::HashMap; +use std::{collections::HashMap, convert::TryFrom}; -/// A parser that converts git log output -/// into the JSON format understood by the -/// API of codeprints.dev. -#[derive(Debug)] -pub struct Parser { - input: String, +/// The internal state of the parser +#[derive(Debug, Default)] +pub struct ParseState { years_map: HashMap, days: HashMap, } -impl Parser { - /// Create a new parser that analyzes the given input - pub fn new(input: String) -> Self { - let years_map = HashMap::new(); - let days = HashMap::new(); - - Parser { - input, - years_map, - days, - } - } - - // Each cell in the timeline is shaded with one of 5 possible colors. These - // colors correspond to the quartiles of the normal distribution over the range - // [0, max(v)] where v is the sum of issues opened, pull requests proposed and - // commits authored per day. - // https://bd808.com/blog/2013/04/17/hacking-github-contributions-calendar/ - // https://github.community/t/the-color-coding-of-contribution-graph-is-showing-wrong-information/18572 - fn get_intensity(quartiles: &[usize], commits: usize) -> usize { - for (index, quartile) in quartiles.iter().enumerate() { - if commits < *quartile { - return index - 1; - } - } - quartiles.len() - 1 - } - - fn map_color(intensity: usize) -> String { - match intensity { - 1 => "var(--color-calendar-graph-day-L1-bg)", - 2 => "var(--color-calendar-graph-day-L2-bg)", - 3 => "var(--color-calendar-graph-day-L3-bg)", - 4 => "var(--color-calendar-graph-day-L4-bg)", - _ => "var(--color-calendar-graph-day-bg)", - } - .to_string() - } - - /// Backfill missing days with zero commits - fn backfill(year: i32, days: &mut HashMap) { - for d in NaiveDate::from_ymd(year, 1, 1).iter_days() { - if d.year() != year { - break; - } - days.entry(d).or_insert(0); - } - } - - fn create_contributions( - &self, - days: &HashMap, - quartiles: &[usize], - ) -> Vec { - let mut contributions = Vec::new(); - for (date, commits) in days { - let intensity = Self::get_intensity(&quartiles, *commits); - let color = Self::map_color(intensity); - - contributions.push(Contribution { - date: date.format("%Y-%m-%d").to_string(), - count: *commits, - color, - intensity, - }); - } - contributions - } - - fn parse_date(&self, line: &str) -> Result> { - if line.trim().is_empty() { - // Empty lines are allowed, but skipped - return Ok(None); - } - let date: NaiveDate = line.parse().context(format!("Invalid date {}", line))?; - Ok(Some(date)) - } - +impl ParseState { /// Add a single day to the map of years fn update_years(&mut self, date: NaiveDate) { let y = date.year(); @@ -116,34 +36,113 @@ impl Parser { *self.days.entry(date).or_insert(0) += 1; } - /// Execute the parsing step - pub fn parse(&mut self) -> Result { - let input = self.input.clone(); - for line in input.lines() { - let day = self.parse_date(&line)?; - if let Some(d) = day { - self.update_days(d); - self.update_years(d); + fn parse_date(&self, line: &str) -> Result> { + if line.trim().is_empty() { + // Empty lines are allowed, but skipped + return Ok(None); + } + let date: NaiveDate = line.parse().context(format!("Invalid date {}", line))?; + Ok(Some(date)) + } +} + +impl TryFrom for ParseState { + type Error = anyhow::Error; + + fn try_from(timeline: Timeline) -> Result { + let mut state = ParseState::default(); + for contribution in timeline.contributions { + let date = contribution.date; + let date = state.parse_date(&date)?; + let count = contribution.count; + + if let Some(date) = date { + // Kinda ineffective to call these update functions in a loop + for _ in 0..count { + state.update_years(date); + state.update_days(date); + } } } + Ok(state) + } +} + +/// Backfill missing days with zero commits +fn backfill(year: i32, days: &mut HashMap) { + for d in NaiveDate::from_ymd(year, 1, 1).iter_days() { + if d.year() != year { + break; + } + days.entry(d).or_insert(0); + } +} + +// Each cell in the timeline is shaded with one of 5 possible colors. These +// colors correspond to the quartiles of the normal distribution over the range +// [0, max(v)] where v is the sum of issues opened, pull requests proposed and +// commits authored per day. +// https://bd808.com/blog/2013/04/17/hacking-github-contributions-calendar/ +// https://github.community/t/the-color-coding-of-contribution-graph-is-showing-wrong-information/18572 +fn get_intensity(quartiles: &[usize], commits: usize) -> usize { + for (index, quartile) in quartiles.iter().enumerate() { + if commits < *quartile { + return index - 1; + } + } + quartiles.len() - 1 +} + +fn map_color(intensity: usize) -> String { + match intensity { + 1 => "var(--color-calendar-graph-day-L1-bg)", + 2 => "var(--color-calendar-graph-day-L2-bg)", + 3 => "var(--color-calendar-graph-day-L3-bg)", + 4 => "var(--color-calendar-graph-day-L4-bg)", + _ => "var(--color-calendar-graph-day-bg)", + } + .to_string() +} + +fn create_contributions( + days: &HashMap, + quartiles: &[usize], +) -> Vec { + let mut contributions = Vec::new(); + for (date, commits) in days { + let intensity = get_intensity(&quartiles, *commits); + let color = map_color(intensity); + + contributions.push(Contribution { + date: date.format("%Y-%m-%d").to_string(), + count: *commits, + color, + intensity, + }); + } + contributions +} - let mut years: Vec = self.years_map.values().cloned().collect(); +impl TryFrom<&ParseState> for Timeline { + type Error = anyhow::Error; + fn try_from(state: &ParseState) -> Result { + let mut years: Vec = state.years_map.values().cloned().collect(); years.sort(); years.reverse(); let mut contributions = Contributions::new(); for year in &years { - let mut year_contribs: HashMap = self + let mut year_contribs: HashMap = state .days .clone() .into_iter() .filter(|(date, _commits)| date.year().to_string() == year.year) .collect(); - Self::backfill(year.year.parse::()?, &mut year_contribs); + backfill(year.year.parse::()?, &mut year_contribs); let commits: Vec = year_contribs.values().cloned().collect(); let quartiles = quartiles(&commits)?; - let mut contribs = self.create_contributions(&year_contribs, &quartiles); + let mut contribs = create_contributions(&year_contribs, &quartiles); contributions.append(&mut contribs); } contributions.sort(); @@ -155,8 +154,41 @@ impl Parser { } } +/// A parser that converts git log output +/// into the JSON format understood by the +/// API of codeprints.dev. +#[derive(Debug, Default)] +pub struct Parser { + input: String, + state: ParseState, +} + +impl Parser { + /// Create a new parser that analyzes the given input + pub fn new(input: String) -> Self { + Parser { + input, + ..Default::default() + } + } + + /// Execute the parsing step + pub fn parse(&mut self) -> Result { + let input = self.input.clone(); + for line in input.lines() { + let day = self.state.parse_date(&line)?; + if let Some(d) = day { + self.state.update_days(d); + self.state.update_years(d); + } + } + + Ok(Timeline::try_from(&self.state)?) + } +} + #[cfg(test)] -mod test_super { +mod test { use super::*; @@ -188,12 +220,12 @@ mod test_super { #[test] fn test_intensities() { let quartiles = [0, 1, 11, 22, 32]; - assert_eq!(0, Parser::get_intensity(&quartiles, 0)); - assert_eq!(1, Parser::get_intensity(&quartiles, 1)); - assert_eq!(1, Parser::get_intensity(&quartiles, 10)); - assert_eq!(2, Parser::get_intensity(&quartiles, 18)); - assert_eq!(3, Parser::get_intensity(&quartiles, 22)); - assert_eq!(4, Parser::get_intensity(&quartiles, 32)); - assert_eq!(4, Parser::get_intensity(&quartiles, 100)); + assert_eq!(0, get_intensity(&quartiles, 0)); + assert_eq!(1, get_intensity(&quartiles, 1)); + assert_eq!(1, get_intensity(&quartiles, 10)); + assert_eq!(2, get_intensity(&quartiles, 18)); + assert_eq!(3, get_intensity(&quartiles, 22)); + assert_eq!(4, get_intensity(&quartiles, 32)); + assert_eq!(4, get_intensity(&quartiles, 100)); } } From 19840f2718b56003a5c6eddc62a29bae91bb7f6e Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:11:03 +0100 Subject: [PATCH 26/50] Work on merge setup --- src/lib.rs | 2 ++ src/merge.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 src/merge.rs diff --git a/src/lib.rs b/src/lib.rs index c1f346c..1c97056 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,9 +13,11 @@ )] mod git; +mod merge; mod parser; mod quartiles; mod types; pub use crate::git::count_commits; +pub use crate::merge::Merger; pub use crate::parser::Parser; diff --git a/src/merge.rs b/src/merge.rs new file mode 100644 index 0000000..48b16fb --- /dev/null +++ b/src/merge.rs @@ -0,0 +1,82 @@ +use std::convert::TryFrom; + +use crate::{parser::ParseState, types::Timeline}; +use anyhow::Result; + +/// Merger merges multiple timelines into one +#[derive(Debug)] +pub struct Merger { + state: ParseState, +} + +impl Merger { + /// Create a new merger with a clean state (no timeline merged) + pub fn new() -> Self { + let state = ParseState::default(); + Merger { state } + } + + fn merge_single(&mut self, single: ParseState) -> Result<()> { + self.state = single; + Ok(()) + } + + /// Merge multiple timelines together into one + /// This is helpful when analyzing multiple repositories and trying to combine + /// the individual results. + pub fn merge(&mut self, timelines: &[Timeline]) -> Result { + for timeline in timelines { + let single = ParseState::try_from(timeline.clone())?; + self.merge_single(single)?; + } + Ok(Timeline::try_from(&self.state)?) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::types::{Contribution, Range, Year}; + + #[test] + fn test_merge_none() { + let mut merger = Merger::new(); + assert_eq!(merger.merge(&[]).unwrap(), Timeline::default()); + } + + #[test] + fn test_merge_one() { + let mut timeline = Timeline::default(); + + let year = "2020".into(); + let total = 1234; + let range = Range { + start: "2020-02-01".into(), + end: "2020-03-02".into(), + }; + + let year1 = Year { year, total, range }; + let years = vec![year1]; + timeline.years = years; + + let contributions = vec![ + Contribution { + date: "2020-01-01".into(), + count: 1000, + color: "".into(), + intensity: 4, + }, + Contribution { + date: "2020-01-02".into(), + count: 234, + color: "".into(), + intensity: 4, + }, + ]; + + timeline.contributions = contributions; + + let mut merger = Merger::new(); + assert_eq!(merger.merge(&[timeline.clone()]).unwrap(), timeline); + } +} From fac6c44dbdda7fc56134adcfe4686ffc5a8ab213 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:11:23 +0100 Subject: [PATCH 27/50] Execute `run` by default if there are no additional arguments --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index ef8f113..a446d52 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,3 +15,5 @@ RUN apt-get update \ COPY --from=builder /analyzer/target/release/codeprints-analyzer /usr/local/bin/codeprints-analyzer WORKDIR /repo ENTRYPOINT [ "codeprints-analyzer" ] +# The standard command parses the commits of a repository +CMD ["run"] From a239c07f5609cf4db45f83a9ab072b209aaa2b2b Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:11:27 +0100 Subject: [PATCH 28/50] Update docs --- README.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 08f8c0a..b07899f 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ codeprints-analyzer You can set the start- and end-date of the output. ``` -docker run -v `pwd`:/repo codeprints/analyzer --after "2020-12-24" --before "2021-02-10" +docker run -v `pwd`:/repo codeprints/analyzer run --after "2020-12-24" --before "2021-02-10" ``` The syntax is exactly the same that `git` also uses. @@ -55,7 +55,7 @@ If you work in a bigger team, you might want to filter the contributions by author. Here is how: ``` -docker run -v `pwd`:/repo codeprints/analyzer --author "Matthias" --author "Octocat" +docker run -v `pwd`:/repo codeprints/analyzer run --author "Matthias" --author "Octocat" ``` To get a list of all author names, run `git shortlog --summary --numbered --email`. @@ -63,6 +63,19 @@ To get a list of all author names, run `git shortlog --summary --numbered --emai (You can also filter by committers. The difference is subtle, but in contrast to authors, these are the contributors who pushed/committed a patch to the repository.) +## Merging multiple codeprints output files + +Do you have multiple repositories that you want to analyze? +No problem! Just run the tool in every repository folder. +After that, copy the files into a single folder and run the following command: + +``` +docker run -v `pwd`:/repo codeprints/analyzer merge +``` + +This will merge all codeprints\_\*.json files in the `repo` directory into one file. +(It will accumulate all contribution counts for each day.) + ## More options To get an exhaustive list of options, run From a7a68b969b465f4874b5b8717cd984589738a739 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:33:14 +0100 Subject: [PATCH 29/50] Work on merger --- src/merge.rs | 19 +++++++++++++++---- src/parser.rs | 6 +++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/merge.rs b/src/merge.rs index 48b16fb..58cf223 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -16,8 +16,20 @@ impl Merger { Merger { state } } - fn merge_single(&mut self, single: ParseState) -> Result<()> { - self.state = single; + fn merge_timeline(&mut self, timeline: &Timeline) -> Result<()> { + for contribution in &timeline.contributions { + let date = contribution.date.clone(); + let date = self.state.parse_date(&date)?; + let count = contribution.count; + + if let Some(date) = date { + // Kinda ineffective to call these update functions in a loop + for _ in 0..count { + self.state.update_years(date); + self.state.update_days(date); + } + } + } Ok(()) } @@ -26,8 +38,7 @@ impl Merger { /// the individual results. pub fn merge(&mut self, timelines: &[Timeline]) -> Result { for timeline in timelines { - let single = ParseState::try_from(timeline.clone())?; - self.merge_single(single)?; + self.merge_timeline(timeline)? } Ok(Timeline::try_from(&self.state)?) } diff --git a/src/parser.rs b/src/parser.rs index 8aff260..0b0822f 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -13,7 +13,7 @@ pub struct ParseState { impl ParseState { /// Add a single day to the map of years - fn update_years(&mut self, date: NaiveDate) { + pub fn update_years(&mut self, date: NaiveDate) { let y = date.year(); let mut year = self.years_map.entry(y).or_insert(Year { year: y.to_string(), @@ -32,11 +32,11 @@ impl ParseState { } /// Add a single day to the map of days - fn update_days(&mut self, date: NaiveDate) { + pub fn update_days(&mut self, date: NaiveDate) { *self.days.entry(date).or_insert(0) += 1; } - fn parse_date(&self, line: &str) -> Result> { + pub fn parse_date(&self, line: &str) -> Result> { if line.trim().is_empty() { // Empty lines are allowed, but skipped return Ok(None); From b01398846d991d7d33f8db049f0e4db5cd69e7a7 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Feb 2021 15:33:57 +0100 Subject: [PATCH 30/50] Remove unused TryFrom --- src/parser.rs | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 0b0822f..ee90fbb 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -46,28 +46,6 @@ impl ParseState { } } -impl TryFrom for ParseState { - type Error = anyhow::Error; - - fn try_from(timeline: Timeline) -> Result { - let mut state = ParseState::default(); - for contribution in timeline.contributions { - let date = contribution.date; - let date = state.parse_date(&date)?; - let count = contribution.count; - - if let Some(date) = date { - // Kinda ineffective to call these update functions in a loop - for _ in 0..count { - state.update_years(date); - state.update_days(date); - } - } - } - Ok(state) - } -} - /// Backfill missing days with zero commits fn backfill(year: i32, days: &mut HashMap) { for d in NaiveDate::from_ymd(year, 1, 1).iter_days() { From ea60627b75b2311c03bee6ee62c3bd85ec642737 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Sat, 20 Feb 2021 00:15:29 +0100 Subject: [PATCH 31/50] Show full year --- src/parser.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index ee90fbb..80961ce 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -18,17 +18,22 @@ impl ParseState { let mut year = self.years_map.entry(y).or_insert(Year { year: y.to_string(), total: 0, - range: Range::default(), + // range: Range::default, + // Always show full year + range: Range { + start: format!("{}-01-01", y), + end: format!("{}-12-31", y), + }, }); year.total += 1; - let date = date.format("%Y-%m-%d").to_string(); - if year.range.start.is_empty() || date < year.range.start { - year.range.start = date.clone(); - } - if year.range.end.is_empty() || date > year.range.end { - year.range.end = date - } + // let date = date.format("%Y-%m-%d").to_string(); + // if year.range.start.is_empty() || date < year.range.start { + // year.range.start = date.clone(); + // } + // if year.range.end.is_empty() || date > year.range.end { + // year.range.end = date + // } } /// Add a single day to the map of days From a5fb023707e892020eb5761072d956313796dea9 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 3 Mar 2021 15:06:51 +0100 Subject: [PATCH 32/50] handle start and end date in output --- src/bin/analyzer/main.rs | 8 ++++- src/git.rs | 17 ++++++++-- src/merge.rs | 4 +-- src/parser.rs | 68 +++++++++++++++++++++++++++++++--------- 4 files changed, 76 insertions(+), 21 deletions(-) diff --git a/src/bin/analyzer/main.rs b/src/bin/analyzer/main.rs index a740879..eb0e945 100644 --- a/src/bin/analyzer/main.rs +++ b/src/bin/analyzer/main.rs @@ -31,10 +31,16 @@ fn main() -> Result<()> { committer, } => { print!("Analyzing commits in current repository..."); - let input = count_commits(before, after, author, committer).context( + let input = count_commits(&before, &after, author, committer).context( "Cannot read project history. Make sure there is no typo in the command", )?; let mut parser = Parser::new(input); + if let Some(before) = before { + parser.set_before(before)?; + } + if let Some(after) = after { + parser.set_after(after)?; + } let timeline = parser.parse()?; let output = serde_json::to_string_pretty(&timeline)?; fs::write(OUTPUT_FILE, output)?; diff --git a/src/git.rs b/src/git.rs index 6a7f92c..3beec19 100644 --- a/src/git.rs +++ b/src/git.rs @@ -1,10 +1,11 @@ -use anyhow::Result; +use anyhow::{Context, Result}; +use chrono::NaiveDate; use duct::cmd; /// Get the count of commits for each day from the git logs pub fn count_commits( - before: Option, - after: Option, + before: &Option, + after: &Option, authors: Vec, committers: Vec, ) -> Result { @@ -28,3 +29,13 @@ pub fn count_commits( let commits = cmd("git", &args).read()?; Ok(commits) } + +// Parse a date from the git log +pub fn parse_date(line: &str) -> Result> { + if line.trim().is_empty() { + // Empty lines are allowed, but skipped + return Ok(None); + } + let date: NaiveDate = line.parse().context(format!("Invalid date {}", line))?; + Ok(Some(date)) +} diff --git a/src/merge.rs b/src/merge.rs index 58cf223..fbe2b30 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -1,6 +1,6 @@ use std::convert::TryFrom; -use crate::{parser::ParseState, types::Timeline}; +use crate::{git, parser::ParseState, types::Timeline}; use anyhow::Result; /// Merger merges multiple timelines into one @@ -19,7 +19,7 @@ impl Merger { fn merge_timeline(&mut self, timeline: &Timeline) -> Result<()> { for contribution in &timeline.contributions { let date = contribution.date.clone(); - let date = self.state.parse_date(&date)?; + let date = git::parse_date(&date)?; let count = contribution.count; if let Some(date) = date { diff --git a/src/parser.rs b/src/parser.rs index 80961ce..81d5bd5 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,28 +1,38 @@ -use crate::quartiles::quartiles; use crate::types::{Contribution, Contributions, Range, Timeline, Year}; -use anyhow::{Context, Result}; +use crate::{git, quartiles::quartiles}; +use anyhow::Result; use chrono::prelude::*; -use std::{collections::HashMap, convert::TryFrom}; +use std::{cmp::{max, min}, collections::HashMap, convert::TryFrom}; /// The internal state of the parser #[derive(Debug, Default)] pub struct ParseState { years_map: HashMap, days: HashMap, + before: Option, + after: Option, } impl ParseState { /// Add a single day to the map of years pub fn update_years(&mut self, date: NaiveDate) { let y = date.year(); + let start = match self.before { + Some(before) => max(before, date), + None => date, + }; + let end = match self.after { + Some(after) => min(after, date), + None => date, + }; let mut year = self.years_map.entry(y).or_insert(Year { year: y.to_string(), total: 0, // range: Range::default, // Always show full year range: Range { - start: format!("{}-01-01", y), - end: format!("{}-12-31", y), + start: start.format("%y-%m-%d").to_string(), + end: end.format("%y-%m-%d").to_string(), }, }); year.total += 1; @@ -40,15 +50,6 @@ impl ParseState { pub fn update_days(&mut self, date: NaiveDate) { *self.days.entry(date).or_insert(0) += 1; } - - pub fn parse_date(&self, line: &str) -> Result> { - if line.trim().is_empty() { - // Empty lines are allowed, but skipped - return Ok(None); - } - let date: NaiveDate = line.parse().context(format!("Invalid date {}", line))?; - Ok(Some(date)) - } } /// Backfill missing days with zero commits @@ -155,12 +156,49 @@ impl Parser { } } + /// Set the minimum date of the timeline. Commits older than the given date + /// will not be counted and won't be in the final output + pub fn set_before(&mut self, before: String) -> Result<&mut Self> { + let before = git::parse_date(&before)?; + if let Some(before) = before { + self.state.before = Some(before); + } + Ok(self) + } + + /// Set the maximum date of the timeline. Commits newer than the given date + /// will not be counted and won't be in the final output + pub fn set_after(&mut self, after: String) -> Result<&mut Self> { + let after = git::parse_date(&after)?; + if let Some(after) = after { + self.state.after = Some(after); + } + Ok(self) + } + + fn outside_date_range(&self, day: NaiveDate) -> bool { + if let Some(before) = self.state.before { + if day < before { + return true; + } + } + if let Some(after) = self.state.after { + if day > after { + return true; + } + } + false + } + /// Execute the parsing step pub fn parse(&mut self) -> Result { let input = self.input.clone(); for line in input.lines() { - let day = self.state.parse_date(&line)?; + let day = git::parse_date(&line)?; if let Some(d) = day { + if self.outside_date_range(d) { + continue; + } self.state.update_days(d); self.state.update_years(d); } From 622c4c68cf0860d930ff7c23542e51da05294523 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Mon, 8 Mar 2021 21:57:02 +0100 Subject: [PATCH 33/50] Fix test --- src/merge.rs | 12 ++++++-- src/parser.rs | 82 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 64 insertions(+), 30 deletions(-) diff --git a/src/merge.rs b/src/merge.rs index fbe2b30..49d7caa 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -62,8 +62,8 @@ mod test { let year = "2020".into(); let total = 1234; let range = Range { - start: "2020-02-01".into(), - end: "2020-03-02".into(), + start: "2020-01-01".into(), + end: "2020-01-02".into(), }; let year1 = Year { year, total, range }; @@ -88,6 +88,12 @@ mod test { timeline.contributions = contributions; let mut merger = Merger::new(); - assert_eq!(merger.merge(&[timeline.clone()]).unwrap(), timeline); + let merged = merger.merge(&[timeline.clone()]).unwrap(); + assert_eq!(merged.years.len(), 1); + let year = &merged.years[0]; + assert_eq!(year.year, "2020"); + assert_eq!(year.total, 1234); + assert_eq!(year.range.start, "2020-01-01"); + assert_eq!(year.range.end, "2020-01-02"); } } diff --git a/src/parser.rs b/src/parser.rs index 81d5bd5..bea3b03 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,8 +1,12 @@ use crate::types::{Contribution, Contributions, Range, Timeline, Year}; use crate::{git, quartiles::quartiles}; -use anyhow::Result; +use anyhow::{Context, Result}; use chrono::prelude::*; -use std::{cmp::{max, min}, collections::HashMap, convert::TryFrom}; +use std::{ + cmp::{max, min}, + collections::HashMap, + convert::TryFrom, +}; /// The internal state of the parser #[derive(Debug, Default)] @@ -17,33 +21,23 @@ impl ParseState { /// Add a single day to the map of years pub fn update_years(&mut self, date: NaiveDate) { let y = date.year(); - let start = match self.before { - Some(before) => max(before, date), - None => date, - }; - let end = match self.after { - Some(after) => min(after, date), - None => date, - }; + let date_str = date.format("%Y-%m-%d").to_string(); + let mut year = self.years_map.entry(y).or_insert(Year { year: y.to_string(), total: 0, // range: Range::default, // Always show full year range: Range { - start: start.format("%y-%m-%d").to_string(), - end: end.format("%y-%m-%d").to_string(), + start: date_str.clone(), + end: date_str.clone(), }, }); - year.total += 1; - // let date = date.format("%Y-%m-%d").to_string(); - // if year.range.start.is_empty() || date < year.range.start { - // year.range.start = date.clone(); - // } - // if year.range.end.is_empty() || date > year.range.end { - // year.range.end = date - // } + year.range.start = min(year.range.start.clone(), date_str.clone()); + year.range.end = max(year.range.end.clone(), date_str); + + year.total += 1; } /// Add a single day to the map of days @@ -53,13 +47,19 @@ impl ParseState { } /// Backfill missing days with zero commits -fn backfill(year: i32, days: &mut HashMap) { +fn backfill(year: i32, days: &mut HashMap) -> Result<()> { + let last_day = days + .keys() + .max_by_key(|key| *key) + .cloned() + .context("cannot get last day for backfilling")?; for d in NaiveDate::from_ymd(year, 1, 1).iter_days() { - if d.year() != year { + if d > last_day { break; } days.entry(d).or_insert(0); } + Ok(()) } // Each cell in the timeline is shaded with one of 5 possible colors. These @@ -122,7 +122,7 @@ impl TryFrom<&ParseState> for Timeline { .into_iter() .filter(|(date, _commits)| date.year().to_string() == year.year) .collect(); - backfill(year.year.parse::()?, &mut year_contribs); + backfill(year.year.parse::()?, &mut year_contribs)?; let commits: Vec = year_contribs.values().cloned().collect(); let quartiles = quartiles(&commits)?; @@ -176,14 +176,14 @@ impl Parser { Ok(self) } - fn outside_date_range(&self, day: NaiveDate) -> bool { + fn out_of_range(&self, day: NaiveDate) -> bool { if let Some(before) = self.state.before { - if day < before { + if day >= before { return true; } } if let Some(after) = self.state.after { - if day > after { + if day <= after { return true; } } @@ -196,7 +196,7 @@ impl Parser { for line in input.lines() { let day = git::parse_date(&line)?; if let Some(d) = day { - if self.outside_date_range(d) { + if self.out_of_range(d) { continue; } self.state.update_days(d); @@ -238,6 +238,34 @@ mod test { assert_eq!(parser.parse().unwrap().years, expected); } + #[test] + fn test_parse_years_range() { + let input = r###" + 2020-04-15 + 2020-04-15 + 2020-04-16 + 2020-04-17 + 2020-04-17 + 2020-04-17 + 2020-04-17 + 2020-04-18 + "###; + + let range = Range { + start: "2020-04-16".to_string(), + end: "2020-04-17".to_string(), + }; + let expected = vec![Year { + year: "2020".to_string(), + total: 5, + range: range, + }]; + let mut parser = Parser::new(input.to_string()); + parser.set_before("2020-04-18".into()).unwrap(); + parser.set_after("2020-04-15".into()).unwrap(); + assert_eq!(parser.parse().unwrap().years, expected); + } + #[test] fn test_intensities() { let quartiles = [0, 1, 11, 22, 32]; From 615c0bf43adf8239ca91d33be31cada13937f3a3 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Mon, 8 Mar 2021 22:22:10 +0100 Subject: [PATCH 34/50] work on merge --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/bin/analyzer/main.rs | 36 ++++++++++++++++++++++++++---------- src/lib.rs | 1 + src/merge.rs | 9 ++++++++- src/types.rs | 1 + 6 files changed, 44 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec05e8a..a8bcd00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,6 +75,7 @@ dependencies = [ "anyhow", "chrono", "duct", + "glob", "quantiles", "serde", "serde_json", @@ -93,6 +94,12 @@ dependencies = [ "shared_child", ] +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + [[package]] name = "heck" version = "0.3.2" diff --git a/Cargo.toml b/Cargo.toml index cd245d9..b23e57e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,3 +29,4 @@ serde_json = "1.0.62" chrono = "0.4.19" quantiles = "0.7.1" structopt = "0.3.21" +glob = "0.3.0" diff --git a/src/bin/analyzer/main.rs b/src/bin/analyzer/main.rs index eb0e945..01c1cdc 100644 --- a/src/bin/analyzer/main.rs +++ b/src/bin/analyzer/main.rs @@ -10,15 +10,23 @@ )] use anyhow::{Context, Result}; -use codeprints_analyzer::count_commits; use codeprints_analyzer::Parser; +use codeprints_analyzer::Timeline; +use codeprints_analyzer::{count_commits, Merger}; +use glob::glob; use std::fs; use structopt::StructOpt; mod options; use options::Command; -const OUTPUT_FILE: &'static str = "codeprints.json"; +fn write(timeline: &Timeline, output_file: &str) -> Result<()> { + let output = serde_json::to_string_pretty(&timeline)?; + fs::write(output_file, output)?; + println!("done!"); + println!("Output file: {}", output_file); + Ok(()) +} fn main() -> Result<()> { let opt = Command::from_args(); @@ -42,18 +50,26 @@ fn main() -> Result<()> { parser.set_after(after)?; } let timeline = parser.parse()?; - let output = serde_json::to_string_pretty(&timeline)?; - fs::write(OUTPUT_FILE, output)?; - println!("done!"); - println!("Output file: {}", OUTPUT_FILE); + + write(&timeline, "codeprints.json")?; } Command::Merge {} => { // Find all `codeprints*.json` files in the current directory // using glob. - // Read each one into memory - // Merge the results together - // Write a `codeprints_merged.json` file - unimplemented!(); + let mut merger = Merger::new(); + for entry in glob("codeprints*.json")? { + match entry { + Ok(path) => { + println!("Merging {}", path.display()); + let input = fs::read_to_string(path)?; + let mut parser = Parser::new(input); + let timeline = parser.parse()?; + merger.merge_timeline(&timeline)?; + } + Err(e) => println!("{:?}", e), + } + } + write(&merger.timeline()?, "codeprints_merged.json")?; } }; Ok(()) diff --git a/src/lib.rs b/src/lib.rs index 1c97056..a27ca0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,3 +21,4 @@ mod types; pub use crate::git::count_commits; pub use crate::merge::Merger; pub use crate::parser::Parser; +pub use crate::types::Timeline as Timeline; diff --git a/src/merge.rs b/src/merge.rs index 49d7caa..f007d3f 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -16,7 +16,8 @@ impl Merger { Merger { state } } - fn merge_timeline(&mut self, timeline: &Timeline) -> Result<()> { + /// Merge a single timeline + pub fn merge_timeline(&mut self, timeline: &Timeline) -> Result<()> { for contribution in &timeline.contributions { let date = contribution.date.clone(); let date = git::parse_date(&date)?; @@ -42,8 +43,14 @@ impl Merger { } Ok(Timeline::try_from(&self.state)?) } + + /// Return the merged timeline of all inputs + pub fn timeline(&self) -> Result { + Ok(Timeline::try_from(&self.state)?) + } } + #[cfg(test)] mod test { use super::*; diff --git a/src/types.rs b/src/types.rs index e137791..cbb3bcb 100644 --- a/src/types.rs +++ b/src/types.rs @@ -18,6 +18,7 @@ pub struct Year { pub type Years = Vec; pub type Contributions = Vec; +/// A timeline represents a codeprints.json file's contents #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Timeline { From 37de10333f04f535f1ad5400ff165d96e80020be Mon Sep 17 00:00:00 2001 From: Wolfgang Gassler Date: Mon, 8 Mar 2021 23:57:05 +0100 Subject: [PATCH 35/50] WIP: merge multiple timeslines - adds a test for multiple timelines (is failing) - adds a parameter update methods of a year --- src/merge.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++++----- src/parser.rs | 12 +++++------ 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/merge.rs b/src/merge.rs index f007d3f..9d1bb4d 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -18,17 +18,15 @@ impl Merger { /// Merge a single timeline pub fn merge_timeline(&mut self, timeline: &Timeline) -> Result<()> { + ///TODO: make sure that all days are filled with 0 between start and end for contribution in &timeline.contributions { let date = contribution.date.clone(); let date = git::parse_date(&date)?; let count = contribution.count; if let Some(date) = date { - // Kinda ineffective to call these update functions in a loop - for _ in 0..count { - self.state.update_years(date); - self.state.update_days(date); - } + self.state.update_years(date, count); + self.state.update_days(date, count); } } Ok(()) @@ -103,4 +101,51 @@ mod test { assert_eq!(year.range.start, "2020-01-01"); assert_eq!(year.range.end, "2020-01-02"); } + + #[test] + fn test_merge_multiple() { + let mut timeline1 = Timeline::default(); + let mut timeline2 = Timeline::default(); + + let range1 = Range { + start: "2020-01-01".into(), + end: "2020-01-02".into(), + }; + let range2 = Range { + start: "2020-01-01".into(), + end: "2020-01-03".into(), + }; + + let year2 = Year { year: "2020".into(), total: 0, range: range2 }; + let year1 = Year { year: "2020".into(), total: 123, range: range1 }; + timeline1.years = vec![year1]; + timeline2.years = vec![year2]; + + let contributions = vec![ + Contribution { + date: "2020-01-01".into(), + count: 1000, + color: "".into(), + intensity: 4, + }, + Contribution { + date: "2020-01-02".into(), + count: 234, + color: "".into(), + intensity: 4, + }, + ]; + + timeline1.contributions = contributions.clone(); + timeline2.contributions = contributions.clone(); + + let mut merger = Merger::new(); + let merged = merger.merge(&[timeline1.clone(),timeline2.clone()]).unwrap(); + assert_eq!(merged.years.len(), 1); + let year = &merged.years[0]; + assert_eq!(year.year, "2020"); + assert_eq!(year.total, 2468); + assert_eq!(year.range.start, "2020-01-01"); + assert_eq!(year.range.end, "2020-01-03"); + } } diff --git a/src/parser.rs b/src/parser.rs index bea3b03..db84fca 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -19,7 +19,7 @@ pub struct ParseState { impl ParseState { /// Add a single day to the map of years - pub fn update_years(&mut self, date: NaiveDate) { + pub fn update_years(&mut self, date: NaiveDate, contributions_to_add: usize) { let y = date.year(); let date_str = date.format("%Y-%m-%d").to_string(); @@ -37,12 +37,12 @@ impl ParseState { year.range.start = min(year.range.start.clone(), date_str.clone()); year.range.end = max(year.range.end.clone(), date_str); - year.total += 1; + year.total += contributions_to_add; } /// Add a single day to the map of days - pub fn update_days(&mut self, date: NaiveDate) { - *self.days.entry(date).or_insert(0) += 1; + pub fn update_days(&mut self, date: NaiveDate, contributions_to_add: usize) { + *self.days.entry(date).or_insert(0) += contributions_to_add; } } @@ -199,8 +199,8 @@ impl Parser { if self.out_of_range(d) { continue; } - self.state.update_days(d); - self.state.update_years(d); + self.state.update_days(d, 1); + self.state.update_years(d, 1); } } From cfc6076c9b7eaddb1d8d8c8acba28794ad14dde9 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 01:30:09 +0100 Subject: [PATCH 36/50] fix merge 2 test --- src/merge.rs | 51 +++++++++++++++++++++++++++++++++++++++++---------- src/types.rs | 2 ++ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/merge.rs b/src/merge.rs index 9d1bb4d..3e43448 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -18,7 +18,7 @@ impl Merger { /// Merge a single timeline pub fn merge_timeline(&mut self, timeline: &Timeline) -> Result<()> { - ///TODO: make sure that all days are filled with 0 between start and end + // TODO: make sure that all days are filled with 0 between start and end for contribution in &timeline.contributions { let date = contribution.date.clone(); let date = git::parse_date(&date)?; @@ -48,7 +48,6 @@ impl Merger { } } - #[cfg(test)] mod test { use super::*; @@ -116,12 +115,21 @@ mod test { end: "2020-01-03".into(), }; - let year2 = Year { year: "2020".into(), total: 0, range: range2 }; - let year1 = Year { year: "2020".into(), total: 123, range: range1 }; + let year1 = Year { + year: "2020".into(), + total: 1234, + range: range1, + }; timeline1.years = vec![year1]; + + let year2 = Year { + year: "2020".into(), + total: 6, + range: range2, + }; timeline2.years = vec![year2]; - let contributions = vec![ + let contributions1 = vec![ Contribution { date: "2020-01-01".into(), count: 1000, @@ -136,16 +144,39 @@ mod test { }, ]; - timeline1.contributions = contributions.clone(); - timeline2.contributions = contributions.clone(); + let contributions2 = vec![ + Contribution { + date: "2020-01-01".into(), + count: 0, + color: "".into(), + intensity: 0, + }, + Contribution { + date: "2020-01-02".into(), + count: 5, + color: "".into(), + intensity: 4, + }, + Contribution { + date: "2020-01-03".into(), + count: 1, + color: "".into(), + intensity: 1, + }, + ]; + + timeline1.contributions = contributions1.clone(); + timeline2.contributions = contributions2.clone(); let mut merger = Merger::new(); - let merged = merger.merge(&[timeline1.clone(),timeline2.clone()]).unwrap(); + let merged = merger + .merge(&[timeline1.clone(), timeline2.clone()]) + .unwrap(); assert_eq!(merged.years.len(), 1); let year = &merged.years[0]; assert_eq!(year.year, "2020"); - assert_eq!(year.total, 2468); + assert_eq!(year.total, 1240); assert_eq!(year.range.start, "2020-01-01"); assert_eq!(year.range.end, "2020-01-03"); - } + } } diff --git a/src/types.rs b/src/types.rs index cbb3bcb..9e3a4e8 100644 --- a/src/types.rs +++ b/src/types.rs @@ -22,7 +22,9 @@ pub type Contributions = Vec; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Timeline { + /// Years belonging to the timeline pub years: Years, + /// Contributions belonging to the timeline pub contributions: Contributions, } From 7cb306398f4fabcf7b625823dfc8909e03b5cb5f Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 01:37:25 +0100 Subject: [PATCH 37/50] Fix clippy warnings --- src/merge.rs | 6 +++--- src/parser.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/merge.rs b/src/merge.rs index 3e43448..c56abdf 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -4,7 +4,7 @@ use crate::{git, parser::ParseState, types::Timeline}; use anyhow::Result; /// Merger merges multiple timelines into one -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Merger { state: ParseState, } @@ -39,12 +39,12 @@ impl Merger { for timeline in timelines { self.merge_timeline(timeline)? } - Ok(Timeline::try_from(&self.state)?) + Timeline::try_from(&self.state) } /// Return the merged timeline of all inputs pub fn timeline(&self) -> Result { - Ok(Timeline::try_from(&self.state)?) + Timeline::try_from(&self.state) } } diff --git a/src/parser.rs b/src/parser.rs index db84fca..e82f903 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -204,7 +204,7 @@ impl Parser { } } - Ok(Timeline::try_from(&self.state)?) + Timeline::try_from(&self.state) } } From fc822a1a3f357c35d6c62df38b5158217838400c Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 01:45:18 +0100 Subject: [PATCH 38/50] Add hash to timeline --- src/bin/analyzer/main.rs | 8 +++++--- src/git.rs | 8 +++++++- src/lib.rs | 7 ++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/bin/analyzer/main.rs b/src/bin/analyzer/main.rs index 01c1cdc..88cd0c7 100644 --- a/src/bin/analyzer/main.rs +++ b/src/bin/analyzer/main.rs @@ -10,9 +10,10 @@ )] use anyhow::{Context, Result}; +use codeprints_analyzer::git; +use codeprints_analyzer::Merger; use codeprints_analyzer::Parser; use codeprints_analyzer::Timeline; -use codeprints_analyzer::{count_commits, Merger}; use glob::glob; use std::fs; use structopt::StructOpt; @@ -39,7 +40,7 @@ fn main() -> Result<()> { committer, } => { print!("Analyzing commits in current repository..."); - let input = count_commits(&before, &after, author, committer).context( + let input = git::count_commits(&before, &after, author, committer).context( "Cannot read project history. Make sure there is no typo in the command", )?; let mut parser = Parser::new(input); @@ -51,7 +52,8 @@ fn main() -> Result<()> { } let timeline = parser.parse()?; - write(&timeline, "codeprints.json")?; + let sha = git::sha()?; + write(&timeline, &format!("codeprints_{}.json", sha))?; } Command::Merge {} => { // Find all `codeprints*.json` files in the current directory diff --git a/src/git.rs b/src/git.rs index 3beec19..4953046 100644 --- a/src/git.rs +++ b/src/git.rs @@ -30,7 +30,7 @@ pub fn count_commits( Ok(commits) } -// Parse a date from the git log +/// Parse a date from the git log pub fn parse_date(line: &str) -> Result> { if line.trim().is_empty() { // Empty lines are allowed, but skipped @@ -39,3 +39,9 @@ pub fn parse_date(line: &str) -> Result> { let date: NaiveDate = line.parse().context(format!("Invalid date {}", line))?; Ok(Some(date)) } + +/// Get the current git commit sha +pub fn sha() -> Result { + let sha = cmd("git", &["rev-parse", "--short", "HEAD"]).read()?; + Ok(sha) +} diff --git a/src/lib.rs b/src/lib.rs index a27ca0d..bf65370 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,13 +12,14 @@ unused_qualifications )] -mod git; +/// Git helper functions +pub mod git; + mod merge; mod parser; mod quartiles; mod types; -pub use crate::git::count_commits; pub use crate::merge::Merger; pub use crate::parser::Parser; -pub use crate::types::Timeline as Timeline; +pub use crate::types::Timeline; From 452a2e333064aa4c342a7aa1ada6dce39a858861 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 02:06:34 +0100 Subject: [PATCH 39/50] fix lints --- src/parser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index e82f903..4900418 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -232,7 +232,7 @@ mod test { let expected = vec![Year { year: "2020".to_string(), total: 7, - range: range, + range, }]; let mut parser = Parser::new(input.to_string()); assert_eq!(parser.parse().unwrap().years, expected); @@ -258,7 +258,7 @@ mod test { let expected = vec![Year { year: "2020".to_string(), total: 5, - range: range, + range, }]; let mut parser = Parser::new(input.to_string()); parser.set_before("2020-04-18".into()).unwrap(); From 05af9d2661eb49361da20195455dcac1f9e5f80a Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 02:11:07 +0100 Subject: [PATCH 40/50] Less clones --- src/merge.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/merge.rs b/src/merge.rs index c56abdf..9580ec2 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -92,7 +92,7 @@ mod test { timeline.contributions = contributions; let mut merger = Merger::new(); - let merged = merger.merge(&[timeline.clone()]).unwrap(); + let merged = merger.merge(&[timeline]).unwrap(); assert_eq!(merged.years.len(), 1); let year = &merged.years[0]; assert_eq!(year.year, "2020"); @@ -165,13 +165,11 @@ mod test { }, ]; - timeline1.contributions = contributions1.clone(); - timeline2.contributions = contributions2.clone(); + timeline1.contributions = contributions1; + timeline2.contributions = contributions2; let mut merger = Merger::new(); - let merged = merger - .merge(&[timeline1.clone(), timeline2.clone()]) - .unwrap(); + let merged = merger.merge(&[timeline1, timeline2]).unwrap(); assert_eq!(merged.years.len(), 1); let year = &merged.years[0]; assert_eq!(year.year, "2020"); From 5cc67262bf978e1d56de61ecba384a48ed36c7ad Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 02:13:47 +0100 Subject: [PATCH 41/50] Remove unused import --- tests/test_parser.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_parser.rs b/tests/test_parser.rs index 5084729..c8502a7 100644 --- a/tests/test_parser.rs +++ b/tests/test_parser.rs @@ -1,5 +1,4 @@ use codeprints_analyzer::Parser; -use serde_json; use std::fs; fn ignore_whitespace(s: &str) -> String { From 74fe53a1c0e687a460f791a46d612124277e9449 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 10 Mar 2021 02:21:14 +0100 Subject: [PATCH 42/50] fix merge call --- src/bin/analyzer/main.rs | 3 +-- src/git.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bin/analyzer/main.rs b/src/bin/analyzer/main.rs index 88cd0c7..740ee52 100644 --- a/src/bin/analyzer/main.rs +++ b/src/bin/analyzer/main.rs @@ -64,8 +64,7 @@ fn main() -> Result<()> { Ok(path) => { println!("Merging {}", path.display()); let input = fs::read_to_string(path)?; - let mut parser = Parser::new(input); - let timeline = parser.parse()?; + let timeline: Timeline = serde_json::from_str(&input)?; merger.merge_timeline(&timeline)?; } Err(e) => println!("{:?}", e), diff --git a/src/git.rs b/src/git.rs index 4953046..d02070f 100644 --- a/src/git.rs +++ b/src/git.rs @@ -36,7 +36,7 @@ pub fn parse_date(line: &str) -> Result> { // Empty lines are allowed, but skipped return Ok(None); } - let date: NaiveDate = line.parse().context(format!("Invalid date {}", line))?; + let date: NaiveDate = line.parse().context(format!("Invalid date: {}", line))?; Ok(Some(date)) } From ca4cac5781b4abb727c02ecfb7c30da16cecd852 Mon Sep 17 00:00:00 2001 From: Wolfgang Gassler Date: Thu, 11 Mar 2021 22:03:18 +0100 Subject: [PATCH 43/50] txt for help option --- src/bin/analyzer/options.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bin/analyzer/options.rs b/src/bin/analyzer/options.rs index 9300ffd..396208e 100644 --- a/src/bin/analyzer/options.rs +++ b/src/bin/analyzer/options.rs @@ -3,6 +3,7 @@ use structopt::StructOpt; #[derive(StructOpt, Debug)] #[structopt(name = "codeprints-analyzer")] pub enum Command { + /// Run the analyzer and generate json summary of contributions Run { /// Limit the commits output to ones with author header lines /// that match the specified pattern. @@ -24,5 +25,6 @@ pub enum Command { #[structopt(alias = "since", long)] after: Option, }, + /// Merge all codeprints*.json to one file named codeprints_merged.json Merge {}, } From 86202e44a10ac60760f2b3f33103f23ef40ebe1c Mon Sep 17 00:00:00 2001 From: Wolfgang Gassler Date: Thu, 11 Mar 2021 22:03:54 +0100 Subject: [PATCH 44/50] test for intesity computation #5 -> failing --- fixtures/mre_raw_2020_from_api.json | 1 + tests/test_merger.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 fixtures/mre_raw_2020_from_api.json create mode 100644 tests/test_merger.rs diff --git a/fixtures/mre_raw_2020_from_api.json b/fixtures/mre_raw_2020_from_api.json new file mode 100644 index 0000000..6dd5783 --- /dev/null +++ b/fixtures/mre_raw_2020_from_api.json @@ -0,0 +1 @@ +{"years":[{"year":"2020","total":2602,"range":{"start":"2020-01-01","end":"2020-12-31"}}],"contributions":[{"date":"2020-12-31","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-30","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-29","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-28","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-27","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-26","count":27,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-12-25","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-24","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-23","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-22","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-21","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-20","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-19","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-18","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-17","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-12-16","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-15","count":31,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-12-14","count":52,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-12-13","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-12-12","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-12-11","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-10","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-12-09","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-12-08","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-07","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-06","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-05","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-04","count":28,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-12-03","count":20,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-12-02","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-01","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-30","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-29","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-28","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-27","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-26","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-25","count":29,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-11-24","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-23","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-22","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-21","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-11-20","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-19","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-18","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-17","count":17,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-11-16","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-15","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-11-14","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-11-13","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-12","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-11","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-10","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-09","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-08","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-07","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-06","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-05","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-04","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-11-03","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-11-02","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-01","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-10-31","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-10-30","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-29","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-28","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-27","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-26","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-25","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-24","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-23","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-22","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-21","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-20","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-19","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-18","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-17","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-10-16","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-15","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-14","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-13","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-12","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-11","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-10","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-09","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-08","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-10-07","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-06","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-05","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-04","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-03","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-10-02","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-01","count":18,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-30","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-29","count":21,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-28","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-27","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-26","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-25","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-24","count":22,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-23","count":20,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-22","count":19,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-21","count":25,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-09-20","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-19","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-18","count":33,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-09-17","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-16","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-15","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-14","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-13","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-12","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-11","count":22,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-10","count":14,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-09","count":14,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-08","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-07","count":18,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-06","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-05","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-04","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-03","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-02","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-01","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-31","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-30","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-29","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-28","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-27","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-26","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-25","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-24","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-23","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-22","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-21","count":17,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-08-20","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-19","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-18","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-17","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-16","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-08-15","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-08-14","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-13","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-12","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-11","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-10","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-08-09","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-08","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-07","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-06","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-05","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-04","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-03","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-02","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-08-01","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-31","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-30","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-29","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-28","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-27","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-26","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-25","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-24","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-23","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-22","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-21","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-20","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-19","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-18","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-17","count":26,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-07-16","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-15","count":23,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-07-14","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-13","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-12","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-11","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-10","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-09","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-08","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-07","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-06","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-05","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-04","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-03","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-02","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-01","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-30","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-29","count":19,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-06-28","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-27","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-26","count":24,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-06-25","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-24","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-06-23","count":32,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-06-22","count":17,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-06-21","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-06-20","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-19","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-18","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-17","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-06-16","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-06-15","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-14","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-06-13","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-06-12","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-11","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-10","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-09","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-08","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-07","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-06-06","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-05","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-04","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-03","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-06-02","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-06-01","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-31","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-30","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-29","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-28","count":30,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-05-27","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-05-26","count":14,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-05-25","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-24","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-05-23","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-22","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-05-21","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-05-20","count":22,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-05-19","count":17,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-05-18","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-05-17","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-16","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-15","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-14","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-13","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-12","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-11","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-10","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-09","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-08","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-07","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-06","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-05","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-04","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-03","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-02","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-01","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-04-30","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-29","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-28","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-27","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-26","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-25","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-24","count":19,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-04-23","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-22","count":26,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-04-21","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-20","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-04-19","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-18","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-04-17","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-16","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-15","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-04-14","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-13","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-12","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-11","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-10","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-09","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-08","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-07","count":25,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-04-06","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-04-05","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-04-04","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-04-03","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-04-02","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-01","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-03-31","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-30","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-29","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-28","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-03-27","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-26","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-25","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-24","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-03-23","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-03-22","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-21","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-20","count":14,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-03-19","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-18","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-17","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-16","count":20,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-03-15","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-14","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-13","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-12","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-03-11","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-10","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-09","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-08","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-03-07","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-03-06","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-05","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-04","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-03","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-03-02","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-01","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-29","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-02-28","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-27","count":21,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-02-26","count":24,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-02-25","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-24","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-23","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-02-22","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-02-21","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-20","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-19","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-18","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-17","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-16","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-15","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-14","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-13","count":21,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-02-12","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-11","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-10","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-09","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-02-08","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-07","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-06","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-02-05","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-04","count":18,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-02-03","count":18,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-02-02","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-01","count":31,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-01-31","count":14,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-30","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-29","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-28","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-27","count":23,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-01-26","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-25","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-24","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-23","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-22","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-21","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-20","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-19","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-18","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-17","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-16","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-15","count":25,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-01-14","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-13","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-12","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-11","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-10","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-09","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-08","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-07","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-06","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-05","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-04","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-03","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-02","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-01","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0}]} \ No newline at end of file diff --git a/tests/test_merger.rs b/tests/test_merger.rs new file mode 100644 index 0000000..46fbbe5 --- /dev/null +++ b/tests/test_merger.rs @@ -0,0 +1,26 @@ +use codeprints_analyzer::Merger; +use codeprints_analyzer::Timeline; +use std::fs; + +#[test] +fn test_intesity() { + + let input = fs::read_to_string("fixtures/mre_raw_2020_from_api.json").unwrap(); + let timeline: Timeline = serde_json::from_str(&input).unwrap(); + let mut merger = Merger::new(); + merger.merge_timeline(&timeline).unwrap(); + + let new_timeline = merger.timeline().unwrap(); + + for year in new_timeline.years { + let orig_year = timeline.years.iter().find(|y| y.year == year.year).unwrap(); + assert_eq!(year.total, orig_year.total); + } + + for contribution in new_timeline.contributions { + let orig_contribution = timeline.contributions.iter().find(|c| c.date == contribution.date).unwrap(); + assert_eq!(contribution.count, orig_contribution.count); + assert_eq!(contribution.color, orig_contribution.color); + assert_eq!(contribution.intensity, orig_contribution.intensity); + } +} From 6653dcad88d15819c4f90edb59b069fb9f77ad31 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Mon, 15 Mar 2021 01:40:25 +0100 Subject: [PATCH 45/50] Add timestamp --- src/bin/analyzer/main.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/bin/analyzer/main.rs b/src/bin/analyzer/main.rs index 740ee52..eeb1f5a 100644 --- a/src/bin/analyzer/main.rs +++ b/src/bin/analyzer/main.rs @@ -16,11 +16,18 @@ use codeprints_analyzer::Parser; use codeprints_analyzer::Timeline; use glob::glob; use std::fs; +use std::time::SystemTime; use structopt::StructOpt; mod options; use options::Command; +fn timestamp() -> Result { + Ok(SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH)? + .as_secs()) +} + fn write(timeline: &Timeline, output_file: &str) -> Result<()> { let output = serde_json::to_string_pretty(&timeline)?; fs::write(output_file, output)?; @@ -53,7 +60,10 @@ fn main() -> Result<()> { let timeline = parser.parse()?; let sha = git::sha()?; - write(&timeline, &format!("codeprints_{}.json", sha))?; + write( + &timeline, + &format!("codeprints_{}_{}.json", sha, timestamp()?), + )?; } Command::Merge {} => { // Find all `codeprints*.json` files in the current directory @@ -70,7 +80,10 @@ fn main() -> Result<()> { Err(e) => println!("{:?}", e), } } - write(&merger.timeline()?, "codeprints_merged.json")?; + write( + &merger.timeline()?, + &format!("merged_codeprints_{}.json", timestamp()?), + )?; } }; Ok(()) From 231ef0ee7d62348d1c472a8d1561f6562da903ae Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Mon, 15 Mar 2021 14:36:08 +0100 Subject: [PATCH 46/50] formatting --- fixtures/mre_raw_2020_from_api.json | 2211 ++++++++++++++++++++++++++- 1 file changed, 2210 insertions(+), 1 deletion(-) diff --git a/fixtures/mre_raw_2020_from_api.json b/fixtures/mre_raw_2020_from_api.json index 6dd5783..3aa5f92 100644 --- a/fixtures/mre_raw_2020_from_api.json +++ b/fixtures/mre_raw_2020_from_api.json @@ -1 +1,2210 @@ -{"years":[{"year":"2020","total":2602,"range":{"start":"2020-01-01","end":"2020-12-31"}}],"contributions":[{"date":"2020-12-31","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-30","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-29","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-28","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-27","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-26","count":27,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-12-25","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-24","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-23","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-22","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-21","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-20","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-19","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-18","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-12-17","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-12-16","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-15","count":31,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-12-14","count":52,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-12-13","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-12-12","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-12-11","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-10","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-12-09","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-12-08","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-07","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-06","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-05","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-04","count":28,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-12-03","count":20,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-12-02","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-12-01","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-30","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-29","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-28","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-27","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-26","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-25","count":29,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-11-24","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-23","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-22","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-21","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-11-20","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-19","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-18","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-17","count":17,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-11-16","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-15","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-11-14","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-11-13","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-12","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-11","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-10","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-09","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-08","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-07","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-06","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-11-05","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-04","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-11-03","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-11-02","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-11-01","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-10-31","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-10-30","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-29","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-28","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-27","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-26","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-25","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-24","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-23","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-22","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-21","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-20","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-19","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-18","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-17","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-10-16","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-15","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-14","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-13","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-12","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-11","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-10","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-09","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-08","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-10-07","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-06","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-10-05","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-04","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-03","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-10-02","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-10-01","count":18,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-30","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-29","count":21,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-28","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-27","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-26","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-25","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-24","count":22,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-23","count":20,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-22","count":19,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-21","count":25,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-09-20","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-19","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-18","count":33,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-09-17","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-16","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-15","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-14","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-13","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-12","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-11","count":22,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-10","count":14,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-09","count":14,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-08","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-07","count":18,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-09-06","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-05","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-04","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-03","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-09-02","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-09-01","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-31","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-30","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-29","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-28","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-27","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-26","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-25","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-24","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-23","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-22","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-21","count":17,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-08-20","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-19","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-18","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-17","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-16","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-08-15","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-08-14","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-13","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-12","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-11","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-10","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-08-09","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-08","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-07","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-06","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-05","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-08-04","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-03","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-08-02","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-08-01","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-31","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-30","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-29","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-28","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-27","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-26","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-25","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-24","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-23","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-22","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-21","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-20","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-19","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-18","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-17","count":26,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-07-16","count":15,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-15","count":23,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-07-14","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-13","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-12","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-11","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-10","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-09","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-08","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-07","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-07-06","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-05","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-04","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-07-03","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-02","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-07-01","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-30","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-29","count":19,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-06-28","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-27","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-26","count":24,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-06-25","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-24","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-06-23","count":32,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-06-22","count":17,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-06-21","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-06-20","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-19","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-18","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-17","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-06-16","count":10,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-06-15","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-14","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-06-13","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-06-12","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-11","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-10","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-09","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-08","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-07","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-06-06","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-05","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-04","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-06-03","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-06-02","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-06-01","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-31","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-30","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-29","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-28","count":30,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-05-27","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-05-26","count":14,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-05-25","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-24","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-05-23","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-22","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-05-21","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-05-20","count":22,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-05-19","count":17,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-05-18","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-05-17","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-16","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-15","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-14","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-13","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-12","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-11","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-10","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-09","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-08","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-07","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-06","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-05","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-04","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-03","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-05-02","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-05-01","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-04-30","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-29","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-28","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-27","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-26","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-25","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-24","count":19,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-04-23","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-22","count":26,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-04-21","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-20","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-04-19","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-18","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-04-17","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-16","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-15","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-04-14","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-13","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-12","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-11","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-10","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-09","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-08","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-07","count":25,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-04-06","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-04-05","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-04-04","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-04-03","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-04-02","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-04-01","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-03-31","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-30","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-29","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-28","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-03-27","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-26","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-25","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-24","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-03-23","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-03-22","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-21","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-20","count":14,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-03-19","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-18","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-17","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-16","count":20,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-03-15","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-14","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-13","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-12","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-03-11","count":7,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-10","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-09","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-08","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-03-07","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-03-06","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-05","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-04","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-03","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-03-02","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-03-01","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-29","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-02-28","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-27","count":21,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-02-26","count":24,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-02-25","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-24","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-23","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-02-22","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-02-21","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-20","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-19","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-18","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-17","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-16","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-15","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-14","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-13","count":21,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-02-12","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-11","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-10","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-09","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-02-08","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-07","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-06","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-02-05","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-04","count":18,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-02-03","count":18,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-02-02","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-02-01","count":31,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-01-31","count":14,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-30","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-29","count":6,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-28","count":11,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-27","count":23,"color":"var(--color-calendar-graph-day-l1-bg)","intensity":3},{"date":"2020-01-26","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-25","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-24","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-23","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-22","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-21","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-20","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-19","count":12,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-18","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-17","count":8,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-16","count":9,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-15","count":25,"color":"var(--color-calendar-graph-day-bg)","intensity":4},{"date":"2020-01-14","count":16,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-13","count":4,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-12","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-11","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-10","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-09","count":1,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-08","count":3,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-07","count":5,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-06","count":2,"color":"var(--color-calendar-graph-day-l3-bg)","intensity":1},{"date":"2020-01-05","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-04","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-03","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0},{"date":"2020-01-02","count":13,"color":"var(--color-calendar-graph-day-l2-bg)","intensity":2},{"date":"2020-01-01","count":0,"color":"var(--color-calendar-graph-day-l4-bg)","intensity":0}]} \ No newline at end of file +{ + "years": [ + { + "year": "2020", + "total": 2602, + "range": { + "start": "2020-01-01", + "end": "2020-12-31" + } + } + ], + "contributions": [ + { + "date": "2020-12-31", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-12-30", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-12-29", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-12-28", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-12-27", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-26", + "count": 27, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-12-25", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-24", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-12-23", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-22", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-21", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-20", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-19", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-12-18", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-12-17", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-12-16", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-15", + "count": 31, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-12-14", + "count": 52, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-12-13", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-12-12", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-12-11", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-10", + "count": 10, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-12-09", + "count": 10, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-12-08", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-07", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-06", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-05", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-04", + "count": 28, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-12-03", + "count": 20, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-12-02", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-12-01", + "count": 11, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-11-30", + "count": 10, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-11-29", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-11-28", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-27", + "count": 16, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-11-26", + "count": 16, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-11-25", + "count": 29, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-11-24", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-23", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-22", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-21", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-11-20", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-19", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-18", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-17", + "count": 17, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-11-16", + "count": 9, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-11-15", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-11-14", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-11-13", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-12", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-11-11", + "count": 16, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-11-10", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-09", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-08", + "count": 10, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-11-07", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-06", + "count": 11, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-11-05", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-04", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-11-03", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-11-02", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-11-01", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-10-31", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-10-30", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-29", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-28", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-27", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-10-26", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-10-25", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-24", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-23", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-22", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-21", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-10-20", + "count": 9, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-10-19", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-18", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-17", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-10-16", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-15", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-14", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-13", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-12", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-11", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-10", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-09", + "count": 15, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-10-08", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-10-07", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-06", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-10-05", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-10-04", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-10-03", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-10-02", + "count": 15, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-10-01", + "count": 18, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-09-30", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-09-29", + "count": 21, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-09-28", + "count": 9, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-09-27", + "count": 15, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-09-26", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-09-25", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-09-24", + "count": 22, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-09-23", + "count": 20, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-09-22", + "count": 19, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-09-21", + "count": 25, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-09-20", + "count": 15, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-09-19", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-09-18", + "count": 33, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-09-17", + "count": 16, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-09-16", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-09-15", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-09-14", + "count": 11, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-09-13", + "count": 11, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-09-12", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-09-11", + "count": 22, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-09-10", + "count": 14, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-09-09", + "count": 14, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-09-08", + "count": 15, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-09-07", + "count": 18, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-09-06", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-09-05", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-09-04", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-09-03", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-09-02", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-09-01", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-31", + "count": 9, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-08-30", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-29", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-28", + "count": 10, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-08-27", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-26", + "count": 15, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-08-25", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-08-24", + "count": 10, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-08-23", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-22", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-21", + "count": 17, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-08-20", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-08-19", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-08-18", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-17", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-16", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-08-15", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-08-14", + "count": 11, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-08-13", + "count": 15, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-08-12", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-11", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-10", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-08-09", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-08-08", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-07", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-06", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-05", + "count": 10, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-08-04", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-03", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-08-02", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-08-01", + "count": 10, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-07-31", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-30", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-29", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-07-28", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-27", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-26", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-07-25", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-07-24", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-07-23", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-22", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-21", + "count": 11, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-07-20", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-07-19", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-18", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-07-17", + "count": 26, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-07-16", + "count": 15, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-07-15", + "count": 23, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-07-14", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-13", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-12", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-11", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-07-10", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-07-09", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-08", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-07", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-07-06", + "count": 9, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-07-05", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-07-04", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-07-03", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-07-02", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-07-01", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-30", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-29", + "count": 19, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-06-28", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-27", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-26", + "count": 24, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-06-25", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-24", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-06-23", + "count": 32, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-06-22", + "count": 17, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-06-21", + "count": 10, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-06-20", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-19", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-18", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-17", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-06-16", + "count": 10, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-06-15", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-14", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-06-13", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-06-12", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-11", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-10", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-09", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-08", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-07", + "count": 9, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-06-06", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-05", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-04", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-06-03", + "count": 11, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-06-02", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-06-01", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-05-31", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-05-30", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-05-29", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-05-28", + "count": 30, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-05-27", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-05-26", + "count": 14, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-05-25", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-05-24", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-05-23", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-05-22", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-05-21", + "count": 16, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-05-20", + "count": 22, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-05-19", + "count": 17, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-05-18", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-05-17", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-05-16", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-05-15", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-05-14", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-05-13", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-05-12", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-05-11", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-05-10", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-05-09", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-05-08", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-05-07", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-05-06", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-05-05", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-05-04", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-05-03", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-05-02", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-05-01", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-04-30", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-29", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-28", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-27", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-26", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-25", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-24", + "count": 19, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-04-23", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-22", + "count": 26, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-04-21", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-20", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-04-19", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-18", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-04-17", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-16", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-15", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-04-14", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-13", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-12", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-11", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-10", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-09", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-08", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-07", + "count": 25, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-04-06", + "count": 9, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-04-05", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-04-04", + "count": 11, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-04-03", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-04-02", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-04-01", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-03-31", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-30", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-29", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-28", + "count": 16, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-03-27", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-26", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-25", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-24", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-03-23", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-03-22", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-21", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-20", + "count": 14, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-03-19", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-18", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-17", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-16", + "count": 20, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-03-15", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-14", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-13", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-12", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-03-11", + "count": 7, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-10", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-09", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-08", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-03-07", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-03-06", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-05", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-04", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-03", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-03-02", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-03-01", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-29", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-02-28", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-27", + "count": 21, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-02-26", + "count": 24, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-02-25", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-24", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-23", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-02-22", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-02-21", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-20", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-19", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-18", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-17", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-16", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-15", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-14", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-13", + "count": 21, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-02-12", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-11", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-10", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-09", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-02-08", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-07", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-06", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-02-05", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-04", + "count": 18, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-02-03", + "count": 18, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-02-02", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-02-01", + "count": 31, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-01-31", + "count": 14, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-01-30", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-29", + "count": 6, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-28", + "count": 11, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-01-27", + "count": 23, + "color": "var(--color-calendar-graph-day-l1-bg)", + "intensity": 3 + }, + { + "date": "2020-01-26", + "count": 16, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-01-25", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-01-24", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-01-23", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-01-22", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-21", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-20", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-19", + "count": 12, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-01-18", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-01-17", + "count": 8, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-16", + "count": 9, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-01-15", + "count": 25, + "color": "var(--color-calendar-graph-day-bg)", + "intensity": 4 + }, + { + "date": "2020-01-14", + "count": 16, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-01-13", + "count": 4, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-12", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-11", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-01-10", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-09", + "count": 1, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-08", + "count": 3, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-07", + "count": 5, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-06", + "count": 2, + "color": "var(--color-calendar-graph-day-l3-bg)", + "intensity": 1 + }, + { + "date": "2020-01-05", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-01-04", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-01-03", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + }, + { + "date": "2020-01-02", + "count": 13, + "color": "var(--color-calendar-graph-day-l2-bg)", + "intensity": 2 + }, + { + "date": "2020-01-01", + "count": 0, + "color": "var(--color-calendar-graph-day-l4-bg)", + "intensity": 0 + } + ] +} \ No newline at end of file From 07054b37a69e969448133952268a0d7353755967 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Mon, 15 Mar 2021 14:36:37 +0100 Subject: [PATCH 47/50] changed output of merge to merged_codeprints_*.json --- src/bin/analyzer/options.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/analyzer/options.rs b/src/bin/analyzer/options.rs index 396208e..8ebed26 100644 --- a/src/bin/analyzer/options.rs +++ b/src/bin/analyzer/options.rs @@ -25,6 +25,6 @@ pub enum Command { #[structopt(alias = "since", long)] after: Option, }, - /// Merge all codeprints*.json to one file named codeprints_merged.json + /// Merge all codeprints*.json to one file named merged_codeprints_.json Merge {}, } From e80175cb57f4cd9990ff6170ff7e560db56ccc06 Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Mon, 15 Mar 2021 14:36:40 +0100 Subject: [PATCH 48/50] formatting --- tests/test_merger.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/test_merger.rs b/tests/test_merger.rs index 46fbbe5..8edc267 100644 --- a/tests/test_merger.rs +++ b/tests/test_merger.rs @@ -4,7 +4,6 @@ use std::fs; #[test] fn test_intesity() { - let input = fs::read_to_string("fixtures/mre_raw_2020_from_api.json").unwrap(); let timeline: Timeline = serde_json::from_str(&input).unwrap(); let mut merger = Merger::new(); @@ -18,7 +17,15 @@ fn test_intesity() { } for contribution in new_timeline.contributions { - let orig_contribution = timeline.contributions.iter().find(|c| c.date == contribution.date).unwrap(); + let orig_contribution = timeline + .contributions + .iter() + .find(|c| c.date == contribution.date) + .unwrap(); + + println!("contribution: {:?}", contribution); + println!("orig: {:?}", orig_contribution); + assert_eq!(contribution.count, orig_contribution.count); assert_eq!(contribution.color, orig_contribution.color); assert_eq!(contribution.intensity, orig_contribution.intensity); From 6f4f1758b424c36a7f0f71fcae082d642a968eb0 Mon Sep 17 00:00:00 2001 From: Wolfgang Gassler Date: Tue, 16 Mar 2021 15:08:41 +0100 Subject: [PATCH 49/50] corrected fixture after fixing the api --- fixtures/mre_raw_2020_from_api.json | 4418 +++++++++++++-------------- 1 file changed, 2209 insertions(+), 2209 deletions(-) diff --git a/fixtures/mre_raw_2020_from_api.json b/fixtures/mre_raw_2020_from_api.json index 3aa5f92..5838bf4 100644 --- a/fixtures/mre_raw_2020_from_api.json +++ b/fixtures/mre_raw_2020_from_api.json @@ -1,2210 +1,2210 @@ { - "years": [ - { - "year": "2020", - "total": 2602, - "range": { - "start": "2020-01-01", - "end": "2020-12-31" - } - } - ], - "contributions": [ - { - "date": "2020-12-31", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-12-30", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-12-29", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-12-28", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-12-27", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-26", - "count": 27, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-12-25", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-24", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-12-23", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-22", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-21", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-20", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-19", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-12-18", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-12-17", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-12-16", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-15", - "count": 31, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-12-14", - "count": 52, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-12-13", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-12-12", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-12-11", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-10", - "count": 10, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-12-09", - "count": 10, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-12-08", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-07", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-06", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-05", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-04", - "count": 28, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-12-03", - "count": 20, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-12-02", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-12-01", - "count": 11, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-11-30", - "count": 10, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-11-29", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-11-28", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-27", - "count": 16, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-11-26", - "count": 16, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-11-25", - "count": 29, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-11-24", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-23", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-22", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-21", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-11-20", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-19", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-18", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-17", - "count": 17, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-11-16", - "count": 9, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-11-15", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-11-14", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-11-13", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-12", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-11-11", - "count": 16, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-11-10", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-09", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-08", - "count": 10, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-11-07", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-06", - "count": 11, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-11-05", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-04", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-11-03", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-11-02", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-11-01", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-10-31", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-10-30", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-29", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-28", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-27", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-10-26", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-10-25", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-24", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-23", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-22", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-21", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-10-20", - "count": 9, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-10-19", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-18", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-17", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-10-16", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-15", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-14", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-13", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-12", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-11", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-10", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-09", - "count": 15, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-10-08", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-10-07", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-06", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-10-05", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-10-04", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-10-03", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-10-02", - "count": 15, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-10-01", - "count": 18, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-09-30", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-09-29", - "count": 21, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-09-28", - "count": 9, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-09-27", - "count": 15, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-09-26", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-09-25", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-09-24", - "count": 22, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-09-23", - "count": 20, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-09-22", - "count": 19, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-09-21", - "count": 25, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-09-20", - "count": 15, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-09-19", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-09-18", - "count": 33, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-09-17", - "count": 16, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-09-16", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-09-15", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-09-14", - "count": 11, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-09-13", - "count": 11, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-09-12", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-09-11", - "count": 22, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-09-10", - "count": 14, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-09-09", - "count": 14, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-09-08", - "count": 15, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-09-07", - "count": 18, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-09-06", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-09-05", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-09-04", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-09-03", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-09-02", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-09-01", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-31", - "count": 9, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-08-30", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-29", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-28", - "count": 10, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-08-27", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-26", - "count": 15, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-08-25", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-08-24", - "count": 10, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-08-23", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-22", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-21", - "count": 17, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-08-20", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-08-19", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-08-18", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-17", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-16", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-08-15", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-08-14", - "count": 11, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-08-13", - "count": 15, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-08-12", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-11", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-10", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-08-09", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-08-08", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-07", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-06", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-05", - "count": 10, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-08-04", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-03", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-08-02", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-08-01", - "count": 10, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-07-31", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-30", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-29", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-07-28", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-27", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-26", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-07-25", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-07-24", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-07-23", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-22", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-21", - "count": 11, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-07-20", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-07-19", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-18", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-07-17", - "count": 26, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-07-16", - "count": 15, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-07-15", - "count": 23, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-07-14", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-13", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-12", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-11", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-07-10", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-07-09", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-08", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-07", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-07-06", - "count": 9, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-07-05", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-07-04", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-07-03", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-07-02", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-07-01", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-30", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-29", - "count": 19, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-06-28", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-27", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-26", - "count": 24, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-06-25", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-24", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-06-23", - "count": 32, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-06-22", - "count": 17, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-06-21", - "count": 10, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-06-20", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-19", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-18", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-17", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-06-16", - "count": 10, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-06-15", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-14", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-06-13", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-06-12", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-11", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-10", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-09", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-08", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-07", - "count": 9, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-06-06", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-05", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-04", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-06-03", - "count": 11, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-06-02", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-06-01", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-05-31", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-05-30", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-05-29", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-05-28", - "count": 30, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-05-27", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-05-26", - "count": 14, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-05-25", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-05-24", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-05-23", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-05-22", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-05-21", - "count": 16, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-05-20", - "count": 22, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-05-19", - "count": 17, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-05-18", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-05-17", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-05-16", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-05-15", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-05-14", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-05-13", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-05-12", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-05-11", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-05-10", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-05-09", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-05-08", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-05-07", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-05-06", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-05-05", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-05-04", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-05-03", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-05-02", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-05-01", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-04-30", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-29", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-28", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-27", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-26", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-25", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-24", - "count": 19, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-04-23", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-22", - "count": 26, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-04-21", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-20", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-04-19", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-18", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-04-17", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-16", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-15", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-04-14", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-13", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-12", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-11", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-10", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-09", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-08", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-07", - "count": 25, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-04-06", - "count": 9, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-04-05", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-04-04", - "count": 11, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-04-03", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-04-02", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-04-01", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-03-31", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-30", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-29", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-28", - "count": 16, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-03-27", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-26", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-25", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-24", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-03-23", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-03-22", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-21", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-20", - "count": 14, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-03-19", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-18", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-17", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-16", - "count": 20, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-03-15", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-14", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-13", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-12", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-03-11", - "count": 7, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-10", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-09", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-08", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-03-07", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-03-06", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-05", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-04", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-03", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-03-02", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-03-01", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-29", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-02-28", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-27", - "count": 21, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-02-26", - "count": 24, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-02-25", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-24", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-23", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-02-22", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-02-21", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-20", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-19", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-18", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-17", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-16", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-15", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-14", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-13", - "count": 21, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-02-12", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-11", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-10", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-09", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-02-08", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-07", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-06", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-02-05", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-04", - "count": 18, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-02-03", - "count": 18, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-02-02", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-02-01", - "count": 31, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-01-31", - "count": 14, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-01-30", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-29", - "count": 6, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-28", - "count": 11, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-01-27", - "count": 23, - "color": "var(--color-calendar-graph-day-l1-bg)", - "intensity": 3 - }, - { - "date": "2020-01-26", - "count": 16, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-01-25", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-01-24", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-01-23", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-01-22", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-21", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-20", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-19", - "count": 12, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-01-18", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-01-17", - "count": 8, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-16", - "count": 9, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-01-15", - "count": 25, - "color": "var(--color-calendar-graph-day-bg)", - "intensity": 4 - }, - { - "date": "2020-01-14", - "count": 16, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-01-13", - "count": 4, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-12", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-11", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-01-10", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-09", - "count": 1, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-08", - "count": 3, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-07", - "count": 5, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-06", - "count": 2, - "color": "var(--color-calendar-graph-day-l3-bg)", - "intensity": 1 - }, - { - "date": "2020-01-05", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-01-04", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-01-03", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - }, - { - "date": "2020-01-02", - "count": 13, - "color": "var(--color-calendar-graph-day-l2-bg)", - "intensity": 2 - }, - { - "date": "2020-01-01", - "count": 0, - "color": "var(--color-calendar-graph-day-l4-bg)", - "intensity": 0 - } - ] -} \ No newline at end of file + "contributions" : [ + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-12-31", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-12-30", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-12-29", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-12-28", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-12-27", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 27, + "date" : "2020-12-26", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-12-25", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-12-24", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-12-23", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-12-22", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-12-21", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-12-20", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-12-19", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-12-18", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-12-17", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-12-16", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 31, + "date" : "2020-12-15", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 52, + "date" : "2020-12-14", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-12-13", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-12-12", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-12-11", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 10, + "date" : "2020-12-10", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 10, + "date" : "2020-12-09", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-12-08", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-12-07", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-12-06", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-12-05", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 28, + "date" : "2020-12-04", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 20, + "date" : "2020-12-03", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-12-02", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 11, + "date" : "2020-12-01", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 10, + "date" : "2020-11-30", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-11-29", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-11-28", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 16, + "date" : "2020-11-27", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 16, + "date" : "2020-11-26", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 29, + "date" : "2020-11-25", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-11-24", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-11-23", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-11-22", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-11-21", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-11-20", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-11-19", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-11-18", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 17, + "date" : "2020-11-17", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 9, + "date" : "2020-11-16", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-11-15", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-11-14", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-11-13", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-11-12", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 16, + "date" : "2020-11-11", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-11-10", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-11-09", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 10, + "date" : "2020-11-08", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-11-07", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 11, + "date" : "2020-11-06", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-11-05", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-11-04", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-11-03", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-11-02", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-11-01", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-10-31", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-10-30", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-10-29", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-10-28", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-10-27", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-10-26", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-10-25", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-10-24", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-10-23", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-10-22", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-10-21", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 9, + "date" : "2020-10-20", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-10-19", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-10-18", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-10-17", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-10-16", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-10-15", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-10-14", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-10-13", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-10-12", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-10-11", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-10-10", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 15, + "date" : "2020-10-09", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-10-08", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-10-07", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-10-06", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-10-05", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-10-04", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-10-03", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 15, + "date" : "2020-10-02", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 18, + "date" : "2020-10-01", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-09-30", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 21, + "date" : "2020-09-29", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 9, + "date" : "2020-09-28", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 15, + "date" : "2020-09-27", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-09-26", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-09-25", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 22, + "date" : "2020-09-24", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 20, + "date" : "2020-09-23", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 19, + "date" : "2020-09-22", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 25, + "date" : "2020-09-21", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 15, + "date" : "2020-09-20", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-09-19", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 33, + "date" : "2020-09-18", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 16, + "date" : "2020-09-17", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-09-16", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-09-15", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 11, + "date" : "2020-09-14", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 11, + "date" : "2020-09-13", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-09-12", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 22, + "date" : "2020-09-11", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 14, + "date" : "2020-09-10", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 14, + "date" : "2020-09-09", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 15, + "date" : "2020-09-08", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 18, + "date" : "2020-09-07", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-09-06", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-09-05", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-09-04", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-09-03", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-09-02", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-09-01", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 9, + "date" : "2020-08-31", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-08-30", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-08-29", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 10, + "date" : "2020-08-28", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-08-27", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 15, + "date" : "2020-08-26", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-08-25", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 10, + "date" : "2020-08-24", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-08-23", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-08-22", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 17, + "date" : "2020-08-21", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-08-20", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-08-19", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-08-18", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-08-17", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-08-16", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-08-15", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 11, + "date" : "2020-08-14", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 15, + "date" : "2020-08-13", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-08-12", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-08-11", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-08-10", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-08-09", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-08-08", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-08-07", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-08-06", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 10, + "date" : "2020-08-05", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-08-04", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-08-03", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-08-02", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 10, + "date" : "2020-08-01", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-07-31", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-07-30", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-07-29", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-07-28", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-07-27", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-07-26", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-07-25", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-07-24", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-07-23", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-07-22", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 11, + "date" : "2020-07-21", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-07-20", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-07-19", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-07-18", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 26, + "date" : "2020-07-17", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 15, + "date" : "2020-07-16", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 23, + "date" : "2020-07-15", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-07-14", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-07-13", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-07-12", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-07-11", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-07-10", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-07-09", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-07-08", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-07-07", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 9, + "date" : "2020-07-06", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-07-05", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-07-04", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-07-03", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-07-02", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-07-01", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-06-30", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 19, + "date" : "2020-06-29", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-06-28", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-06-27", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 24, + "date" : "2020-06-26", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-06-25", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-06-24", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 32, + "date" : "2020-06-23", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 17, + "date" : "2020-06-22", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 10, + "date" : "2020-06-21", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-06-20", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-06-19", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-06-18", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-06-17", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 10, + "date" : "2020-06-16", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-06-15", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-06-14", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-06-13", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-06-12", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-06-11", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-06-10", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-06-09", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-06-08", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 9, + "date" : "2020-06-07", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-06-06", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-06-05", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-06-04", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 11, + "date" : "2020-06-03", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-06-02", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-06-01", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-05-31", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-05-30", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-05-29", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 30, + "date" : "2020-05-28", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-05-27", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 14, + "date" : "2020-05-26", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-05-25", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-05-24", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-05-23", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-05-22", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 16, + "date" : "2020-05-21", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 22, + "date" : "2020-05-20", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 17, + "date" : "2020-05-19", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-05-18", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-05-17", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-05-16", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-05-15", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-05-14", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-05-13", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-05-12", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-05-11", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-05-10", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-05-09", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-05-08", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-05-07", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-05-06", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-05-05", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-05-04", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-05-03", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-05-02", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-05-01", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-04-30", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-04-29", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-04-28", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-04-27", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-04-26", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-04-25", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 19, + "date" : "2020-04-24", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-04-23", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 26, + "date" : "2020-04-22", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-04-21", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-04-20", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-04-19", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-04-18", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-04-17", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-04-16", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-04-15", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-04-14", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-04-13", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-04-12", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-04-11", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-04-10", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-04-09", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-04-08", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 25, + "date" : "2020-04-07", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 9, + "date" : "2020-04-06", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-04-05", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 11, + "date" : "2020-04-04", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-04-03", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-04-02", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-04-01", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-03-31", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-03-30", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-03-29", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 16, + "date" : "2020-03-28", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-03-27", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-03-26", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-03-25", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-03-24", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-03-23", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-03-22", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-03-21", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 14, + "date" : "2020-03-20", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-03-19", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-03-18", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-03-17", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 20, + "date" : "2020-03-16", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-03-15", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-03-14", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-03-13", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-03-12", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 7, + "date" : "2020-03-11", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-03-10", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-03-09", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-03-08", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-03-07", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-03-06", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-03-05", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-03-04", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-03-03", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-03-02", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-03-01", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-02-29", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-02-28", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 21, + "date" : "2020-02-27", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 24, + "date" : "2020-02-26", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-02-25", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-02-24", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-02-23", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-02-22", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-02-21", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-02-20", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-02-19", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-02-18", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-02-17", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-02-16", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-02-15", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-02-14", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 21, + "date" : "2020-02-13", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-02-12", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-02-11", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-02-10", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-02-09", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-02-08", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-02-07", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-02-06", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-02-05", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 18, + "date" : "2020-02-04", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 18, + "date" : "2020-02-03", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-02-02", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 31, + "date" : "2020-02-01", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 14, + "date" : "2020-01-31", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-01-30", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 6, + "date" : "2020-01-29", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 11, + "date" : "2020-01-28", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l3-bg)", + "count" : 23, + "date" : "2020-01-27", + "intensity" : 3 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 16, + "date" : "2020-01-26", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-01-25", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-01-24", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-01-23", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-01-22", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-01-21", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-01-20", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 12, + "date" : "2020-01-19", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-01-18", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 8, + "date" : "2020-01-17", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 9, + "date" : "2020-01-16", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l4-bg)", + "count" : 25, + "date" : "2020-01-15", + "intensity" : 4 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 16, + "date" : "2020-01-14", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 4, + "date" : "2020-01-13", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-01-12", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-01-11", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-01-10", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 1, + "date" : "2020-01-09", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 3, + "date" : "2020-01-08", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 5, + "date" : "2020-01-07", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-l1-bg)", + "count" : 2, + "date" : "2020-01-06", + "intensity" : 1 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-01-05", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-01-04", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-01-03", + "intensity" : 0 + }, + { + "color" : "var(--color-calendar-graph-day-l2-bg)", + "count" : 13, + "date" : "2020-01-02", + "intensity" : 2 + }, + { + "color" : "var(--color-calendar-graph-day-bg)", + "count" : 0, + "date" : "2020-01-01", + "intensity" : 0 + } + ], + "years" : [ + { + "range" : { + "end" : "2020-12-31", + "start" : "2020-01-01" + }, + "total" : 2602, + "year" : "2020" + } + ] +} From 6c51be23e9de982002de9c2c9ec61a3778f26aaf Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 18 Mar 2021 01:07:20 +0100 Subject: [PATCH 50/50] fix typo in intensity string --- src/parser.rs | 8 ++++---- tests/test_merger.rs | 17 +++++++---------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 4900418..f01b37e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -79,10 +79,10 @@ fn get_intensity(quartiles: &[usize], commits: usize) -> usize { fn map_color(intensity: usize) -> String { match intensity { - 1 => "var(--color-calendar-graph-day-L1-bg)", - 2 => "var(--color-calendar-graph-day-L2-bg)", - 3 => "var(--color-calendar-graph-day-L3-bg)", - 4 => "var(--color-calendar-graph-day-L4-bg)", + 1 => "var(--color-calendar-graph-day-l1-bg)", + 2 => "var(--color-calendar-graph-day-l2-bg)", + 3 => "var(--color-calendar-graph-day-l3-bg)", + 4 => "var(--color-calendar-graph-day-l4-bg)", _ => "var(--color-calendar-graph-day-bg)", } .to_string() diff --git a/tests/test_merger.rs b/tests/test_merger.rs index 8edc267..12c2c02 100644 --- a/tests/test_merger.rs +++ b/tests/test_merger.rs @@ -3,7 +3,7 @@ use codeprints_analyzer::Timeline; use std::fs; #[test] -fn test_intesity() { +fn test_intensity() { let input = fs::read_to_string("fixtures/mre_raw_2020_from_api.json").unwrap(); let timeline: Timeline = serde_json::from_str(&input).unwrap(); let mut merger = Merger::new(); @@ -16,18 +16,15 @@ fn test_intesity() { assert_eq!(year.total, orig_year.total); } - for contribution in new_timeline.contributions { - let orig_contribution = timeline + for actual in new_timeline.contributions { + let expected = timeline .contributions .iter() - .find(|c| c.date == contribution.date) + .find(|c| c.date == actual.date) .unwrap(); - println!("contribution: {:?}", contribution); - println!("orig: {:?}", orig_contribution); - - assert_eq!(contribution.count, orig_contribution.count); - assert_eq!(contribution.color, orig_contribution.color); - assert_eq!(contribution.intensity, orig_contribution.intensity); + assert_eq!(actual.intensity, expected.intensity); + assert_eq!(actual.count, expected.count); + assert_eq!(actual.color, expected.color); } }