uvm_core 0.13.1

The core functionality for the unity version manager commandline client.
Documentation
use super::*;
use std::collections::BTreeMap;
use std::fs;
use std::io;
use std::path::PathBuf;
use crate::unity::hub::paths;
use log::warn;

use thiserror::Error;

#[derive(Error, Debug)]
pub enum UnityHashError {
    #[error("hash load error")]
    LoadError(#[from] reqwest::Error),

    #[error("failed to parse URL")]
    UrlError(#[from] reqwest::UrlError),

    #[error("failed to read hash from cache")]
    CacheError {
        #[from]
        source: std::io::Error
    },

    #[error("hash not available")]
    Other
}

type Result<T> = std::result::Result<T, UnityHashError>;

pub fn all_versions() -> Result<impl Iterator<Item = Version>> {
    let url = reqwest::Url::parse("https://unity-versions-service.herokuapp.com/").unwrap();
    let url = url.join("versions/")?;

    let versions: BTreeMap<Version, String> = reqwest::get(url)
        .and_then(|mut response| response.json())?;

    Ok(versions.into_iter().map(|(version, _)| version))
}

fn hash_from_service(version: &Version) -> Result<String> {
    debug!("fetch hash for version {} from versions service", version);
    let url = reqwest::Url::parse("https://unity-versions-service.herokuapp.com/").unwrap();
    let url = url
        .join("versions/")
        .and_then(|url| url.join(&format!("{}/", version)))
        .and_then(|url| url.join("hash"))?;

    let hash: String = reqwest::get(url)
        .and_then(|mut response| response.json())?;
    debug!("loaded hash {}", &hash);
    Ok(hash)
}

fn hash_from_cache(version: &Version) -> Result<String> {
    use std::io::Read;

    debug!("fetch hash for version {} from cache", version);
    let path = cache_file(version)?;
    let mut file = fs::File::open(&path)?;
    let mut hash = String::new();
    file.read_to_string(&mut hash)?;
    Ok(hash)
}

fn cache_file(version: &Version) -> io::Result<PathBuf> {
    paths::hash_cache_dir()
        .map(|p| p.join(&format!("{}.hash", version)))
        .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "Unable to fetch cache dir"))
}

fn cache_hash<H: AsRef<str>>(hash: H, version: &Version) -> io::Result<()> {
    use std::fs::DirBuilder;
    use std::io::Write;
    let hash = hash.as_ref();
    let path = cache_file(version)?;
    DirBuilder::new()
        .recursive(true)
        .create(&path.parent().unwrap())?;
    let mut file = fs::File::create(&path)?;
    file.write_all(hash.as_bytes())
}

pub fn hash_for_version(version: &Version) -> Result<String> {
    let versions: BTreeMap<Version, String> = serde_yaml::from_str(VERSIONS).unwrap_or_default();

    versions
        .get(version)
        .cloned()
        .ok_or_else(|| "not found")
        .or_else(|_| {
            debug!("hash for version {} not available in memory", version);
            hash_from_cache(version)
        }).or_else(|_| {
            debug!("hash for version {} not available in cache", version);
            hash_from_service(version).and_then(|hash| {
                cache_hash(&hash, version).unwrap_or_else(|err| {
                    warn!("unable to cache hash {} for version {}", &hash, version);
                    warn!("error: {}", err);
                });
                Ok(hash)
            })
        })
}

const VERSIONS: &str = "
2017.1.0b1: a29fc4a7eb25
2017.1.0b10: 94eaa37e21dd
2017.1.0b2: 5e138e18bf82
2017.1.0b3: 9393889e4fe6
2017.1.0b4: ab0150af3e1e
2017.1.0b5: e2f219641e2c
2017.1.0b6: 38ec4e48ade7
2017.1.0b7: 8a1ad67dc191
2017.1.0b8: 17011ab1b2e1
2017.1.0b9: a1e6a9071015
2017.1.0f1: 4d7fe18a2f34
2017.1.0f2: 66e9e4bfc850
2017.1.0f3: 472613c02cf7
2017.1.0p1: 2f459b492f3c
2017.1.0p2: 31954117ff6c
2017.1.0p3: 0f0686ba7d25
2017.1.0p5: de463fc61bac
2017.1.1f1: 5d30cf096e79
2017.1.1p1: 007fc09e806c
2017.1.1p2: b8e3f2d6c409
2017.1.1p3: 929150d2fa14
2017.1.1p4: 4b0ddcd3f6ad
2017.1.2f1: cc85bf6a8a04
2017.1.2p1: c2ed782bb21e
2017.1.2p2: eba6bfec1bb2
2017.1.2p3: 249a06fbaf10
2017.1.2p4: d597d0924185
2017.1.3f1: 574eeb502d14
2017.1.3p1: 02d73f71d3bd
2017.1.3p2: 744dab055778
2017.1.3p3: fc055e6cd68b
2017.1.3p4: 918e58443b8e
2017.1.4f1: 9fd71167a288
2017.1.4p1: \"644977348e46\"
2017.1.4p2: 490bad3999ec
2017.1.5f1: 9758a36cfaa6
2017.2.0b1: 1a1b26354326
2017.2.0b10: 6c4d42ddd191
2017.2.0b11: 614980c52f17
2017.2.0b2: a9976befbe0f
2017.2.0b3: 4c2ac554540c
2017.2.0b4: 0c51d4e28d7f
2017.2.0b5: 9b4733af38e7
2017.2.0b6: b6bf3c071fe7
2017.2.0b7: 4bc201a72e4a
2017.2.0b8: c5fc3ca9cbbf
2017.2.0b9: 95ec3a4d5d9d
2017.2.0f1: 35e55a2a85de
2017.2.0f2: 472de62575d5
2017.2.0f3: 46dda1414e51
2017.2.0p1: 24fd82ce573a
2017.2.0p2: dbc2eb12ac98
2017.2.0p3: 40117ac43b95
2017.2.0p4: 0c3a6a294e34
2017.2.1f1: 94bf3f9e6b5e
2017.2.1p1: edf5bdf50eb0
2017.2.1p2: 1dc514532f08
2017.2.1p3: 273860332f50
2017.2.1p4: 1992a1ed2d78
2017.2.2f1: 1f4e0f9b6a50
2017.2.2p1: 31794ac12ad1
2017.2.2p2: 32bc645ba6f6
2017.2.2p3: 7706f9f606ca
2017.2.2p4: a30add86d148
2017.2.3f1: 372229934efd
2017.2.3p1: b4bae9093154
2017.2.3p2: 21333da13d02
2017.2.3p3: 726d0db4eeac
2017.2.3p4: 2f2d0e6b4eb5
2017.2.4f1: f1557d1f61fd
2017.2.5f1: 588dc79c95ed
2017.3.0b1: bc2668834c45
2017.3.0b10: d1367129888f
2017.3.0b11: 8e840c60cd77
2017.3.0b2: ec6e8c8c3015
2017.3.0b3: 28dc7ce05bb9
2017.3.0b4: 4c1b6e48c9c9
2017.3.0b5: af76f56822bf
2017.3.0b6: 57ec95547059
2017.3.0b7: 93b5ce6f4b0f
2017.3.0b8: d2b3b1ff7201
2017.3.0b9: e18fe9bb4e54
2017.3.0f1: b84f5794ed91
2017.3.0f2: d3a5469e8c44
2017.3.0f3: a9f86dcd79df
2017.3.0p1: 4596dd67072f
2017.3.0p2: b91e4c5f54ad
2017.3.0p3: bfcbae508940
2017.3.0p4: 25a5860ad58d
2017.3.1f1: fc1d3344e6ea
2017.3.1p1: 6c5ba423732e
2017.3.1p2: fd9fec26f216
2017.3.1p3: a66397957d3b
2017.3.1p4: 7f25373c3e03
2017.4.0f1: b5bd171ee9ba
2017.4.10f1: f2cce2a5991f
2017.4.11f1: 8c6b8ef6d111
2017.4.12f1: b582b87345b1
2017.4.13f1: 6902ad48015d
2017.4.14f1: b28150134d55
2017.4.15f1: 5d485b4897a7
2017.4.16f1: 7f7bdd1ef02b
2017.4.17f1: 05307cddbb71
2017.4.18f1: a9236f402e28
2017.4.19f1: 47cd37c28be8
2017.4.1f1: 9231f953d9d3
2017.4.20f1: 20968fa45e51
2017.4.20f2: 413dbd19b6dc
2017.4.21f1: de35fe252486
2017.4.22f1: eb4bc6fa7f1d
2017.4.23f1: f80c8a98b1b5
2017.4.24f1: 786769fc3439
2017.4.25f1: 9cba1c3a94f1
2017.4.26f1: 3b349d10f010
2017.4.27f1: 0c4b856e4c6e
2017.4.28f1: e3a0f7dd2097
2017.4.29f1: 06508aa14ca1
2017.4.2f2: 52d9cb89b362
2017.4.30f1: c6fa43736cae
2017.4.31f1: 9c8dbc3421cb
2017.4.32f1: 4da3ed968770
2017.4.33f1: a8557a619e24
2017.4.34f1: 121f18246307
2017.4.35f1: e57a7bcbbf0b
2017.4.36f1: c663def8414c
2017.4.37f1: 78b69503ebc4
2017.4.38f1: 82ac2fb100ce
2017.4.39f1: 947131c5be7e
2017.4.3f1: 21ae32b5a9cb
2017.4.40f1: 6e14067f8a9a
2017.4.4f1: 645c9050ba4d
2017.4.5f1: 89d1db9cb682
2017.4.6f1: c24f30193bac
2017.4.7f1: de9eb5ca33c5
2017.4.8f1: 5ab7f4878ef1
2017.4.9f1: 6d84dfc57ccf
2018.1.0b1: bcd94551ef32
2018.1.0b10: 4ec9a3104331
2018.1.0b11: c5bf62a40d4b
2018.1.0b12: b4ca90bad6b1
2018.1.0b13: 43de91b8ac41
2018.1.0b2: 79c3bdce0980
2018.1.0b3: e1ef60e69006
2018.1.0b4: 003615bcffde
2018.1.0b5: a48da4f646ae
2018.1.0b6: 2c4679632cfb
2018.1.0b7: cfaabe8e4f18
2018.1.0b8: 0b50224845b9
2018.1.0b9: 36a41ae63f8e
2018.1.0f1: 21784bcc13fa
2018.1.0f2: d4d99f31acba
2018.1.1f1: b8cbb5de9840
2018.1.2f1: a46d718d282d
2018.1.3f1: a53ad04f7c7f
2018.1.4f1: 1a308f4ebef1
2018.1.5f1: 732dbf75922d
2018.1.6f1: 57cc34175ccf
2018.1.7f1: 4cb482063d12
2018.1.8f1: 26051d4de9e9
2018.1.9f1: 24bbd83e8b9e
2018.1.9f2: a6cc294b73ee
2018.2.0b10: 4bc57476174c
2018.2.0b11: 912020d71ebf
2018.2.0b2: 96999d86066c
2018.2.0b3: 0a6b93065060
2018.2.0b4: a3564b9ba417
2018.2.0b5: 35351042bf9d
2018.2.0b6: ac34ff94dd0f
2018.2.0b7: 8ce15a37a3ae
2018.2.0b8: fed204371f5a
2018.2.0b9: 3b5ad740cdc8
2018.2.0f1: 51acc5a75f1e
2018.2.0f2: \"787658998520\"
2018.2.10f1: 674aa5a67ed5
2018.2.11f1: 38bd7dec5000
2018.2.12f1: 0a46ddfcfad4
2018.2.13f1: 83fbdcd35118
2018.2.14f1: 3262fb3b0716
2018.2.15f1: 65e0713a5949
2018.2.16f1: 39a4ac3d51f6
2018.2.17f1: 88933597c842
2018.2.18f1: 4550892b6062
2018.2.19f1: 06990f28ba00
2018.2.1f1: 1a9968d9f99c
2018.2.20f1: cef3e6c0c622
2018.2.21f1: a122f5dc316d
2018.2.2f1: c18cef34cbcd
2018.2.3f1: 1431a7d2ced7
2018.2.4f1: cb262d9ddeaf
2018.2.5f1: 3071d1717b71
2018.2.6f1: c591d9a97a0b
2018.2.7f1: 4ebd28dd9664
2018.2.8f1: ae1180820377
2018.2.9f1: \"2207421190e9\"
2018.3.0b1: 3f0ac31c6d6f
2018.3.0b10: 6677d031dfe5
2018.3.0b11: 45aaf16dbe1a
2018.3.0b12: 77f6238a7ced
2018.3.0b2: 21e0e8a5466d
2018.3.0b3: cc0086a8e10c
2018.3.0b4: 44012bad7987
2018.3.0b5: 01088ee0a3a8
2018.3.0b6: f5aefbeed0ac
2018.3.0b7: af029f4527e0
2018.3.0b8: fa755def4b97
2018.3.0b9: a3326ae325b2
2018.3.0f1: f023c421e164
2018.3.0f2: 6e9a27477296
2018.3.10f1: f88de2c96e63
2018.3.11f1: 5063218e4ab8
2018.3.12f1: 8afd630d1f5b
2018.3.13f1: 06548a9e9582
2018.3.14f1: d0e9f15437b1
2018.3.1f1: bb579dc42f1d
2018.3.2f1: b3c100a4b73a
2018.3.3f1: 393bae82dbb8
2018.3.4f1: 1d952368ca3a
2018.3.5f1: 76b3e37670a4
2018.3.6f1: a220877bc173
2018.3.7f1: 9e14d22a41bb
2018.3.8f1: fc0fe30d6d91
2018.3.9f1: 947e1ea5aa8d
2018.4.0f1: b6ffa8986c8d
2018.4.10f1: a0470569e97b
2018.4.11f1: 7098af2f11ea
2018.4.12f1: 59ddc4c59b4f
2018.4.13f1: 497f083a43af
2018.4.14f1: 05119b33d0b7
2018.4.15f1: 13f5a1bf9ca1
2018.4.16f1: e6e9ca02b32a
2018.4.17f1: b830f56f42f0
2018.4.18f1: 61fce66342ad
2018.4.19f1: 459f70f82ea4
2018.4.1f1: b7c424a951c0
2018.4.20f1: \"008688490035\"
2018.4.21f1: fd3915227633
2018.4.22f1: 3362ffbb7aa1
2018.4.23f1: c9cf1a90e812
2018.4.24f1: 3071911a89e9
2018.4.25f1: b07bfa0a8827
2018.4.26f1: a7ac1c6396db
2018.4.27f1: 4e283b7d3f88
2018.4.28f1: a2d4f71491a4
2018.4.29f1: 50cce2edf27f
2018.4.2f1: d6fb3630ea75
2018.4.30f1: c698a062d8e6
2018.4.31f1: 212ea663d844
2018.4.32f1: fba45da84107
2018.4.33f1: d75f7e9df24c
2018.4.34f1: ae2afac172fb
2018.4.35f1: dbb5675dce2d
2018.4.36f1: 6cd387d23174
2018.4.3f1: 8a9509a5aff9
2018.4.4f1: 5440768ff61c
2018.4.5f1: 7b38f8ac282e
2018.4.6f1: cde1bbcc9f0d
2018.4.7f1: b9a993fd1334
2018.4.8f1: 9bc9d983d803
2018.4.9f1: ca372476eaba
2019.1.0a10: 84f9b5a9b69f
2019.1.0a11: 0f106840e011
2019.1.0a12: 5175bce2e5d4
2019.1.0a13: 3de2277bb0e6
2019.1.0a14: 0e6151d5f054
2019.1.0a7: 4474d51790a5
2019.1.0a8: 7ae038d0fb32
2019.1.0a9: 0acd256790e8
2019.1.0b1: 83b3ba1f99df
2019.1.0b10: dbf1e96a8b63
2019.1.0b2: 669ada05268b
2019.1.0b3: 52be913b8b36
2019.1.0b4: fd0dda99e05a
2019.1.0b5: 9899a5bd7e43
2019.1.0b6: e3cf6cb42b7c
2019.1.0b7: 8afb02580933
2019.1.0b8: 0862b00eb5a3
2019.1.0b9: f1481f10a935
2019.1.0f1: 5c52223b18d4
2019.1.0f2: 292b93d75a2c
2019.1.10f1: f007ed779b7a
2019.1.11f1: 9b001d489a54
2019.1.12f1: f04f5427219e
2019.1.13f1: b5956c0a61e7
2019.1.14f1: 148b5891095a
2019.1.1f1: fef62e97e63b
2019.1.2f1: 3e18427e571f
2019.1.3f1: dc414eb9ed43
2019.1.4f1: ffa3a7a2dd7d
2019.1.5f1: 0ca0f5646614
2019.1.6f1: f2970305fe1c
2019.1.7f1: f3c4928e5742
2019.1.8f1: 7938dd008a75
2019.1.9f1: d5f1b37da199
2019.2.0a11: 50bfd5f1a2f4
2019.2.0a13: 7d71eaf2acca
2019.2.0a14: f7ca70490e38
2019.2.0a4: 2403bdbdd88b
2019.2.0a6: 770171a847a0
2019.2.0a7: b5f63d908f8e
2019.2.0a8: 18a4512f903f
2019.2.0a9: 3ec61d0c8674
2019.2.0b1: 18ccf127b486
2019.2.0b10: 54f9b0ad4ba4
2019.2.0b2: ad601490df46
2019.2.0b3: 281ad50da7fd
2019.2.0b4: 243498937c5d
2019.2.0b5: e3a10156d6de
2019.2.0b6: 2099073aa6fc
2019.2.0b7: 87c9ecb96495
2019.2.0b9: eabe87e2a246
2019.2.0f1: 20c1667945cf
2019.2.10f1: 923acd2d43aa
2019.2.11f1: 5f859a4cfee5
2019.2.12f1: b1a7e1fb4fa5
2019.2.13f1: e20f6c7e5017
2019.2.14f1: 49dd4e9fa428
2019.2.15f1: dcb72c2e9334
2019.2.16f1: b9898e2d04a4
2019.2.17f1: 8e603399ca02
2019.2.18f1: bbf64de26e34
2019.2.19f1: 929ab4d01772
2019.2.1f1: ca4d5af0be6f
2019.2.20f1: c67d00285037
2019.2.21f1: 9d528d026557
2019.2.2f1: ab112815d860
2019.2.3f1: 8e55c27a4621
2019.2.4f1: c63b2af89a85
2019.2.5f1: 9dace1eed4cc
2019.2.6f1: fe82a0e88406
2019.2.7f2: c96f78eb5904
2019.2.8f1: ff5b465c8d13
2019.2.9f1: ebce4d76e6e8
2019.3.0a10: d046aa12c0d7
2019.3.0a11: 6fa9444d8a5d
2019.3.0a12: b073d123dd5d
2019.3.0a2: fa7740529556
2019.3.0a3: 91c086393aab
2019.3.0a4: 7368acd360f4
2019.3.0a5: 9aff892fb75b
2019.3.0a6: 8709ed9302b4
2019.3.0a7: 5a4bb929feff
2019.3.0a8: 8ea4afdbfa47
2019.3.0b1: 78e106a973e1
2019.3.0b10: 7955ac590a97
2019.3.0b11: 1781308d0868
2019.3.0b12: e0f9cf1b1aee
2019.3.0b2: 0c8fb71b3dfb
2019.3.0b3: d0377b9426dc
2019.3.0b4: 3271e9fc5036
2019.3.0b5: 13eef430e0c9
2019.3.0b6: 0612c96692fb
2019.3.0b7: 9946d7a66754
2019.3.0b8: 7eb5456f98b4
2019.3.0b9: de32b4c0dd7a
2019.3.0f1: ffacea4b84e7
2019.3.0f3: 6c9e2bfd6f81
2019.3.0f5: 44796c9d3c2c
2019.3.0f6: 27ab2135bccf
2019.3.10f1: 5968d7f82152
2019.3.11f1: ceef2d848e70
2019.3.12f1: 84b23722532d
2019.3.13f1: d4ddf0d95db9
2019.3.14f1: 2b330bf6d2d8
2019.3.15f1: 59ff3e03856d
2019.3.1f1: 89d6087839c2
2019.3.2f1: c46a3a38511e
2019.3.3f1: 7ceaae5f7503
2019.3.4f1: 4f139db2fdbd
2019.3.5f1: d691e07d38ef
2019.3.6f1: 5c3fb0a11183
2019.3.7f1: 6437fd74d35d
2019.3.8f1: 4ba98e9386ed
2019.3.9f1: e6e740a1c473
2019.4.0f1: 0af376155913
2019.4.10f1: 5311b3af6f69
2019.4.11f1: 2d9804dddde7
2019.4.12f1: 225e826a680e
2019.4.13f1: 518737b1de84
2019.4.14f1: 4037e52648cd
2019.4.15f1: fbf367ac14e9
2019.4.16f1: e05b6e02d63e
2019.4.17f1: 667c8606c536
2019.4.18f1: 3310a4d4f880
2019.4.19f1: ca5b14067cec
2019.4.1f1: e6c045e14e4e
2019.4.20f1: 6dd1c08eedfa
2019.4.21f1: b76dac84db26
2019.4.22f1: 9fdda2fe27ad
2019.4.23f1: 3f4e01f1a5ec
2019.4.24f1: 5da6f0345e82
2019.4.25f1: 01a0494af254
2019.4.26f1: e0392c6b2363
2019.4.27f1: 23dc10685eb4
2019.4.28f1: 1381962e9d08
2019.4.29f1: 0eeae20b1d82
2019.4.2f1: 20b4642a3455
2019.4.30f1: e8c891080a1f
2019.4.31f1: bd5abf232a62
2019.4.32f1: f88bf0bee961
2019.4.33f1: c9b2b02eeeef
2019.4.34f1: 6a9faed444f2
2019.4.35f1: 0462406dff2e
2019.4.36f1: 660c164b2fc5
2019.4.3f1: f880dceab6fe
2019.4.4f1: 1f1dac67805b
2019.4.5f1: 81610f64359c
2019.4.6f1: a7aea80e3716
2019.4.7f1: e992b1a16e65
2019.4.8f1: 60781d942082
2019.4.9f1: 50fe8a171dd9
2020.1.0a11: ccf51fff0e6a
2020.1.0a12: 40e46701fee5
2020.1.0a13: dce830042a25
2020.1.0a14: 2a3307d3869b
2020.1.0a15: c34b21e125d7
2020.1.0a16: 196f78887a11
2020.1.0a17: ccc6f9131a63
2020.1.0a18: 630f9adc3455
2020.1.0a19: 6995b659db2e
2020.1.0a20: \"019325219793\"
2020.1.0a21: 4ea9a24ebde1
2020.1.0a22: 17d4c89d06f9
2020.1.0a23: 607f55d6e9ce
2020.1.0a24: 1f86fad89a55
2020.1.0a25: 301553012d38
2020.1.0a3: a37e4d4d532f
2020.1.0a5: 8af4c0145d29
2020.1.0a7: d3d2f5b1d33e
2020.1.0a8: a932f1074310
2020.1.0a9: 3ca10380fd3b
2020.1.0b1: 92a30bddf81d
2020.1.0b10: d80b47d1592d
2020.1.0b11: de513167607b
2020.1.0b12: 9e6726e6ce12
2020.1.0b13: 3682d55b6e87
2020.1.0b14: 69bacbd35688
2020.1.0b15: 40d9420e7de8
2020.1.0b16: 70ea0f8c4a3c
2020.1.0b2: 14d43bf8b596
2020.1.0b3: 6955a944264e
2020.1.0b4: 7e2ed8c1221a
2020.1.0b5: f017efceb459
2020.1.0b6: 255abb3234f8
2020.1.0b7: 6cfebb967dcd
2020.1.0b8: 726fc0bca2bc
2020.1.0b9: 9c0aec301c8d
2020.1.0f1: 2ab9c4179772
2020.1.10f1: 974a9d56f159
2020.1.11f1: 698c1113cef0
2020.1.12f1: 55b56f0a86e3
2020.1.13f1: 5e24f28bfbc0
2020.1.14f1: d81f64f5201d
2020.1.17f1: 9957aee8edc2
2020.1.1f1: 2285c3239188
2020.1.2f1: 7b32bc54ba47
2020.1.3f1: cf5c4788e1d8
2020.1.4f1: fa717bb873ec
2020.1.5f1: e025938fdedc
2020.1.6f1: fc477ca6df10
2020.1.7f1: 064ffcdb64ad
2020.1.8f1: 22e8c0b0c3ec
2020.1.9f1: 145f5172610f
2020.2.0a10: 11fb376d50c9
2020.2.0a11: d00a9d9791a8
2020.2.0a12: a331b04b65b8
2020.2.0a13: 542ff463470b
2020.2.0a15: 86048ae4b4bd
2020.2.0a16: 5a1f66dd0d56
2020.2.0a17: 7a5530473e9d
2020.2.0a18: 4f8709444da6
2020.2.0a19: 8037ac78137e
2020.2.0a21: 3e0d5f775006
2020.2.0a7: cea774d83c47
2020.2.0a8: 8b7e7268f9f8
2020.2.0a9: 31beeaab9d72
2020.2.0b1: 4ae7c5e87f33
2020.2.0b10: 19f63eee530c
2020.2.0b11: c499c2bf2e80
2020.2.0b12: 92852ae685d8
2020.2.0b2: 90b2443a8df1
2020.2.0b4: 7b778e331e0b
2020.2.0b5: e2067236bd5c
2020.2.0b6: 24a0f8b56f72
2020.2.0b7: 1b1252580c64
2020.2.0b8: dff91d65251a
2020.2.0b9: ef2968fa77ae
2020.2.0f1: 3721df5a8b28
2020.2.1f1: 270dd8c3da1c
2020.2.2f1: 068178b99f32
2020.2.3f1: 8ff31bc5bf5b
2020.2.4f1: becced5a802b
2020.2.5f1: e2c53f129de5
2020.2.6f1: 8a2143876886
2020.2.7f1: c53830e277f1
2020.3.0f1: c7b5465681fb
2020.3.10f1: 297d780c91bc
2020.3.11f1: 99c7afb366b3
2020.3.12f1: b3b2c6512326
2020.3.13f1: 71691879b7f5
2020.3.14f1: d0d1bb862f9d
2020.3.15f1: 5e502cb56e17
2020.3.15f2: 6cf78cb77498
2020.3.16f1: 049d6eca3c44
2020.3.17f1: a4537701e4ab
2020.3.18f1: a7d1c678663c
2020.3.19f1: 68f137dc9bbe
2020.3.1f1: 77a89f25062f
2020.3.20f1: 41c4e627c95f
2020.3.21f1: a38c86f6690f
2020.3.22f1: e1a7f79fd887
2020.3.23f1: c5d91304a876
2020.3.24f1: 79c78de19888
2020.3.25f1: 9b9180224418
2020.3.26f1: 7298b473bc1a
2020.3.27f1: e759542391ea
2020.3.28f1: f5400f52e03f
2020.3.29f1: 2ff179115da0
2020.3.2f1: 8fd9074bf66c
2020.3.30f1: 1fb1bf06830e
2020.3.3f1: 76626098c1c4
2020.3.4f1: 0abb6314276a
2020.3.5f1: 8095aa901b9b
2020.3.6f1: 338bb68529b2
2020.3.7f1: dd97f2c94397
2020.3.8f1: 507919d4fff5
2020.3.9f1: 108be757e447
2021.1.0a2: 37c5ec4c3cb1
2021.1.0a4: 7d39c812e75a
2021.1.0a5: 0878d20e0f3c
2021.1.0a6: 0722b711ea8f
2021.1.0a7: fdd63b12dbc0
2021.1.0a8: 824e91d155c5
2021.1.0a9: 18321e85013a
2021.1.0b1: 9f7c487dd2da
2021.1.0b10: b27f69638034
2021.1.0b11: ddf8e7a924bd
2021.1.0b12: 5f97ac28ace0
2021.1.0b2: 1e651ea6a5c1
2021.1.0b3: 202fb86be42c
2021.1.0b4: 6d90c0720bd4
2021.1.0b5: 37f46e59aab7
2021.1.0b6: 4f6b2ade48ff
2021.1.0b7: 02180fe17a0e
2021.1.0b8: 4a0a5fc962a9
2021.1.0f1: 61a549675243
2021.1.10f1: b15f561b2cef
2021.1.11f1: 4d8c25f7477e
2021.1.12f1: afcadd793de6
2021.1.13f1: a03098edbbe0
2021.1.14f1: 51d2f824827f
2021.1.15f1: e767a7370072
2021.1.16f1: 5fa502fca597
2021.1.17f1: 03b40fe07a36
2021.1.18f1: 25bdc3efbc2d
2021.1.19f1: 5f5eb8bbdc25
2021.1.1f1: 6fdc41dfa55a
2021.1.20f1: be552157821d
2021.1.21f1: f2d5d3c59f8c
2021.1.22f1: a137e5fb0427
2021.1.23f1: b50729e604a9
2021.1.24f1: 6667702a1e7c
2021.1.25f1: b6f2b893ea32
2021.1.26f1: 6f076387c01d
2021.1.27f1: 7e296a84045d
2021.1.28f1: f3f9dc10f3dd
2021.1.2f1: e5d502d80fbb
2021.1.3f1: 4bef613afd59
2021.1.4f1: 4cd64a618c1b
2021.1.5f1: 3737af19df53
2021.1.6f1: c0fade0cc7e9
2021.1.7f1: d91830b65d9b
2021.1.9f1: 7a790e367ab3
2021.2.0a10: b8c2bb7e8b36
2021.2.0a11: 7e28cd2d801e
2021.2.0a12: 687b3b92c1e8
2021.2.0a13: 71a161db37e2
2021.2.0a14: 462ae11b66db
2021.2.0a15: 37767e16dc73
2021.2.0a16: 663b19a0829e
2021.2.0a17: 96ee4da88f82
2021.2.0a19: f81c6ad18371
2021.2.0a20: 0bd21e314fca
2021.2.0a21: 75138d5880a6
2021.2.0a5: 4a734693b889
2021.2.0a6: dc497bf8326a
2021.2.0a8: 05e6d22b19f7
2021.2.0a9: 5be3997fdbde
2021.2.0b1: b0978dae4864
2021.2.0b10: b31a071b0ce1
2021.2.0b11: 0bffbba03cb9
2021.2.0b12: 8137c0cefaf0
2021.2.0b13: 94c1109a0557
2021.2.0b14: bf4dfffaa8cd
2021.2.0b15: b1c7ce145b7d
2021.2.0b16: edbc0738c91b
2021.2.0b2: d86242d513ba
2021.2.0b3: bb7e34618385
2021.2.0b4: af9ec38f7da3
2021.2.0b5: c11a42e94ab9
2021.2.0b6: 2055a14f48ed
2021.2.0b7: f7def5121c60
2021.2.0b8: 3fad0faf7e71
2021.2.0b9: 162b5e238388
2021.2.0f1: 4bf1ec4b23c9
2021.2.10f1: ee872746220e
2021.2.11f1: e50cafbb4399
2021.2.12f1: 48b1aa000234
2021.2.13f1: 90b6766da538
2021.2.1f1: c20c6d589440
2021.2.2f1: 5e2b1e92c7f8
2021.2.3f1: 32358a8527b4
2021.2.4f1: 99ba6aa4c552
2021.2.5f1: 4ec9a5e799f5
2021.2.6f1: 8c4e826ba445
2021.2.7f1: 6bd9e232123f
2021.2.8f1: d0e5f0a7b06a
2021.2.9f1: 921b45a28ab6
2022.1.0a10: 48c8cfa2acec
2022.1.0a11: ae01f5fb527d
2022.1.0a12: 816252c3efbb
2022.1.0a13: 5a5aca0fb632
2022.1.0a15: 49120632d05b
2022.1.0a16: 603c2cfd9276
2022.1.0a7: c277161121c6
2022.1.0a8: a6d7f27874c0
2022.1.0a9: 5a1ba9fbc92d
2022.1.0b1: ea0f0219deed
2022.1.0b2: 980041f98dd2
2022.1.0b3: 169963e3b543
2022.1.0b4: 0b1e54378c16
2022.1.0b5: 9f5ac7cea48f
2022.1.0b6: 0c945167f89c
2022.1.0b7: c0c678b963f4
2022.1.0b8: cca363eec1bc
2022.1.0b9: a43aced8177f
5.4.5f1: 68943b6c8c42
5.5.0f3: 38b4efef76f0
5.5.1f1: 88d00a7498cd
5.5.2f1: 3829d7f588f3
5.5.2p1: 9360c5517afe
5.5.3f1: 4d2f809fd6f3
5.5.3p2: f15b2772e4d0
5.5.4f1: 8ffd0efd98b1
5.5.5f1: d875e6967482
5.6.0f3: 497a0f351392
5.6.0p2: bbd5ca01a0ea
5.6.0p3: f8dcc233883f
5.6.1f1: 2860b30f0b54
5.6.1p1: 74c1f4917542
5.6.2f1: a2913c821e27
5.6.3f1: d3101c3b8468
5.6.3p3: 88d4ddf6344a
5.6.3p4: fbe8bd37d7fa
5.6.4f1: ac7086b8d112
5.6.4p1: e67c4b7007d5";