config.json


فایل config.json پیکربندی مسیر را توصیف می‌کند. این فایل اطلاعات مهمی مانند تمرین‌ها و مفاهیم مسیر را در خود دارد.

فراداده

این خصوصیت‌های سطح‌بالا حاوی فراداده‌ی عمومی مسیر هستند:

  • language: زبان مسیر (مثلاً "C#"). طول آن باید حداکثر ۲۵۵ باشد. (الزامی)
  • slug: زبان مسیر به‌صورت رشته‌ای با حروف کوچک و در قالب kebab-case (مثلاً "csharp"). طول آن باید حداکثر ۲۵۵ باشد. (الزامی)
  • active: یک مقدار boolean که نشان می‌دهد مسیر فعال است یا نه (یعنی دانشجوها می‌توانند در وب‌سایت به مسیر بپیوندند) (الزامی)
  • blurb: توضیح کوتاهی از زبان. طول آن باید حداکثر ۴۰۰ باشد. (الزامی)
  • version: نسخه‌ی فایل config.json (در حال حاضر ثابت و برابر با 3) (الزامی)
  • online_editor: یک شیء که تنظیمات ویرایشگر آنلاین را توصیف می‌کند: (الزامی)
    • indent_style: یا "space" یا "tab" (الزامی)
    • indent_size: اندازه‌ی تورفتگی به‌صورت یک عدد صحیح (مثلاً 4) (الزامی)
    • highlightjs_language: شناسه‌ی زبان برای Highlight.js (فهرست کامل شناسه‌ها را ببینید) (اختیاری)
  • status: یک شیء که توصیف می‌کند کدام ویژگی‌های نسخه‌ی ۳ باید فعال باشند: (الزامی)
    • concept_exercises: یک مقدار boolean که نشان می‌دهد آیا تمرین‌های مفهومی ساخته شده‌اند یا نه (الزامی). وقتی true باشد، رابط وب‌سایت Exercism تغییر می‌کند تا نشان دهد تمرین‌های مفهومی برای مسیر در دسترس‌اند.
    • test_runner: یک مقدار boolean که نشان می‌دهد آیا test runner پیاده‌سازی شده است یا نه (الزامی). وقتی true باشد، راه‌حل‌های ارسال‌شده را از زیرساخت تست ما عبور می‌دهیم و نتایج را در وب‌سایت نمایش می‌دهیم. وب‌سایت همچنین به دانشجوها اجازه می‌دهد از داخل ویرایشگر آنلاین یک اجرای Test را آغاز کنند.
    • representer: یک مقدار boolean که نشان می‌دهد آیا representer پیاده‌سازی شده است یا نه (الزامی)
    • analyzer: یک مقدار boolean که نشان می‌دهد آیا analyzer پیاده‌سازی شده است یا نه (الزامی)
  • files: الگوهای مکان فایل‌هایی که در یک تمرین استفاده می‌شوند، نسبت به پوشه‌ی تمرین. (اختیاری)
    • solution: الگوی فایل(های) پیاده‌سازی stub (اختیاری)
    • test: الگوی فایل(های) Test (اختیاری)
    • example: الگوی فایل(های) پیاده‌سازی مثال (اختیاری)
    • exemplar: الگوی فایل(های) پیاده‌سازی نمونه (اختیاری)
    • editor: الگوهای فایل(های) فقط‌خواندنی اضافی ویرایشگر (اختیاری)
  • test_runner: یک شیء که test runner مسیر را توصیف می‌کند (در صورت وجود): (الزامی اگر status.test_runner برابر true باشد)
    • average_run_time: یک مقدار number صحیح برای تعداد ثانیه‌هایی که test runner به‌طور میانگین برای اجرا صرف می‌کند (مثلاً 4) (الزامی اگر status.test_runner برابر true باشد)
  • approaches: یک شیء با فراداده‌ی رویکردهای مسیر: (الزامی اگر مسیر رویکردی داشته باشد)
    • snippet_extension: یک مقدار رشته‌ای که برای پسوند فایل snippet استفاده می‌شود (مثلاً rb) (الزامی اگر مسیر رویکردی داشته باشد)

فایل

از این کلید برای مشخص کردن مکان فایل‌ها در سطح کل مسیر استفاده می‌شود. به‌جای اینکه نگهدارنده‌ها مجبور باشند کلید files را به‌صورت دستی در فایل‌های config.json تمرین‌ها تنظیم کنند، configlet می‌تواند آن را با استفاده از این الگوهای سطح مسیر به‌صورت خودکار پر کند.

الگوهای فایلی که در شیء files تعریف شده‌اند از این جانگهدارها پشتیبانی می‌کنند:

  • %{kebab_slug}: slug تمرین در قالب kebab-case (مثلاً bit-manipulation)
  • %{snake_slug}: slug تمرین در قالب snake_case (مثلاً bit_manipulation)
  • %{camel_slug}: slug تمرین در قالب camelCase (مثلاً bitManipulation)
  • %{pascal_slug}: slug تمرین در قالب PascalCase (مثلاً BitManipulation)

پشتیبانی از configlet اضافه خواهد شد تا از این الگوها برای پر کردن کلید files در فایل .meta/config.json یک تمرین استفاده کند.

مثال

{
  "language": "C#",
  "slug": "csharp",
  "active": true,
  "status": {
    "concept_exercises": true,
    "test_runner": true,
    "representer": false,
    "analyzer": false
  },
  "blurb": "C# is a modern, object-oriented language with lots of great features, such as type-inference and async/await. The tooling is excellent, and there is extensive, well-written documentation.",
  "version": 3,
  "online_editor": {
    "indent_style": "space",
    "indent_size": 4,
    "highlightjs_language": "csharp"
  },
  "test_runner": {
    "average_run_time": 2
  },
  "files": {
    "solution": [
      "%{pascal_slug}.cs"
    ],
    "test": [
      "%{pascal_slug}Tests.cs"
    ],
    "example": [
      ".meta/Example.cs"
    ],
    "exemplar": [
      ".meta/Exemplar.cs"
    ]
  }
}

تمرین

کلید سطح‌بالای exercises یک شیء است با سه کلید ممکن:

  • concept: آرایه‌ای است که تمرین‌های مفهومی مسیر را فهرست می‌کند
  • practice: آرایه‌ای است که تمرین‌های عملی مسیر را فهرست می‌کند
  • foregone: آرایه‌ای است که slug تمرین‌هایی را فهرست می‌کند که مسیر آن‌ها را پیاده‌سازی نمی‌کند

تمرین مفهومی

هر تمرین مفهومی یک عضو در آرایه‌ی exercises.concept است. ترتیب تمرین‌ها در وب‌سایت همان ترتیب فهرست‌شدن آن‌ها در این فایل است و باید با ترتیب معمول حل آن‌ها مطابقت داشته باشد. یک تمرین مفهومی از این فیلدها تشکیل می‌شود:

  • uuid: یک UUID نسخه‌ی ۴ که تمرین را به‌طور یکتا مشخص می‌کند. این UUID باید هم درون مسیر و هم میان همه‌ی مسیرها یکتا باشد و هرگز نباید تغییر کند
  • slug: slug تمرین، که رشته‌ای با حروف کوچک در قالب kebab-case است. این slug باید در میان همه‌ی slugهای تمرین‌های مفهومی و عملی درون مسیر یکتا باشد. طول آن باید حداکثر ۲۵۵ باشد.
  • name: اسم تمرین. طول آن باید حداکثر ۲۵۵ باشد.
  • concepts: آرایه‌ای از slugهای مفاهیمی که در این تمرین مفهومی آموزش داده می‌شوند
  • prerequisites: آرایه‌ای از slugهای مفاهیمی که قفلشان باید پیش از آن‌که دانشجو بتواند این تمرین را شروع کند باز شده باشد
  • status (اختیاری): وضعیت تمرین، که یکی از "wip"، "beta"، "active" یا "deprecated" است؛ اگر مشخص نشود، به‌صورت پیش‌فرض "active" در نظر گرفته می‌شود
    • wip: تمرینی که هنوز در حال انجام است و برای استفاده‌ی عمومی آماده نیست. تمرین‌هایی با این برچسب در رابط کاربری به دانشجوها نشان داده نمی‌شوند و در منطق قفل‌گشایی استفاده نمی‌شوند. ممکن است برای نگهدارنده‌ها نمایش داده شوند.
    • beta: به تمرین‌های فعالی اشاره دارد که تازه‌اند و می‌خواهیم درباره‌شان بازخورد بگیریم. برای این تمرین‌ها برچسب beta را در سایت نمایش می‌دهیم، همراه با فراخوان به اقدام «لطفاً به ما بازخورد بدهید.»
    • active: وضعیت عادی تمرین‌های فعال
    • deprecated: تمرین‌هایی که دیگر به دانشجوهایی که آن‌ها را شروع نکرده‌اند نشان داده نمی‌شوند (در این مرحله قابل استفاده نیستند). برای اطلاعات بیشتر تمرین منسوخ‌شده را ببینید.

مثال

{
  "exercises": {
    "concept": [
      {
        "slug": "cars-assemble",
        "name": "Cars, Assemble!",
        "uuid": "93fbc7cf-3a7e-4450-ad22-e30129c36bb9",
        "concepts": [
          "if-statements",
          "numbers"
        ],
        "prerequisites": [
          "basics"
        ]
      },
      ...
    ]
  }
}

نمونه‌ی کار در حال انجام

{
  "exercises": {
    "concept": [
      {
        "slug": "cars-assemble",
        "name": "Cars, Assemble!",
        "uuid": "93fbc7cf-3a7e-4450-ad22-e30129c36bb9",
        "concepts": [
          "if-statements",
          "numbers"
        ],
        "prerequisites": [
          "basics"
        ],
        "status": "wip"
      },
      ...
    ]
  }
}

تمرین عملی

هر تمرین عملی یک عضو در آرایه‌ی exercises.practice است. یک تمرین عملی از این فیلدها تشکیل می‌شود:

  • uuid: یک UUID نسخه‌ی ۴ که تمرین را به‌طور یکتا مشخص می‌کند. این UUID باید هم درون مسیر و هم میان همه‌ی مسیرها یکتا باشد و هرگز نباید تغییر کند
  • slug: slug تمرین، که رشته‌ای با حروف کوچک در قالب kebab-case است. این slug باید در میان همه‌ی slugهای تمرین‌های مفهومی و عملی درون مسیر یکتا باشد. طول آن باید حداکثر ۲۵۵ باشد.
  • name: اسم تمرین. طول آن باید حداکثر ۲۵۵ باشد.
  • practices: آرایه‌ای از slugهای مفاهیمی که تمرین به دانشجوها در تمرین کردن‌شان کمک می‌کند
  • prerequisites: آرایه‌ای از slugهای مفاهیمی که قفلشان باید پیش از آن‌که دانشجو بتواند تمرین را شروع کند باز شده باشد
  • difficulty: عددی که سختی تمرین را نشان می‌دهد. این عدد باید در بازه‌ی ۱ (آسان‌ترین) تا ۱۰ (سخت‌ترین) باشد. وب‌سایت سختی را به این شکل تفسیر می‌کند:
    • ۱، ۲، ۳: آسان
    • ۴، ۵، ۶، ۷: متوسط
    • ۸، ۹، ۱۰: سخت
  • status (اختیاری): وضعیت تمرین، که یکی از "wip"، "beta"، "active" یا "deprecated" است؛ اگر مشخص نشود، به‌صورت پیش‌فرض "active" در نظر گرفته می‌شود
    • wip: تمرینی که هنوز در حال انجام است و برای استفاده‌ی عمومی آماده نیست. تمرین‌هایی با این برچسب در رابط کاربری به دانشجوها نشان داده نمی‌شوند و در منطق قفل‌گشایی استفاده نمی‌شوند. ممکن است برای نگهدارنده‌ها نمایش داده شوند.
    • beta: به تمرین‌های فعالی اشاره دارد که تازه‌اند و می‌خواهیم درباره‌شان بازخورد بگیریم. برای این تمرین‌ها برچسب beta را در سایت نمایش می‌دهیم، همراه با فراخوان به اقدام «لطفاً به ما بازخورد بدهید»
    • active: وضعیت عادی تمرین‌های فعال
    • deprecated: تمرین‌هایی که دیگر به دانشجوهایی که آن‌ها را شروع نکرده‌اند نشان داده نمی‌شوند (در این مرحله قابل استفاده نیستند).

«ترتیب پیشنهادی» تمرین‌های عملی در وب‌سایت با ترتیب تمرین‌ها در آرایه‌ی practice مطابقت دارد.

مثال

{
  "exercises": {
    "practice": [
      {
        "slug": "leap",
        "name": "Leap",
        "uuid": "8ba15933-29a2-49b1-a9ce-70474bad3007",
        "practices": [
          "if-statements",
          "numbers",
          "operator-precedence"
        ],
        "prerequisites": [
          "if-statements",
          "numbers"
        ],
        "difficulty": 1
      },
      ...
    ]
  }
}

نمونه‌ی beta

{
  "exercises": {
    "practice": [
      {
        "slug": "leap",
        "name": "Leap",
        "uuid": "8ba15933-29a2-49b1-a9ce-70474bad3007",
        "practices": [
          "if-statements",
          "numbers",
          "operator-precedence"
        ],
        "prerequisites": [
          "if-statements",
          "numbers"
        ],
        "difficulty": 1,
        "status": "beta"
      },
      ...
    ]
  }
}

تمرین کنارگذاشته‌شده

اگر یک مسیر بداند که نمی‌خواهد تمرینی را که در مخزن Problem Specifications تعریف شده پیاده‌سازی کند، می‌تواند slug آن تمرین را به کلید exercises.foregone اضافه کند. configlet هنگام خروجی گرفتن از تمرین‌های پیاده‌سازی‌نشده‌ی مسیر، تمرین‌های کنارگذاشته‌شده را نادیده می‌گیرد.

دلایلی که ممکن است یک مسیر نخواهد تمرینی را پیاده‌سازی کند می‌تواند این‌ها باشد:

  • پیاده‌سازی معقول تمرین با آن زبان امکان‌پذیر نیست. برای نمونه، تمرین lens-person نیاز دارد که زبان از lenses پشتیبانی کند.
  • موضوع تمرین با زبان هم‌خوانی ندارد. برای مثال، برای برخی زبان‌های سطح‌بالا، یک تمرین سطح‌پایین دستکاری بیت ممکن است منطقی نباشد.

مثال

{
  "exercises": {
    "foregone": [
      "lens-person"
    ]
  }
}

مفهوم

هر مفهوم یک عضو در آرایه‌ی سطح‌بالای concepts است. یک مفهوم از این فیلدها تشکیل می‌شود:

  • uuid: یک UUID نسخه‌ی ۴ که مفهوم را به‌طور یکتا مشخص می‌کند. این UUID باید هم درون مسیر و هم میان همه‌ی مسیرها یکتا باشد و هرگز نباید تغییر کند
  • slug: slug مفهوم، که رشته‌ای با حروف کوچک در قالب kebab-case است. این slug باید در میان همه‌ی مفاهیم درون مسیر یکتا باشد. طول آن باید حداکثر ۲۵۵ باشد.
  • name: اسم مفهوم. طول آن باید حداکثر ۲۵۵ باشد.
  • tags: شرایطی را مشخص می‌کند که یک ارسال به یک رویکرد پیوند داده می‌شود. (اختیاری)
    • all: آرایه‌ای از برچسب‌ها که همه‌شان باید در یک ارسال موجود باشند (اختیاری، مگر اینکه any هیچ عضوی نداشته باشد)
    • any: آرایه‌ای از برچسب‌ها که دست‌کم یکی از آن‌ها باید در یک ارسال موجود باشد (اختیاری، مگر اینکه all هیچ عضوی نداشته باشد)
    • not: هیچ‌یک از این برچسب‌ها نباید در یک ارسال موجود باشند (اختیاری)

مثال

{
  "concepts": [
    {
      "uuid": "b9a421b2-c5ff-4213-bd6d-b886da31ea0d",
      "slug": "numbers",
      "name": "Numbers",
      "tags": {
        "all": [
          "concept:number"
        ]
      }
    }
  ]
}

ویژگی کلیدی

ویژگی‌های کلیدی زبان به‌طور خلاصه توصیف می‌کنند که مهم‌ترین ویژگی‌های زبان چه هستند. هدفشان معرفی ویژگی‌های جالب‌تر یک زبان به دانشجوهای بالقوه است. عنوان‌ها باید بکوشند کمترین اصطلاح فنی ممکن را به کار ببرند، با توجه به اینکه دانشجوها ممکن است پیش از یادگیری آن زبان با معنی اصطلاحات مخصوص آن زبان آشنا نباشند.

ویژگی‌های کلیدی در فیلد سطح‌بالای key_features مشخص می‌شوند که به‌صورت آرایه‌ای از اشیاء با این فیلدها تعریف می‌شود:

  • title: سرصفحه‌ی مختصری برای ویژگی کلیدی. طول آن باید حداکثر ۲۵ باشد. از Markdown پشتیبانی نمی‌شود.
  • content: توصیفی از ویژگی کلیدی. طول آن باید حداکثر ۱۰۰ باشد. از Markdown پشتیبانی نمی‌شود.
  • icon: آیکونی که برای این ویژگی نمایش داده می‌شود. می‌توانید آیکونی را انتخاب کنید که به نظرتان مناسب است، فارغ از اسمش. می‌توانید از این آیکون‌ها استفاده کنید:
    • community
    • concurrency
    • cross-platform
    • documentation
    • dynamically-typed
    • easy
    • embeddable
    • evolving
    • expressive
    • extensible
    • fast
    • fun
    • functional
    • garbage-collected
    • general-purpose
    • homoiconic
    • immutable
    • interactive
    • interop
    • multi-paradigm
    • portable
    • powerful
    • productive
    • safe
    • scientific
    • small
    • stable
    • statically-typed
    • tooling
    • web
    • widely-used

می‌توانید ظاهر بصری این آیکون‌ها را در بخش آیکون‌های ویژگی کلیدی ببینید.

باید دقیقاً ۶ ویژگی کلیدی مشخص شود.

مثال

{
  "key_features": [
    {
      "title": "Fault-tolerant",
      "content": "Elixir runs on the Erlang VM, known for running low-latency, distributed and fault-tolerant systems.",
      "icon": "safe"
    },
    ...
  ],
}

برچسب

مسیرها می‌توانند با برچسب‌ها نشانه‌گذاری شوند، که امکان جست‌وجوی مسیرها با ترکیب برچسب مشخص را فراهم می‌کند.

مسیر باید برچسب‌هایش را بر اساس کاربرد عمومی زبانش انتخاب کند. برای مثال، دانشجویی را تصور کنید که با خود می‌گوید: «می‌خواهم یادگیری ماشین کار کنم، چه زبانی را انتخاب کنم؟»، یا «می‌خواهم برنامه‌نویسی تابعی یاد بگیرم، کدام زبان را انتخاب کنم؟». اگر زبان شما گزینه‌ی خوبی باشد، آن برچسب را به آن بدهید. اگر زبان شما از برخی ایده‌های تابعی پشتیبانی می‌کند اما به‌ندرت استفاده می‌شوند، یا شمار کمی از افراد با آن یادگیری ماشین انجام می‌دهند اما نادر است، آن برچسب‌ها را اعمال نکنید.

برچسب‌ها در فیلد سطح‌بالای tags مشخص می‌شوند که به‌صورت آرایه‌ای از رشته‌ها تعریف می‌شود. می‌توان از این برچسب‌ها استفاده کرد (گروه‌بندی‌شده بر اساس دسته):

پارادایم

  • paradigm/array: زبان یک زبان برنامه‌نویسی آرایه‌ای است
  • paradigm/declarative: زبان از سبک برنامه‌نویسی اعلانی پشتیبانی می‌کند
  • paradigm/functional: زبان از سبک برنامه‌نویسی تابعی پشتیبانی می‌کند
  • paradigm/imperative: زبان از سبک برنامه‌نویسی دستوری پشتیبانی می‌کند
  • paradigm/logic: زبان از سبک برنامه‌نویسی مبتنی بر منطق پشتیبانی می‌کند
  • paradigm/object_oriented: زبان از سبک برنامه‌نویسی شیءگرا پشتیبانی می‌کند
  • paradigm/procedural: زبان از سبک برنامه‌نویسی رویه‌ای پشتیبانی می‌کند
  • paradigm/stack-oriented: زبان از سبک برنامه‌نویسی پشته‌ای پشتیبانی می‌کند

نوع‌دهی

  • typing/static: زبان از نوع‌دهی ایستا استفاده می‌کند
  • typing/gradual: زبان از نوع‌دهی تدریجی استفاده می‌کند
  • typing/dynamic: زبان از نوع‌دهی پویا استفاده می‌کند
  • typing/strong: زبان از نوع‌دهی قوی استفاده می‌کند
  • typing/weak: زبان از نوع‌دهی ضعیف استفاده می‌کند

حالت اجرا

  • execution_mode/compiled: کد پیش از اجرا ابتدا کامپایل می‌شود
  • execution_mode/interpreted: کد مستقیماً تفسیر می‌شود

پلتفرم

  • platform/windows: روی Windows اجرا می‌شود
  • platform/mac: روی Mac اجرا می‌شود
  • platform/linux: روی Linux اجرا می‌شود
  • platform/ios: روی iOS اجرا می‌شود
  • platform/android: روی Android اجرا می‌شود
  • platform/web: روی مرورگر اجرا می‌شود

محیط اجرا

  • runtime/standalone_executable: به‌صورت فایل اجرایی مستقل اجرا می‌شود
  • runtime/language_specific: روی محیط اجرای مخصوص زبان اجرا می‌شود
  • runtime/clr: روی Common Language Runtime (.NET) اجرا می‌شود
  • runtime/jvm: روی JVM (Java) اجرا می‌شود
  • runtime/beam: روی BEAM (Erlang) اجرا می‌شود
  • runtime/wasmtime: روی Wasmtime (WebAssembly) اجرا می‌شود

کاربرد

  • used_for/artificial_intelligence: AI
  • used_for/backends: Backend
  • used_for/cross_platform_development: توسعه‌ی چندسکویی
  • used_for/embedded_systems: سیستم‌های نهفته
  • used_for/financial_systems: سیستم‌های مالی
  • used_for/frontends: Frontend
  • used_for/games: بازی
  • used_for/guis: رابط‌های گرافیکی
  • used_for/mobile: موبایل
  • used_for/robotics: رباتیک
  • used_for/scientific_calculations: محاسبات علمی
  • used_for/scripts: اسکریپت
  • used_for/web_development: توسعه‌ی وب

توجه کنید که گنجاندن چند برچسب از یک دسته‌ی واحد کاملاً اشکالی ندارد.

مثال

{
  "tags": [
    "paradigm/declarative",
    "paradigm/functional",
    "paradigm/object_oriented",
    "platform/linux",
    "platform/windows",
    "runtime/jvm"
  ]
}

مثال

این نمونه‌ای است از اینکه یک فایل config.json معتبر چگونه می‌تواند باشد:

{
  "language": "C#",
  "slug": "csharp",
  "active": true,
  "status": {
    "concept_exercises": true,
    "test_runner": true,
    "representer": false,
    "analyzer": false
  },
  "blurb": "C# is a modern, object-oriented language with lots of great features, such as type-inference and async/await. The tooling is excellent, and there is extensive, well-written documentation.",
  "version": 3,
  "online_editor": {
    "indent_style": "space",
    "indent_size": 4,
    "highlightjs_language": "csharp"
  },
  "test_runner": {
    "average_run_time": 2
  },
  "files": {
    "solution": [
      "%{pascal_slug}.cs"
    ],
    "test": [
      "%{pascal_slug}Tests.cs"
    ],
    "example": [
      ".meta/Example.cs"
    ],
    "exemplar": [
      ".meta/Exemplar.cs"
    ]
  },
  "exercises": {
    "concept": [
      {
        "slug": "lucians-luscious-lasagna",
        "name": "Lucian's Luscious Lasagna",
        "uuid": "7d358894-4fbd-4c91-b49f-d68f1c5aa6bc",
        "concepts": [
          "basics"
        ],
        "prerequisites": []
      },
      {
        "slug": "cars-assemble",
        "name": "Cars, Assemble!",
        "uuid": "93fbc7cf-3a7e-4450-ad22-e30129c36bb9",
        "concepts": [
          "if-statements",
          "numbers"
        ],
        "prerequisites": [
          "basics"
        ],
        "status": "wip"
      }
    ],
    "practice": [
      {
        "slug": "hello-world",
        "name": "Hello, World!",
        "uuid": "6c88f46b-5acb-4fae-a6ec-b48ae3f8168f",
        "practices": [
          "strings"
        ],
        "prerequisites": [
          "basics"
        ],
        "difficulty": 1
      },
      {
        "slug": "leap",
        "name": "Leap",
        "uuid": "8ba15933-29a2-49b1-a9ce-70474bad3007",
        "practices": [
          "if-statements",
          "numbers",
          "operator-precedence"
        ],
        "prerequisites": [
          "if-statements",
          "numbers"
        ],
        "difficulty": 2,
        "status": "beta"
      }
    ]
  },
  "concepts": [
    {
      "uuid": "2eb4a463-355f-46ef-ac55-a75ec5afdf86",
      "slug": "basics",
      "name": "Basics"
    },
    {
      "uuid": "4466e33e-dcd2-4b1f-9d9d-2c4315bf5188",
      "slug": "if-statements",
      "name": "If Statements"
    },
    {
      "uuid": "b9a421b2-c5ff-4213-bd6d-b886da31ea0d",
      "slug": "numbers",
      "name": "Numbers"
    },
    {
      "uuid": "7a86561d-173b-45c0-a53c-1ffd7b9ff259",
      "slug": "strings",
      "name": "Strings"
    }
  ],
  "key_features": [
    {
      "title": "Modern",
      "content": "C# is a modern, fast-evolving language.",
      "icon": "expressive"
    },
    {
      "title": "Cross-platform",
      "content": "C# runs on almost any platform and chipset.",
      "icon": "cross-platform"
    },
    {
      "title": "Multi-paradigm",
      "content": "C# is primarily an object-oriented language, but also has lots of functional features.",
      "icon": "multi-paradigm"
    },
    {
      "title": "General purpose",
      "content": "C# can be used for a wide variety of workloads, like websites, console applications, and even games.",
      "icon": "general-purpose"
    },
    {
      "title": "Tooling",
      "content": "C# has excellent tooling, with linting and advanced refactoring options built-in.",
      "icon": "tooling"
    },
    {
      "title": "Documentation",
      "content": "Documentation is excellent and exhaustive, making it easy to get started with C#.",
      "icon": "documentation"
    }
  ],
  "tags": [
    "paradigm/declarative",
    "paradigm/functional",
    "paradigm/object_oriented",
    "platform/linux",
    "platform/windows",
    "runtime/jvm"
  ]
}