internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: uccser/cs-unplugged

Issue:
Support multiple page resources
Currently the create image function for a resource return a single image. Instead it should return a list of images, which would allow multiple page resources.

For example, for 4 pages of a single page resource the content would be:

```
Image output: [A]
Final document: A, A, A, A
```

For 4 pages of a three page resource the content would be:

```
Image output: [A, B, C], [A, B, C], [A, B, C], [A, B, C] 
Final document: A, B, C, A, B, C, A, B, C, A, B, C
```


Discussion:

Resolving patch:
diff --git a/csunplugged/resources/views/generate_resource_pdf.py b/csunplugged/resources/views/generate_resource_pdf.py
--- a/csunplugged/resources/views/generate_resource_pdf.py
+++ b/csunplugged/resources/views/generate_resource_pdf.py
@@ -63,7 +63,9 @@ def generate_resource_pdf(request, resource, module_path):
 
 
 def generate_resource_image(get_request, resource, module_path):
-    """Retrieve image from resource generator and resize to size.
+    """Retrieve image(s) for one copy of resource from resource generator.
+
+    Images are resized to size.
 
     Args:
         get_request: HTTP request object
@@ -71,27 +73,33 @@ def generate_resource_image(get_request, resource, module_path):
         module_path: Path to module for generating resource.
 
     Returns:
-        Base64 string of a generated resource image.
+        List of Base64 strings of a generated resource images for one copy.
     """
-    # Get image from resource image creator
+    # Get images from resource image creator
     resource_image_generator = importlib.import_module(module_path)
-    image = resource_image_generator.resource_image(get_request, resource)
+    raw_images = resource_image_generator.resource_image(get_request, resource)
+    if not isinstance(raw_images, list):
+        raw_images = [raw_images]
 
-    # Resize image to reduce file size
+    # Resize images to reduce file size
     if get_request["paper_size"] == "a4":
         max_pixel_height = 267 * MM_TO_PIXEL_RATIO
     elif get_request["paper_size"] == "letter":
         max_pixel_height = 249 * MM_TO_PIXEL_RATIO
-    (width, height) = image.size
-    if height > max_pixel_height:
-        ratio = max_pixel_height / height
-        width *= ratio
-        height *= ratio
-        image = image.resize((int(width), int(height)), Image.ANTIALIAS)
-
-    # Save image to buffer
-    image_buffer = BytesIO()
-    image.save(image_buffer, format="PNG")
-
-    # Return base64 of image
-    return base64.b64encode(image_buffer.getvalue())
+
+    images = []
+    for image in raw_images:
+        (width, height) = image.size
+        if height > max_pixel_height:
+            ratio = max_pixel_height / height
+            width *= ratio
+            height *= ratio
+            image = image.resize((int(width), int(height)), Image.ANTIALIAS)
+
+        # Save image to buffer
+        image_buffer = BytesIO()
+        image.save(image_buffer, format="PNG")
+        # Add base64 of image to list of images
+        images.append(base64.b64encode(image_buffer.getvalue()))
+
+    return images


Test patch:
Repository: uccser/cs-unplugged

Issue:
Check desired orientation of binary to alphabet resource
Currently is displayed in portrait but half the page is unused. May be better to switch to landscape which will increase the size of table cells.


Discussion:
Another idea was to print 2 per page. This needs to be checked with authors regarding table size.
Authors decided it is better to display one larger table per page.

Resolving patch:
diff --git a/csunplugged/resources/views/binary_to_alphabet.py b/csunplugged/resources/views/binary_to_alphabet.py
--- a/csunplugged/resources/views/binary_to_alphabet.py
+++ b/csunplugged/resources/views/binary_to_alphabet.py
@@ -78,6 +78,7 @@ def resource_image(request, resource):
 
             base_coord_y += 54
 
+    image = image.rotate(90, expand=True)
     return image
 
 


Test patch:
Repository: uccser/cs-unplugged

Issue:
Add Binary Numbers 5-7 lesson 2



Discussion:

Resolving patch:
diff --git a/csunplugged/topics/migrations/0063_auto_20170614_0639.py b/csunplugged/topics/migrations/0063_auto_20170614_0639.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/topics/migrations/0063_auto_20170614_0639.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.2 on 2017-06-14 06:39
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('topics', '0062_auto_20170609_0424'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='lesson',
+            name='slug',
+            field=models.SlugField(max_length=80),
+        ),
+    ]
diff --git a/csunplugged/topics/models.py b/csunplugged/topics/models.py
--- a/csunplugged/topics/models.py
+++ b/csunplugged/topics/models.py
@@ -262,7 +262,7 @@ class Lesson(models.Model):
         on_delete=models.CASCADE,
         related_name="unit_plan_lessons"
     )
-    slug = models.SlugField()
+    slug = models.SlugField(max_length=80)
     name = models.CharField(max_length=100)
     number = models.IntegerField()
     duration = models.PositiveSmallIntegerField(null=True)
diff --git a/csunplugged/utils/group_lessons_by_age.py b/csunplugged/utils/group_lessons_by_age.py
--- a/csunplugged/utils/group_lessons_by_age.py
+++ b/csunplugged/utils/group_lessons_by_age.py
@@ -19,7 +19,7 @@ def group_lessons_by_age(lessons):
         The value for a key is a sorted list of lessons (ordered by number).
     """
     grouped_lessons = OrderedDict()
-    lessons = lessons.order_by("number")
+    lessons = lessons.order_by("age_range", "number")
     for lesson in lessons:
         for age_range in lesson.age_range.all():
             ages = (age_range.age_range.lower, age_range.age_range.upper)


Test patch:
diff --git a/csunplugged/tests/topics/views/test_unit_plan_view.py b/csunplugged/tests/topics/views/test_unit_plan_view.py
--- a/csunplugged/tests/topics/views/test_unit_plan_view.py
+++ b/csunplugged/tests/topics/views/test_unit_plan_view.py
@@ -92,7 +92,7 @@ def test_unit_plan_view_lessons_context(self):
                 [lesson1, lesson2]
             )
 
-    def test_curriculum_integration_view_prerequisite_lessons_context_order(self):
+    def test_unit_plan_view_lessons_context_order(self):
         topic = self.test_data.create_topic(1)
         unit_plan = self.test_data.create_unit_plan(topic, 1)
         age_range_1 = self.test_data.create_age_range(5, 7)
Repository: uccser/cs-unplugged

Issue:
Add sorting networks lessons
- [ ] Lesson 2 (8-10) - needs generated resources
- [ ] Lesson 1 (11-14)
- [ ] Lesson 2 (11-14)


Discussion:

Resolving patch:
diff --git a/csunplugged/resources/views/sorting_network_cards.py b/csunplugged/resources/views/sorting_network_cards.py
--- a/csunplugged/resources/views/sorting_network_cards.py
+++ b/csunplugged/resources/views/sorting_network_cards.py
@@ -47,25 +47,24 @@ def resource_image(request, resource):
         font_size = 900
         font_path = "static/fonts/NotoSans-Regular.ttf"
         text = [u"\u00bd", u"\u2153", u"\u2154", u"\u215c", u"\u00be", u"\u215d"]
-    else:
+    elif card_type == "maori_numbers":
         font_size = 300
         text = [
-            "tahi",
-            "rua",
-            "toru",
-            "whā",
-            "rima",
-            "ono",
-            "whitu",
-            "waru",
-            "iwa",
-            "tekau",
-            "tekau mā tahi",
-            "tekau mā waru",
-            "tekau mā toru",
-            "tekau mā whā",
-            "rua tekau",
-            "rua tekau mā ono",
+            "tahi", "rua", "toru", "whā", "rima", "ono", "whitu", "waru",
+            "iwa", "tekau", "tekau mā tahi", "tekau mā waru", "tekau mā toru",
+            "tekau mā whā", "rua tekau", "rua tekau mā ono"
+        ]
+    elif card_type == "words":
+        font_size = 500
+        text = ["crocodile", "crochet", "kiwi", "weka", "kiwi", "kiwano"]
+    elif card_type == "letters":
+        font_size = 800
+        text = ["L", "O", "N", "K", "E", "D", "S", "P", "G", "B", "I", "Y"]
+    else:
+        font_size = 500
+        text = [
+            "whero", "kākāriki", "kiwikiwi", "karaka",
+            "kōwhai", "pango", "māwhero", "mā"
         ]
 
     font = ImageFont.truetype(font_path, font_size)
@@ -129,6 +128,9 @@ def valid_options():
         All valid options (dict).
     """
     return {
-        "type": ["small_numbers", "large_numbers", "fractions", "maori_numbers"],
+        "type": [
+            "small_numbers", "large_numbers", "fractions", "maori_numbers",
+            "words", "letters", "maori_colours"
+        ],
         "paper_size": ["a4", "letter"],
     }


Test patch:
Repository: uccser/cs-unplugged

Issue:
Center navbar menu text on mobile devices
![image](https://user-images.githubusercontent.com/8001048/27560437-4254d4b0-5b18-11e7-811f-6da827fa1365.png)

Always display curriculum areas for learning outcomes on a new line
This prevents a confusing interface, like so:

![image](https://user-images.githubusercontent.com/8001048/27560331-e410500a-5b17-11e7-8cd2-db32964f721b.png)



Discussion:

Resolving patch:
diff --git a/csunplugged/topics/views.py b/csunplugged/topics/views.py
--- a/csunplugged/topics/views.py
+++ b/csunplugged/topics/views.py
@@ -31,7 +31,7 @@ def get_queryset(self):
         Returns:
             Queryset of Topic objects ordered by name.
         """
-        return Topic.objects.order_by("name")
+        return Topic.objects.order_by("name").prefetch_related("unit_plans")
 
 
 class TopicView(generic.DetailView):


Test patch:
Repository: uccser/cs-unplugged

Issue:
Fix update of Cloud SQL database in develop deployment



Discussion:

Resolving patch:
diff --git a/csunplugged/config/settings/database_proxy.py b/csunplugged/config/settings/database_proxy.py
--- a/csunplugged/config/settings/database_proxy.py
+++ b/csunplugged/config/settings/database_proxy.py
@@ -10,7 +10,7 @@
 DATABASES = {
     "default": {
         "ENGINE": "django.db.backends.postgresql",
-        "HOST": "127.0.0.1",
+        "HOST": "localhost",
         "PORT": "5433",
         "NAME": "csunplugged",
         "USER": env("GOOGLE_CLOUD_SQL_DATABASE_USERNAME"),  # noqa: F405
diff --git a/infrastructure/replace_envs.py b/infrastructure/replace_envs.py
new file mode 100644
--- /dev/null
+++ b/infrastructure/replace_envs.py
@@ -0,0 +1,51 @@
+# For the given file, finds each environment variable placeholder and replaces
+# it with the value of the variable. Then writes the file to the directory this
+# program was called from.
+
+import os
+import re
+import sys
+
+REGEX = re.compile("\$\{([A-Z_]+)\}")
+
+
+def get_filename():
+    if len(sys.argv) != 2:
+        raise LookupError("One filename argument must be provided!")
+    else:
+        return sys.argv[1]
+
+
+def read_file(filename):
+    with open(filename, "r", encoding="UTF-8") as file_object:
+        file_content = file_object.read()
+    return file_content
+
+
+def replace_placeholders(file_content):
+    updated_content = re.sub(REGEX, get_variable_value, file_content)
+    return updated_content
+
+
+def get_variable_value(match):
+    variable_name = match.group(1)
+    if variable_name in os.environ:
+        return os.environ[variable_name]
+    else:
+        raise LookupError("{} environment variable not found!".format(variable_name))
+
+
+def write_file(filename, updated_content):
+    filename = os.path.basename(filename)
+    with open(filename, "w", encoding="UTF-8") as file_object:
+        file_object.write(updated_content)
+
+
+def main():
+    filename = get_filename()
+    file_content = read_file(filename)
+    updated_content = replace_placeholders(file_content)
+    write_file(filename, updated_content)
+
+
+main()


Test patch:
Repository: uccser/cs-unplugged

Issue:
Modify docker configuration to work on OSX
Docker for Mac does not properly support the `network_mode: host` option for containers. In order to run the system on OSX, it will be necessary to network the containers using a bridged network:

> By default Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name."

Rather than accessing other containers via a port on localhost, containers will  access each other using the instance name as the hostname. Port 80 will then be exposed from the nginx container to the host.


Discussion:

Resolving patch:
diff --git a/csunplugged/config/settings/database_proxy.py b/csunplugged/config/settings/database_proxy.py
--- a/csunplugged/config/settings/database_proxy.py
+++ b/csunplugged/config/settings/database_proxy.py
@@ -10,8 +10,8 @@
 DATABASES = {
     "default": {
         "ENGINE": "django.db.backends.postgresql",
-        "HOST": "localhost",
-        "PORT": "5433",
+        "HOST": "cloud_sql_proxy",
+        "PORT": "5432",
         "NAME": "csunplugged",
         "USER": env("GOOGLE_CLOUD_SQL_DATABASE_USERNAME"),  # noqa: F405
         "PASSWORD": env("GOOGLE_CLOUD_SQL_DATABASE_PASSWORD"),  # noqa: F405


Test patch:
Repository: uccser/cs-unplugged

Issue:
Generation of treasure hunt resource exceeds Travis CI job time limit
See: https://travis-ci.org/uccser/cs-unplugged/jobs/293588682


Discussion:

Resolving patch:
diff --git a/csunplugged/config/settings/base.py b/csunplugged/config/settings/base.py
--- a/csunplugged/config/settings/base.py
+++ b/csunplugged/config/settings/base.py
@@ -209,6 +209,7 @@
     },
 ]
 
-# ENVIRONMENT VARIABLES
+# OTHER SETTINGS
 # ------------------------------------------------------------------------------
 DJANGO_PRODUCTION = env.bool("DJANGO_PRODUCTION")
+RESOURCE_COPY_AMOUNT = 20
diff --git a/csunplugged/resources/management/commands/makeresources.py b/csunplugged/resources/management/commands/makeresources.py
--- a/csunplugged/resources/management/commands/makeresources.py
+++ b/csunplugged/resources/management/commands/makeresources.py
@@ -6,6 +6,7 @@
 from tqdm import tqdm
 from django.core.management.base import BaseCommand
 from django.http.request import QueryDict
+from django.conf import settings
 from resources.models import Resource
 from resources.views.views import generate_resource_pdf
 from resources.utils.get_resource_generator import get_resource_generator
@@ -50,7 +51,7 @@ def handle(self, *args, **options):
             # Create PDF for all possible combinations
             for combination in progress_bar:
                 if resource.copies:
-                    combination["copies"] = 30
+                    combination["copies"] = settings.RESOURCE_COPY_AMOUNT
                 requested_options = QueryDict(urlencode(combination, doseq=True))
                 generator = get_resource_generator(resource.generator_module, requested_options)
                 (pdf_file, filename) = generate_resource_pdf(resource.name, generator)
diff --git a/csunplugged/resources/views/views.py b/csunplugged/resources/views/views.py
--- a/csunplugged/resources/views/views.py
+++ b/csunplugged/resources/views/views.py
@@ -48,6 +48,7 @@ def resource(request, resource_slug):
     context["debug"] = settings.DEBUG
     context["resource_thumbnail_base"] = "{}img/resources/{}/thumbnails/".format(settings.STATIC_URL, resource.slug)
     context["grouped_lessons"] = group_lessons_by_age(resource.lessons.all())
+    context["copies_amount"] = settings.RESOURCE_COPY_AMOUNT
     if resource.thumbnail_static_path:
         context["thumbnail"] = resource.thumbnail_static_path
     return render(request, resource.webpage_template, context)


Test patch:
diff --git a/csunplugged/tests/resources/management/test_makeresources_command.py b/csunplugged/tests/resources/management/test_makeresources_command.py
--- a/csunplugged/tests/resources/management/test_makeresources_command.py
+++ b/csunplugged/tests/resources/management/test_makeresources_command.py
@@ -69,4 +69,4 @@ def test_makeresources_command_single_resource_with_copies(self):
         management.call_command("makeresources")
         filepath = self.RESOURCE_PATH.format("Resource Grid (a4).pdf")
         pdf = PdfFileReader(open(filepath, "rb"))
-        self.assertEqual(pdf.getNumPages(), 30)
+        self.assertEqual(pdf.getNumPages(), 20)
Repository: uccser/cs-unplugged

Issue:
Workaround Crowdin bug where integer yaml keys are not preserved
When downloading in-context localisation files, integer keys in YAML files are not preserved. This is only an issue in the file `topics/content/en/programming-challenges-structure-difficulties.yaml`, which uses the difficulty number as the key.

As a work around, we can use the string value of the integer as the key, i.e. `"0"` instead of `0`


Discussion:

Resolving patch:
diff --git a/csunplugged/topics/management/commands/_ProgrammingChallengesStructureLoader.py b/csunplugged/topics/management/commands/_ProgrammingChallengesStructureLoader.py
--- a/csunplugged/topics/management/commands/_ProgrammingChallengesStructureLoader.py
+++ b/csunplugged/topics/management/commands/_ProgrammingChallengesStructureLoader.py
@@ -89,7 +89,7 @@ def load(self):
         for difficulty in difficulty_levels:
 
             new_difficulty = ProgrammingChallengeDifficulty(
-                level=difficulty,
+                level=int(difficulty),
             )
 
             translations = difficulties_translations.get(difficulty, dict())


Test patch:
Repository: uccser/cs-unplugged

Issue:
Implement automatic update of .po file 
The .po file needs to be updated with all static strings for translation, by running the `python manage.py makemessages`. This needs to be run upon any change to templates or database content.

This process should be automated on Travis to run when any such files are updated on `develop`.


Discussion:

Resolving patch:
diff --git a/infrastructure/crowdin/crowdin_bot_python_package/crowdin_bot/get_complete_translations.py b/infrastructure/crowdin/crowdin_bot_python_package/crowdin_bot/get_complete_translations.py
--- a/infrastructure/crowdin/crowdin_bot_python_package/crowdin_bot/get_complete_translations.py
+++ b/infrastructure/crowdin/crowdin_bot_python_package/crowdin_bot/get_complete_translations.py
@@ -43,9 +43,9 @@ def process_item(item, parent_path=None, csu_language_code=None):
         else:
             path = filename
 
-        # Skip full translated check for *.po - they can always be included
+        # Skip *.po - they are handled separately
         if filename.endswith(".po"):
-            return [path]
+            return []
 
         if item.find("phrases").text == item.find("approved").text:
             return [path]
@@ -79,4 +79,5 @@ def process_item(item, parent_path=None, csu_language_code=None):
     completed = []
     for item in files:
         completed += process_item(item, csu_language_code=args.csu_code)
-    print('\n'.join(completed))
+    for path in completed:
+        print(path)
diff --git a/infrastructure/crowdin/crowdin_bot_python_package/crowdin_bot/get_crowdin_languages.py b/infrastructure/crowdin/crowdin_bot_python_package/crowdin_bot/get_crowdin_languages.py
--- a/infrastructure/crowdin/crowdin_bot_python_package/crowdin_bot/get_crowdin_languages.py
+++ b/infrastructure/crowdin/crowdin_bot_python_package/crowdin_bot/get_crowdin_languages.py
@@ -12,14 +12,14 @@ def get_project_languages():
     Returns:
         (list) list of project crowdin language codes
     """
-    info_xml = api.api_call_xml("info")
-    languages = info_xml.find('languages')
-    translatable_languages = []
-    for language in languages:
-        # Check it's not the incontext pseudo language
-        if language.find("can_translate").text == "1":
-            translatable_languages.append(language.find('code').text)
-    return translatable_languages
+    active_languages = []
+    trans_status = api.api_call_json("status")
+    for language in trans_status:
+        # Check language has actually had some translation done
+        if int(language["words_approved"]) > 0:
+            active_languages.append(language["code"])
+    return active_languages
 
 if __name__ == "__main__":
-    print('\n'.join(get_project_languages()))
+    for language in get_project_languages():
+        print(language)


Test patch:
Repository: uccser/cs-unplugged

Issue:
Support RTL/BiDi website layout
Currently, the html attribute `dir` is set to RTL when required, which gets us part of the way there. However more changes are needed to truly mirror the layout. This essentially boils down to switching 'left' with 'right' in css rules and html classes in all but a few exceptional cases. 

Some good suggestions for how to use `sass`/`scss` features to achieve this are included in this blog: http://matanich.com/2013/09/06/rtl-css-with-sass




Discussion:

Resolving patch:
diff --git a/csunplugged/config/settings/base.py b/csunplugged/config/settings/base.py
--- a/csunplugged/config/settings/base.py
+++ b/csunplugged/config/settings/base.py
@@ -43,6 +43,7 @@
 THIRD_PARTY_APPS = [
     "django_bootstrap_breadcrumbs",
     "modeltranslation",
+    "bidiutils",
 ]
 
 # Apps specific for this project go here.
@@ -142,8 +143,11 @@
     django.conf.locale.LANG_INFO.update(EXTRA_LANG_INFO)
     # Add new languages to the list of all django languages
     global_settings.LANGUAGES = global_settings.LANGUAGES + EXTRA_LANGUAGES
+    global_settings.LANGUAGES_BIDI = (global_settings.LANGUAGES_BIDI +
+                                      [INCONTEXT_L10N_PSEUDOLANGUAGE_BIDI.split('-')[0]])
     # Add new languages to the list of languages used for this project
     LANGUAGES += tuple(EXTRA_LANGUAGES)
+    LANGUAGES_BIDI = global_settings.LANGUAGES_BIDI
 
 
 # See: https://docs.djangoproject.com/en/dev/ref/settings/#site-id
@@ -193,6 +197,7 @@
                 "django.contrib.messages.context_processors.messages",
                 "config.context_processors.version_number.version_number",
                 "config.context_processors.deployed.deployed",
+                "bidiutils.context_processors.bidi",
             ],
             "libraries": {
                 "render_html_field": "config.templatetags.render_html_field",


Test patch:
Repository: uccser/cs-unplugged

Issue:
Only prepend www for production website
It should not be used for development website.


Discussion:

Resolving patch:
diff --git a/csunplugged/config/settings/production.py b/csunplugged/config/settings/production.py
--- a/csunplugged/config/settings/production.py
+++ b/csunplugged/config/settings/production.py
@@ -23,7 +23,10 @@
 
 # URL Configuration
 # ------------------------------------------------------------------------------
-PREPEND_WWW = True
+if env("DEPLOYMENT", default=None) == "prod":  # noqa: F405
+    PREPEND_WWW = True
+else:
+    PREPEND_WWW = False
 
 # DATABASE CONFIGURATION
 # ----------------------------------------------------------------------------


Test patch:
Repository: uccser/cs-unplugged

Issue:
Minor adjustments to navbar and homepage
## Navbar

- [x] There should be more space between logo and 'Topics'.
- [x] The search bar can be ~20% smaller.

## Hompeage

- [x] Navbar should be transparent and fade in when user scrolls down.


Discussion:

Resolving patch:
diff --git a/csunplugged/general/views.py b/csunplugged/general/views.py
--- a/csunplugged/general/views.py
+++ b/csunplugged/general/views.py
@@ -9,6 +9,16 @@ class GeneralIndexView(TemplateView):
 
     template_name = "general/index.html"
 
+    def get_context_data(self, **kwargs):
+        """Provide the context data for the homepage.
+
+        Returns:
+            Dictionary of context data.
+        """
+        context = super(GeneralIndexView, self).get_context_data(**kwargs)
+        context["homepage"] = True
+        return context
+
 
 class GeneralAboutView(TemplateView):
     """View for the about page that renders from a template."""


Test patch: