mirror of
https://github.com/artemkorsakov/project-euler-stats.git
synced 2026-07-22 05:42:55 +00:00
Add cache data
This commit is contained in:
parent
dc3d0ab277
commit
048f1975e8
6 changed files with 873 additions and 86 deletions
656
cache/cache.json
vendored
Normal file
656
cache/cache.json
vendored
Normal file
|
|
@ -0,0 +1,656 @@
|
|||
{
|
||||
"accountData": {
|
||||
"account": "Artem_Korsakov",
|
||||
"alias": "Artem Korsakov",
|
||||
"location": "Russia",
|
||||
"language": "Scala"
|
||||
},
|
||||
"progressData": {
|
||||
"level": "Level 4",
|
||||
"solved": 118,
|
||||
"percentage": 12.6,
|
||||
"progress": "Solved 118 out of 936 problems (12.6%)",
|
||||
"toTheNext": "7 problems away from level 5"
|
||||
},
|
||||
"euleriansPlace": "You are not in Eulerians' rating",
|
||||
"locationUrl": "https://projecteuler.net/location=Russia",
|
||||
"languageUrl": "https://projecteuler.net/language=Scala",
|
||||
"locationRating": {
|
||||
"place": 999999,
|
||||
"top100": 204,
|
||||
"top50": 287,
|
||||
"top25": 387,
|
||||
"top10": 527,
|
||||
"top5": 810,
|
||||
"top1": 900
|
||||
},
|
||||
"languageRating": {
|
||||
"place": 82,
|
||||
"top100": 108,
|
||||
"top50": 140,
|
||||
"top25": 177,
|
||||
"top10": 250,
|
||||
"top5": 374,
|
||||
"top1": 786
|
||||
},
|
||||
"levelDataArray": [
|
||||
{
|
||||
"level": "Level 1",
|
||||
"members": "71201 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 2",
|
||||
"members": "32115 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 3",
|
||||
"members": "12279 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 4",
|
||||
"members": "6199 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 5",
|
||||
"members": "3074 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 6",
|
||||
"members": "1908 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 7",
|
||||
"members": "1048 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 8",
|
||||
"members": "769 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 9",
|
||||
"members": "537 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 10",
|
||||
"members": "381 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 11",
|
||||
"members": "249 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 12",
|
||||
"members": "199 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 13",
|
||||
"members": "159 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 14",
|
||||
"members": "126 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 15",
|
||||
"members": "90 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 16",
|
||||
"members": "91 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 17",
|
||||
"members": "78 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 18",
|
||||
"members": "59 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 19",
|
||||
"members": "45 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 20",
|
||||
"members": "39 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 21",
|
||||
"members": "38 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 22",
|
||||
"members": "29 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 23",
|
||||
"members": "27 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 24",
|
||||
"members": "28 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 25",
|
||||
"members": "19 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 26",
|
||||
"members": "15 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 27",
|
||||
"members": "12 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 28",
|
||||
"members": "13 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 29",
|
||||
"members": "15 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 30",
|
||||
"members": "14 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 31",
|
||||
"members": "14 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 32",
|
||||
"members": "9 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 33",
|
||||
"members": "10 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 34",
|
||||
"members": "11 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 35",
|
||||
"members": "13 members"
|
||||
},
|
||||
{
|
||||
"level": "Level 36",
|
||||
"members": "43 members"
|
||||
}
|
||||
],
|
||||
"awardsData": [
|
||||
{
|
||||
"name": "Problem Solving Awards",
|
||||
"awards": [
|
||||
{
|
||||
"award": "Baby Steps",
|
||||
"link": "https://projecteuler.net/award=1",
|
||||
"description": "Solve three problems",
|
||||
"isCompleted": true,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "615578 members"
|
||||
},
|
||||
{
|
||||
"award": "The Journey Begins",
|
||||
"link": "https://projecteuler.net/award=2",
|
||||
"description": "Progress to Level 1 by solving twenty-five problems",
|
||||
"isCompleted": true,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "119573 members"
|
||||
},
|
||||
{
|
||||
"award": "Decathlete",
|
||||
"link": "https://projecteuler.net/award=3",
|
||||
"description": "Solve ten consecutive problems",
|
||||
"isCompleted": true,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "267966 members"
|
||||
},
|
||||
{
|
||||
"award": "Flawless Fifty",
|
||||
"link": "https://projecteuler.net/award=4",
|
||||
"description": "Solve fifty consecutive problems",
|
||||
"isCompleted": true,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "36441 members"
|
||||
},
|
||||
{
|
||||
"award": "C for Commitment",
|
||||
"link": "https://projecteuler.net/award=5",
|
||||
"description": "Complete any grid",
|
||||
"isCompleted": false,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "6975 members"
|
||||
},
|
||||
{
|
||||
"award": "CC for Continued Commitment",
|
||||
"link": "https://projecteuler.net/award=6",
|
||||
"description": "Complete any two grids",
|
||||
"isCompleted": false,
|
||||
"progress": "0 / 2",
|
||||
"percentage": 0,
|
||||
"members": "851 members"
|
||||
},
|
||||
{
|
||||
"award": "D for Dedication",
|
||||
"link": "https://projecteuler.net/award=7",
|
||||
"description": "Complete any five grids",
|
||||
"isCompleted": false,
|
||||
"progress": "0 / 5",
|
||||
"percentage": 0,
|
||||
"members": "76 members"
|
||||
},
|
||||
{
|
||||
"award": "Three Strikes!",
|
||||
"link": "https://projecteuler.net/award=8",
|
||||
"description": "Get the diagonals in any three grids",
|
||||
"isCompleted": false,
|
||||
"progress": "1 / 3",
|
||||
"percentage": 33.33,
|
||||
"members": "128 members"
|
||||
},
|
||||
{
|
||||
"award": "Perfect Game",
|
||||
"link": "https://projecteuler.net/award=9",
|
||||
"description": "Get the diagonals in all possible grids",
|
||||
"isCompleted": false,
|
||||
"progress": "1 / 9",
|
||||
"percentage": 11.11,
|
||||
"members": "25 members"
|
||||
},
|
||||
{
|
||||
"award": "As Easy As Pi",
|
||||
"link": "https://projecteuler.net/award=11",
|
||||
"description": "Solve problems 3, 14, 15, 92, 65, 35, 89, 79, 32, 38, and 46",
|
||||
"isCompleted": true,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "17963 members"
|
||||
},
|
||||
{
|
||||
"award": "Unlucky Squares",
|
||||
"link": "https://projecteuler.net/award=12",
|
||||
"description": "Solve thirteen square numbered problems",
|
||||
"isCompleted": false,
|
||||
"progress": "11 / 13",
|
||||
"percentage": 84.62,
|
||||
"members": "4823 members"
|
||||
},
|
||||
{
|
||||
"award": "Triangle Trophy",
|
||||
"link": "https://projecteuler.net/award=13",
|
||||
"description": "Solve all the triangle numbered problems below 100",
|
||||
"isCompleted": true,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "2088 members"
|
||||
},
|
||||
{
|
||||
"award": "Square Triangle",
|
||||
"link": "https://projecteuler.net/award=14",
|
||||
"description": "Solve thirty-six triangle numbered problems",
|
||||
"isCompleted": false,
|
||||
"progress": "14 / 36",
|
||||
"percentage": 38.89,
|
||||
"members": "133 members"
|
||||
},
|
||||
{
|
||||
"award": "Prime Obsession",
|
||||
"link": "https://projecteuler.net/award=15",
|
||||
"description": "Solve fifty prime numbered problems",
|
||||
"isCompleted": false,
|
||||
"progress": "27 / 50",
|
||||
"percentage": 54,
|
||||
"members": "2461 members"
|
||||
},
|
||||
{
|
||||
"award": "Trinary Triumph",
|
||||
"link": "https://projecteuler.net/award=16",
|
||||
"description": "Solve problems 1, 3, 9, 27, 81, 243, and 729",
|
||||
"isCompleted": false,
|
||||
"progress": "6 / 7",
|
||||
"percentage": 85.71,
|
||||
"members": "203 members"
|
||||
},
|
||||
{
|
||||
"award": "Fibonacci Fever",
|
||||
"link": "https://projecteuler.net/award=17",
|
||||
"description": "Solve thirteen Fibonacci numbered problems",
|
||||
"isCompleted": false,
|
||||
"progress": "10 / 13",
|
||||
"percentage": 76.92,
|
||||
"members": "2021 members"
|
||||
},
|
||||
{
|
||||
"award": "Daring Dozen",
|
||||
"link": "https://projecteuler.net/award=18",
|
||||
"description": "Solve twelve problems with an ID containing three digits",
|
||||
"isCompleted": true,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "16821 members"
|
||||
},
|
||||
{
|
||||
"award": "Lucky Luke",
|
||||
"link": "https://projecteuler.net/award=19",
|
||||
"description": "Solve fifty lucky numbered problems",
|
||||
"isCompleted": false,
|
||||
"progress": "24 / 50",
|
||||
"percentage": 48,
|
||||
"members": "1659 members"
|
||||
},
|
||||
{
|
||||
"award": "Decimator",
|
||||
"link": "https://projecteuler.net/award=21",
|
||||
"description": "Solve one in every ten problems from problems 101 to 200",
|
||||
"isCompleted": false,
|
||||
"progress": "3 / 10",
|
||||
"percentage": 30,
|
||||
"members": "5281 members"
|
||||
},
|
||||
{
|
||||
"award": "Trecenti Decimator",
|
||||
"link": "https://projecteuler.net/award=22",
|
||||
"description": "Solve one in every ten problems for the first 300 problems",
|
||||
"isCompleted": false,
|
||||
"progress": "15 / 30",
|
||||
"percentage": 50,
|
||||
"members": "2075 members"
|
||||
},
|
||||
{
|
||||
"award": "Sicarius Decimator",
|
||||
"link": "https://projecteuler.net/award=23",
|
||||
"description": "I see a target. Good hunting, 47",
|
||||
"isCompleted": false,
|
||||
"progress": "20 / 47",
|
||||
"percentage": 42.55,
|
||||
"members": "1728 members"
|
||||
},
|
||||
{
|
||||
"award": "Ultimus Decimator",
|
||||
"link": "https://projecteuler.net/award=24",
|
||||
"description": "Solve one in every ten problems in the archives",
|
||||
"isCompleted": false,
|
||||
"progress": "20 / 92",
|
||||
"percentage": 21.74,
|
||||
"members": "214 members"
|
||||
},
|
||||
{
|
||||
"award": "One Percenter",
|
||||
"link": "https://projecteuler.net/award=25",
|
||||
"description": "Better than 99% = One badass problem solver",
|
||||
"isCompleted": true,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "10101 members"
|
||||
},
|
||||
{
|
||||
"award": "High Flyer",
|
||||
"link": "https://projecteuler.net/award=26",
|
||||
"description": "Progress to the maximum level",
|
||||
"isCompleted": false,
|
||||
"progress": "4 / 36",
|
||||
"percentage": 11.11,
|
||||
"members": "69 members"
|
||||
},
|
||||
{
|
||||
"award": "Perfection",
|
||||
"link": "https://projecteuler.net/",
|
||||
"description": "Solve every problem",
|
||||
"isCompleted": false,
|
||||
"progress": "118 / 936",
|
||||
"percentage": 12.61,
|
||||
"members": "0 members"
|
||||
},
|
||||
{
|
||||
"award": "The Archivist",
|
||||
"link": "https://projecteuler.net/award=28",
|
||||
"description": "Solve half of the problems in the archives",
|
||||
"isCompleted": false,
|
||||
"progress": "118 / 463",
|
||||
"percentage": 25.49,
|
||||
"members": "558 members"
|
||||
},
|
||||
{
|
||||
"award": "Master of Archives",
|
||||
"link": "https://projecteuler.net/award=29",
|
||||
"description": "Solve every problem in the archives",
|
||||
"isCompleted": false,
|
||||
"progress": "118 / 926",
|
||||
"percentage": 12.74,
|
||||
"members": "22 members"
|
||||
},
|
||||
{
|
||||
"award": "On The Ball",
|
||||
"link": "https://projecteuler.net/award=31",
|
||||
"description": "Solve the most recent problem",
|
||||
"isCompleted": false,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "7068 members"
|
||||
},
|
||||
{
|
||||
"award": "High Five",
|
||||
"link": "https://projecteuler.net/award=32",
|
||||
"description": "Solve the five most recent problems",
|
||||
"isCompleted": false,
|
||||
"progress": "0 / 5",
|
||||
"percentage": 0,
|
||||
"members": "1090 members"
|
||||
},
|
||||
{
|
||||
"award": "Ten Out Of Ten",
|
||||
"link": "https://projecteuler.net/award=33",
|
||||
"description": "Solve the ten most recent problems",
|
||||
"isCompleted": false,
|
||||
"progress": "0 / 10",
|
||||
"percentage": 0,
|
||||
"members": "596 members"
|
||||
},
|
||||
{
|
||||
"award": "State Of The Art",
|
||||
"link": "https://projecteuler.net/award=34",
|
||||
"description": "Solve the twenty-five most recent problems",
|
||||
"isCompleted": false,
|
||||
"progress": "0 / 25",
|
||||
"percentage": 0,
|
||||
"members": "293 members"
|
||||
},
|
||||
{
|
||||
"award": "Unknown Conqueror",
|
||||
"link": "https://projecteuler.net/award=35",
|
||||
"description": "Five times lucky, five times smart",
|
||||
"isCompleted": false,
|
||||
"progress": "0 / 5",
|
||||
"percentage": 0,
|
||||
"members": "20 members"
|
||||
},
|
||||
{
|
||||
"award": "One In A Hundred",
|
||||
"link": "https://projecteuler.net/award=41",
|
||||
"description": "Be among the first hundred to solve a problem",
|
||||
"isCompleted": false,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "5021 members"
|
||||
},
|
||||
{
|
||||
"award": "Chart Topper",
|
||||
"link": "https://projecteuler.net/award=42",
|
||||
"description": "Be among the first ten to solve a problem",
|
||||
"isCompleted": false,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "671 members"
|
||||
},
|
||||
{
|
||||
"award": "Gold Medal",
|
||||
"link": "https://projecteuler.net/award=43",
|
||||
"description": "The first to solve a problem",
|
||||
"isCompleted": false,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "133 members"
|
||||
},
|
||||
{
|
||||
"award": "Tag Explorer",
|
||||
"link": "https://projecteuler.net/award=45",
|
||||
"description": "Solve at least one problem for one-hundred different tags",
|
||||
"isCompleted": false,
|
||||
"progress": "68 / 100",
|
||||
"percentage": 68,
|
||||
"members": "694 members"
|
||||
},
|
||||
{
|
||||
"award": "Easy Prey",
|
||||
"link": "https://projecteuler.net/award=51",
|
||||
"description": "Solve the fifty easiest problems",
|
||||
"isCompleted": false,
|
||||
"progress": "49 / 50",
|
||||
"percentage": 98,
|
||||
"members": "65328 members"
|
||||
},
|
||||
{
|
||||
"award": "Big Game Hunter",
|
||||
"link": "https://projecteuler.net/award=52",
|
||||
"description": "Solve twenty-five of the fifty hardest problems",
|
||||
"isCompleted": false,
|
||||
"progress": "0 / 25",
|
||||
"percentage": 0,
|
||||
"members": "138 members"
|
||||
},
|
||||
{
|
||||
"award": "Difficulty Explorer",
|
||||
"link": "https://projecteuler.net/award=53",
|
||||
"description": "Solve at least one problem at ten different difficulty levels",
|
||||
"isCompleted": false,
|
||||
"progress": "9 / 10",
|
||||
"percentage": 90,
|
||||
"members": "8358 members"
|
||||
},
|
||||
{
|
||||
"award": "Conquering Difficulties",
|
||||
"link": "https://projecteuler.net/award=54",
|
||||
"description": "Solve at least one problem at all of the difficulty levels",
|
||||
"isCompleted": false,
|
||||
"progress": "9 / 20",
|
||||
"percentage": 45,
|
||||
"members": "518 members"
|
||||
},
|
||||
{
|
||||
"award": "Mount Euler",
|
||||
"link": "https://projecteuler.net/award=55",
|
||||
"description": "Mastering the mountain of difficulty",
|
||||
"isCompleted": false,
|
||||
"progress": "1 / 20",
|
||||
"percentage": 5,
|
||||
"members": "63 members"
|
||||
},
|
||||
{
|
||||
"award": "The Centenarian",
|
||||
"link": "https://projecteuler.net/award=59",
|
||||
"description": "Solved a problem on one-hundred different days",
|
||||
"isCompleted": false,
|
||||
"progress": "31 / 100",
|
||||
"percentage": 31,
|
||||
"members": "647 members"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Contributor Awards",
|
||||
"awards": [
|
||||
{
|
||||
"award": "Bright Spark",
|
||||
"link": "https://projecteuler.net/award=61",
|
||||
"description": "Contributed to the development of a problem",
|
||||
"isCompleted": false,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "147 members"
|
||||
},
|
||||
{
|
||||
"award": "Brainstormer",
|
||||
"link": "https://projecteuler.net/award=62",
|
||||
"description": "Contributed to the development of five or more problems",
|
||||
"isCompleted": false,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "52 members"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Forum Based Awards",
|
||||
"awards": [
|
||||
{
|
||||
"award": "Hello World!",
|
||||
"link": "https://projecteuler.net/award=91",
|
||||
"description": "Made your first permanent post",
|
||||
"isCompleted": false,
|
||||
"progress": "",
|
||||
"percentage": 0,
|
||||
"members": "5522 members"
|
||||
},
|
||||
{
|
||||
"award": "Wise Words",
|
||||
"link": "https://projecteuler.net/award=92",
|
||||
"description": "Received five Kudos across all your permanent posts",
|
||||
"isCompleted": false,
|
||||
"progress": "0 / 5",
|
||||
"percentage": 0,
|
||||
"members": "1126 members"
|
||||
},
|
||||
{
|
||||
"award": "Valued Expositor",
|
||||
"link": "https://projecteuler.net/award=93",
|
||||
"description": "Received twenty-five Kudos across all your permanent posts",
|
||||
"isCompleted": false,
|
||||
"progress": "0 / 25",
|
||||
"percentage": 0,
|
||||
"members": "411 members"
|
||||
},
|
||||
{
|
||||
"award": "Esteemed Journalist",
|
||||
"link": "https://projecteuler.net/award=94",
|
||||
"description": "Received one-hundred Kudos across all your permanent posts",
|
||||
"isCompleted": false,
|
||||
"progress": "0 / 100",
|
||||
"percentage": 0,
|
||||
"members": "151 members"
|
||||
},
|
||||
{
|
||||
"award": "The Guru",
|
||||
"link": "https://projecteuler.net/award=95",
|
||||
"description": "Received ten Kudos for a permanent post in a single problem thread",
|
||||
"isCompleted": false,
|
||||
"progress": "0 / 10",
|
||||
"percentage": 0,
|
||||
"members": "459 members"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"friends": [
|
||||
{
|
||||
"rank": "1",
|
||||
"username": "fonkost",
|
||||
"solved": 385,
|
||||
"level": 15,
|
||||
"awards": 21
|
||||
},
|
||||
{
|
||||
"rank": "2",
|
||||
"username": "Artem Korsakov",
|
||||
"solved": 118,
|
||||
"level": 4,
|
||||
"awards": 8
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -13,18 +13,22 @@ tasks, awards, and friends' rankings.
|
|||
## Features
|
||||
|
||||
1. **Profile Information**:
|
||||
|
||||
- Displays your Project Euler account details, including username, alias, location,
|
||||
programming language, level, and number of solved problems.
|
||||
|
||||
2. **Progress Overview**:
|
||||
|
||||
- Shows your overall progress, including the percentage of problems solved
|
||||
and your rankings in global, regional, and language-specific leaderboards.
|
||||
|
||||
3. **Tasks**:
|
||||
|
||||
- Lists your current tasks, such as the number of problems remaining
|
||||
to reach the next level or improve your rankings.
|
||||
|
||||
4. **Awards**:
|
||||
|
||||
- Displays your progress toward earning Project Euler awards, including both completed and uncompleted awards.
|
||||
|
||||
5. **Friends**:
|
||||
|
|
@ -110,10 +114,10 @@ Solve problem 15; 27.1%
|
|||
|
||||
### Location progress
|
||||
|
||||
This section provides an overview of your ranking in the **Location rating** on Project Euler.
|
||||
Currently, this account is **not in the Top 100**, with **118 problems solved**.
|
||||
The table below breaks down the number of problems required to reach higher ranks,
|
||||
such as Top 100, Top 50, Top 25, Top 10, Top 5, and Top 1,
|
||||
This section provides an overview of your ranking in the **Location rating** on Project Euler.
|
||||
Currently, this account is **not in the Top 100**, with **118 problems solved**.
|
||||
The table below breaks down the number of problems required to reach higher ranks,
|
||||
such as Top 100, Top 50, Top 25, Top 10, Top 5, and Top 1,
|
||||
along with the number of problems remaining to achieve each milestone.
|
||||
|
||||
This section helps you track your progress and set goals for climbing the ranks in the Location leaderboard.
|
||||
|
|
@ -123,9 +127,9 @@ This section helps you track your progress and set goals for climbing the ranks
|
|||
### Language progress
|
||||
|
||||
This section highlights your ranking in the **Language rating** on Project Euler.
|
||||
This account is currently in **82nd place**, with **118 problems solved**.
|
||||
The table outlines the number of problems needed to advance to higher ranks,
|
||||
such as Top 50, Top 25, Top 10, Top 5, and Top 1,
|
||||
This account is currently in **82nd place**, with **118 problems solved**.
|
||||
The table outlines the number of problems needed to advance to higher ranks,
|
||||
such as Top 50, Top 25, Top 10, Top 5, and Top 1,
|
||||
along with the remaining problems required for each milestone.
|
||||
|
||||
This section helps you track your progress and set goals for climbing the ranks in the Language leaderboard.
|
||||
|
|
@ -134,10 +138,10 @@ This section helps you track your progress and set goals for climbing the ranks
|
|||
|
||||
### Level progress
|
||||
|
||||
This section provides an overview of your **level progression** on Project Euler.
|
||||
It displays your current level, the number of problems you've solved,
|
||||
and how close you are to reaching the next levels.
|
||||
Additionally, it shows how many members have achieved each level,
|
||||
This section provides an overview of your **level progression** on Project Euler.
|
||||
It displays your current level, the number of problems you've solved,
|
||||
and how close you are to reaching the next levels.
|
||||
Additionally, it shows how many members have achieved each level,
|
||||
giving you a sense of your standing within the community.
|
||||
|
||||
This section is designed to help you stay motivated and focused on your journey through Project Euler's levels.
|
||||
|
|
@ -147,11 +151,11 @@ Keep solving problems to climb higher and join the ranks of the top members!
|
|||
|
||||
### Awards
|
||||
|
||||
This section provides an overview of the **awards** you can earn on Project Euler.
|
||||
Awards are divided into three categories: **Problem Solving Awards**, **Contributor Awards**, and **Forum Based Awards**.
|
||||
This section provides an overview of the **awards** you can earn on Project Euler.
|
||||
Awards are divided into three categories: **Problem Solving Awards**, **Contributor Awards**, and **Forum Based Awards**.
|
||||
Each award has a description, the number of members who have earned it, and a progress bar to track your progress.
|
||||
|
||||
This section helps you stay motivated by showcasing your achievements and highlighting areas for improvement.
|
||||
This section helps you stay motivated by showcasing your achievements and highlighting areas for improvement.
|
||||
Keep solving problems, contributing, and engaging with the community to unlock more awards!
|
||||
|
||||
<img src="images/awards.png" alt="awards" width="500" />
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { fetchWithCookies } from './fetchUtils';
|
||||
import { saveDataToFile, loadDataFromFile, checkFileExists, ensureFolderExists } from './fileUtils';
|
||||
import {
|
||||
parseAccountData,
|
||||
parseAwardsData,
|
||||
|
|
@ -17,6 +18,7 @@ import { generateFriendsHTML } from './friendsBlock';
|
|||
import {
|
||||
AccountData,
|
||||
AwardBlockData,
|
||||
CacheData,
|
||||
FriendData,
|
||||
LevelData,
|
||||
PersonalTask,
|
||||
|
|
@ -33,24 +35,58 @@ const keepAliveName = 'keep_alive';
|
|||
* Fetches progress data and returns it as an HTMLElement.
|
||||
* @param session - The session cookie value.
|
||||
* @param keep_alive - The keep-alive cookie value.
|
||||
* @param retries - The number of retries in case of failure.
|
||||
* @param source - The source data for generating HTML.
|
||||
* @returns A Promise that resolves to an HTMLElement.
|
||||
*/
|
||||
export async function fetchProgress(session: string, keep_alive: string, source: Source): Promise<HTMLElement> {
|
||||
const cookies = `${sessionIdName}=${session}; ${keepAliveName}=${keep_alive}`;
|
||||
// Define the path to the plugin's cache folder and ensure it exists
|
||||
const folderPath = getPluginFolderPath();
|
||||
await ensureFolderExists(folderPath);
|
||||
const filePath = `${folderPath}/cache.json`;
|
||||
|
||||
// Attempt to load cached data from the file
|
||||
const savedData = await loadDataFromFile(filePath);
|
||||
|
||||
// If cached data exists, generate and return HTML from it
|
||||
if (savedData) {
|
||||
return generateHTML(savedData, source);
|
||||
}
|
||||
|
||||
// If no cached data is available, try to fetch fresh data from the server
|
||||
const fetchedData = await tryToFetchAndSaveProgress(session, keep_alive, filePath);
|
||||
|
||||
// If fetching fresh data is successful, generate and return HTML from it
|
||||
if (fetchedData) {
|
||||
return generateHTML(fetchedData, source);
|
||||
}
|
||||
|
||||
// If neither cached nor fresh data is available, create an error message
|
||||
const errorContainer = document.createElement('div');
|
||||
errorContainer.textContent = 'Error fetching progress. Please update your cookies in the settings and try again.';
|
||||
return errorContainer;
|
||||
}
|
||||
|
||||
function getPluginFolderPath(): string {
|
||||
return `${this.app.vault.configDir}/plugins/project-euler-stats/cache`;
|
||||
}
|
||||
|
||||
async function tryToFetchAndSaveProgress(session: string, keep_alive: string, filePath: string): Promise<CacheData | null> {
|
||||
const cookies = `${sessionIdName}=${session}; ${keepAliveName}=${keep_alive}`;
|
||||
|
||||
try {
|
||||
return await tryToFetchProgress(cookies, source);
|
||||
const cacheData = await tryToFetchProgress(cookies);
|
||||
|
||||
console.log('Я пошел фетчить прогресс, вот данные:', cacheData);
|
||||
|
||||
await saveDataToFile(filePath, cacheData);
|
||||
return cacheData;
|
||||
} catch (error) {
|
||||
console.error('Error fetching progress:', error);
|
||||
|
||||
const errorContainer = document.createElement('div');
|
||||
errorContainer.textContent = 'Error fetching progress. Please update your cookies in the settings and try again.';
|
||||
return errorContainer;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function tryToFetchProgress(cookies: string, source: Source): Promise<HTMLElement> {
|
||||
async function tryToFetchProgress(cookies: string): Promise<CacheData> {
|
||||
const [
|
||||
accountData,
|
||||
progressData,
|
||||
|
|
@ -70,19 +106,7 @@ async function tryToFetchProgress(cookies: string, source: Source): Promise<HTML
|
|||
const { locationRating, languageRating } = await fetchRatings(locationUrl, languageUrl, cookies);
|
||||
const awardsData = await fetchAwardsData(cookies);
|
||||
|
||||
return generateHTML(
|
||||
accountData,
|
||||
progressData,
|
||||
euleriansPlace,
|
||||
locationUrl,
|
||||
languageUrl,
|
||||
locationRating,
|
||||
languageRating,
|
||||
levelDataArray,
|
||||
awardsData,
|
||||
friends,
|
||||
source
|
||||
);
|
||||
return new CacheData(accountData, progressData, euleriansPlace, locationUrl, languageUrl, locationRating, languageRating, levelDataArray, awardsData, friends);
|
||||
}
|
||||
|
||||
async function fetchData<T>(url: string, parser: (html: string) => T, cookies: string): Promise<T> {
|
||||
|
|
@ -112,43 +136,31 @@ async function fetchAwardsData(cookies: string): Promise<AwardBlockData[]> {
|
|||
return parseAwardsData(myAwardsHtml, awardsHtml);
|
||||
}
|
||||
|
||||
function generateHTML(
|
||||
accountData: AccountData,
|
||||
progressData: ProgressData,
|
||||
euleriansPlace: string,
|
||||
locationUrl: string,
|
||||
languageUrl: string,
|
||||
locationRating: RatingData,
|
||||
languageRating: RatingData,
|
||||
levelDataArray: LevelData[],
|
||||
awardsData: AwardBlockData[],
|
||||
friends: FriendData[],
|
||||
source: Source
|
||||
): HTMLElement {
|
||||
function generateHTML(cache: CacheData, source: Source): HTMLElement {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const profileElement = generateProfileHTML(accountData, progressData);
|
||||
const profileElement = generateProfileHTML(cache.accountData, cache.progressData);
|
||||
container.appendChild(profileElement);
|
||||
|
||||
const imageElement = generateImageHTML(accountData.account);
|
||||
const imageElement = generateImageHTML(cache.accountData.account);
|
||||
container.appendChild(imageElement);
|
||||
|
||||
const progressElement = generateProgressTableHTML(accountData, progressData, locationUrl, languageUrl, euleriansPlace, locationRating, languageRating, awardsData, source);
|
||||
const progressElement = generateProgressTableHTML(cache, source);
|
||||
container.appendChild(progressElement);
|
||||
|
||||
const locationRatingElement = generateRatingTableHTML(locationUrl, accountData.location, progressData.solved, locationRating);
|
||||
const locationRatingElement = generateRatingTableHTML(cache.locationUrl, cache.accountData.location, cache.progressData.solved, cache.locationRating);
|
||||
container.appendChild(locationRatingElement);
|
||||
|
||||
const languageRatingElement = generateRatingTableHTML(languageUrl, accountData.language, progressData.solved, languageRating);
|
||||
const languageRatingElement = generateRatingTableHTML(cache.languageUrl, cache.accountData.language, cache.progressData.solved, cache.languageRating);
|
||||
container.appendChild(languageRatingElement);
|
||||
|
||||
const levelsElement = generateLevelsTableHTML(progressData, levelDataArray);
|
||||
const levelsElement = generateLevelsTableHTML(cache.progressData, cache.levelDataArray);
|
||||
container.appendChild(levelsElement);
|
||||
|
||||
const awardsElement = generateAwardsTableHTML(awardsData);
|
||||
const awardsElement = generateAwardsTableHTML(cache.awardsData);
|
||||
container.appendChild(awardsElement);
|
||||
|
||||
const friendsElement = generateFriendsHTML(friends, accountData);
|
||||
const friendsElement = generateFriendsHTML(cache.friends, cache.accountData);
|
||||
container.appendChild(friendsElement);
|
||||
|
||||
return container;
|
||||
|
|
|
|||
32
helpers/fileUtils.ts
Normal file
32
helpers/fileUtils.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { App, Plugin, TFile } from 'obsidian';
|
||||
import { CacheData } from './types';
|
||||
|
||||
export async function saveDataToFile(filePath: string, data: CacheData): Promise<void> {
|
||||
try {
|
||||
const jsonData = JSON.stringify(data, null, 2);
|
||||
await this.app.vault.adapter.write(filePath, jsonData);
|
||||
} catch (error) {
|
||||
console.error('Failed to save data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadDataFromFile(filePath: string): Promise<CacheData | null> {
|
||||
try {
|
||||
const jsonData = await this.app.vault.adapter.read(filePath);
|
||||
const rawData = JSON.parse(jsonData);
|
||||
return CacheData.fromObject(rawData);
|
||||
} catch (error) {
|
||||
console.error('Failed to load data:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkFileExists(filePath: string): Promise<boolean> {
|
||||
return await this.app.vault.adapter.exists(filePath);
|
||||
}
|
||||
|
||||
export async function ensureFolderExists(folderPath: string): Promise<void> {
|
||||
if (!await this.app.vault.adapter.exists(folderPath)) {
|
||||
await this.app.vault.adapter.mkdir(folderPath);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { AccountData, AwardData, AwardBlockData, PersonalTask, ProgressData, RatingData, Source } from './types';
|
||||
import { AccountData, AwardData, AwardBlockData, CacheData, PersonalTask, ProgressData, RatingData, Source } from './types';
|
||||
import { createProgressBar, createSectionHeader } from './commonBlocks';
|
||||
|
||||
interface Result {
|
||||
|
|
@ -206,39 +206,25 @@ function createTasksList(
|
|||
|
||||
/**
|
||||
* Generates HTML for the progress table.
|
||||
* @param accountData - The account data.
|
||||
* @param progressData - The progress data.
|
||||
* @param locationUrl - The URL for the location rating.
|
||||
* @param languageUrl - The URL for the language rating.
|
||||
* @param euleriansPlace - The user's place in Eulerians' rating.
|
||||
* @param locationRating - The location rating data.
|
||||
* @param languageRating - The language rating data.
|
||||
* @param awardsData - The awards data.
|
||||
* @param cache - The cache data.
|
||||
* @param source - The source data.
|
||||
* @returns The generated HTMLElement (progress table container).
|
||||
*/
|
||||
export function generateProgressTableHTML(
|
||||
accountData: AccountData,
|
||||
progressData: ProgressData,
|
||||
locationUrl: string,
|
||||
languageUrl: string,
|
||||
euleriansPlace: string,
|
||||
locationRating: RatingData,
|
||||
languageRating: RatingData,
|
||||
awardsData: AwardBlockData[],
|
||||
cache: CacheData,
|
||||
source: Source
|
||||
): HTMLElement {
|
||||
const progressContainer = document.createElement('div');
|
||||
progressContainer.appendChild(createSectionHeader('Progress'));
|
||||
progressContainer.appendChild(createProgressBar(progressData.percentage));
|
||||
progressContainer.appendChild(createProgressBar(cache.progressData.percentage));
|
||||
progressContainer.appendChild(createProgressTable(
|
||||
progressData,
|
||||
euleriansPlace,
|
||||
locationUrl,
|
||||
languageUrl,
|
||||
accountData,
|
||||
locationRating,
|
||||
languageRating
|
||||
cache.progressData,
|
||||
cache.euleriansPlace,
|
||||
cache.locationUrl,
|
||||
cache.languageUrl,
|
||||
cache.accountData,
|
||||
cache.locationRating,
|
||||
cache.languageRating
|
||||
));
|
||||
|
||||
// Personal tasks section
|
||||
|
|
@ -252,11 +238,11 @@ export function generateProgressTableHTML(
|
|||
tasksHeader.textContent = 'Tasks';
|
||||
progressContainer.appendChild(tasksHeader);
|
||||
progressContainer.appendChild(createTasksList(
|
||||
progressData,
|
||||
accountData,
|
||||
locationRating,
|
||||
languageRating,
|
||||
awardsData
|
||||
cache.progressData,
|
||||
cache.accountData,
|
||||
cache.locationRating,
|
||||
cache.languageRating,
|
||||
cache.awardsData
|
||||
));
|
||||
|
||||
return progressContainer;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,15 @@ export class AccountData {
|
|||
public location: string,
|
||||
public language: string
|
||||
) {}
|
||||
|
||||
static fromObject(obj: any): AccountData {
|
||||
return new AccountData(
|
||||
obj.account,
|
||||
obj.alias,
|
||||
obj.location,
|
||||
obj.language
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -21,6 +30,16 @@ export class ProgressData {
|
|||
public progress: string,
|
||||
public toTheNext: string
|
||||
) {}
|
||||
|
||||
static fromObject(obj: any): ProgressData {
|
||||
return new ProgressData(
|
||||
obj.level,
|
||||
obj.solved,
|
||||
obj.percentage,
|
||||
obj.progress,
|
||||
obj.toTheNext
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -36,6 +55,18 @@ export class RatingData {
|
|||
public top5: number,
|
||||
public top1: number
|
||||
) {}
|
||||
|
||||
static fromObject(obj: any): RatingData {
|
||||
return new RatingData(
|
||||
obj.place,
|
||||
obj.top100,
|
||||
obj.top50,
|
||||
obj.top25,
|
||||
obj.top10,
|
||||
obj.top5,
|
||||
obj.top1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -51,6 +82,13 @@ export class LevelData {
|
|||
public level: string,
|
||||
public members: string
|
||||
) {}
|
||||
|
||||
static fromObject(obj: any): LevelData {
|
||||
return new LevelData(
|
||||
obj.level,
|
||||
obj.members
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -67,6 +105,13 @@ export class AwardBlockData {
|
|||
public awards: AwardData[]
|
||||
) {}
|
||||
|
||||
static fromObject(obj: any): AwardBlockData {
|
||||
return new AwardBlockData(
|
||||
obj.name,
|
||||
obj.awards.map((award: any) => AwardData.fromObject(award))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of completed awards in this block.
|
||||
* @returns The number of completed awards.
|
||||
|
|
@ -99,6 +144,18 @@ export class AwardData {
|
|||
public percentage: number,
|
||||
public members: string
|
||||
) {}
|
||||
|
||||
static fromObject(obj: any): AwardData {
|
||||
return new AwardData(
|
||||
obj.award,
|
||||
obj.link,
|
||||
obj.description,
|
||||
obj.isCompleted,
|
||||
obj.progress,
|
||||
obj.percentage,
|
||||
obj.members
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class FriendData {
|
||||
|
|
@ -109,6 +166,46 @@ export class FriendData {
|
|||
public level: number,
|
||||
public awards: number
|
||||
) {}
|
||||
|
||||
static fromObject(obj: any): FriendData {
|
||||
return new FriendData(
|
||||
obj.rank,
|
||||
obj.username,
|
||||
obj.solved,
|
||||
obj.level,
|
||||
obj.awards
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class CacheData {
|
||||
constructor(
|
||||
public accountData: AccountData,
|
||||
public progressData: ProgressData,
|
||||
public euleriansPlace: string,
|
||||
public locationUrl: string,
|
||||
public languageUrl: string,
|
||||
public locationRating: RatingData,
|
||||
public languageRating: RatingData,
|
||||
public levelDataArray: LevelData[],
|
||||
public awardsData: AwardBlockData[],
|
||||
public friends: FriendData[]
|
||||
) {}
|
||||
|
||||
static fromObject(obj: any): CacheData {
|
||||
return new CacheData(
|
||||
AccountData.fromObject(obj.accountData),
|
||||
ProgressData.fromObject(obj.progressData),
|
||||
obj.euleriansPlace,
|
||||
obj.locationUrl,
|
||||
obj.languageUrl,
|
||||
RatingData.fromObject(obj.locationRating),
|
||||
RatingData.fromObject(obj.languageRating),
|
||||
obj.levelDataArray.map((level: any) => LevelData.fromObject(level)),
|
||||
obj.awardsData.map((awardBlock: any) => AwardBlockData.fromObject(awardBlock)),
|
||||
obj.friends.map((friend: any) => FriendData.fromObject(friend))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Source {
|
||||
|
|
|
|||
Loading…
Reference in a new issue