Archive for December, 2015
I stepped into the world of Ruby on Rails through the Markus Project. One of the main tasks that I completed during the Ucosp term was revising the CSV group upload feature. In production, the function is used by administrators to create groups for an assignment by specifying the group name, repository name, and the group members for all groups in a CSV file format. The function already existed in MarkUs, but was in need for a few modifications such as checking membership and repository equivalences when reusing existing groups. Moreover, the previous implementation destroyed all existing groupings for an assignment at the start of the upload and created brand new groupings which prevented incremental group uploads. This was to be changed so that the existing groupings were not deleted.
The first week was spent tracing through the code trying to figure out how the logic behind the CSV group creation worked while also learning the Ruby on Rails framework. The progress was slow, and huge gaps still remained in my understanding. Since tracing through the code didn’t seem to help much, I decided to draw out the flow chart for the function. Seeing the code transformed into a set of shapes and arrows helped me understand what the current code was doing. However, I soon realized that I had no idea of what the expected behaviour should be or what the specific user requirements were for all the corner cases that came into my head. It was time to ask for help.
After the first meeting with Karen Reid, I had enough understanding of the requirements to create a code skeleton. I drew up another diagram with the logic flow for all the different scenarios that I could come up with. It was difficult to decide whether a user error should be fixed, ignored or blocked so the flow chart ended up with many branches that ended in “what if”s. During the second meeting however, most of those “what if” cases were resolved as user errors which made the CSV upload function much cleaner and easier to implement.
The final flow chart is given below. Some useful terms used in the diagram are:
- A group is a relationship between a group_name and a repo_name which corresponds to a repository instance
- A grouping is a relationship between a group, an assignment and student memberships
Problem: We have various annotations, which are rectangles defined by the grader, floating above images (JPGs and PDFs) submitted by the student. They look like the yellow box in this image:
We want to rotate the image. This is not very difficult, but how do we rotate the annotation so that it stays over the same area of the image?
The answer is that it depends on how the coordinates of the annotation are stored. I found that the solution was much more elegant for PDFs than for JPGs. Thus, I will attempt to explain my code for rotating PDF annotations.
A PDF annotation is defined by four corner points, which are relative to the boundaries of the page. The left of the page is x=0, the right is x=PAGE_WIDTH, the top is y=0, and the bottom is y=PAGE_HEIGHT. For the above image the four sides would be defined approximately by these four values:
xleft=0.08 * PAGE_WIDTH xright=0.5 * PAGE_WIDTH ytop=0.84 * PAGE_HEIGHT ybottom=0.96 * PAGE_HEIGHT
The important point is that they are relative to the page (the JPG annotations are in screen space coordinates, which made it much messier). We can find the algorithm for rotating the annotations by visual inspection. In the following image, the red box is the annotation. Since we are only rotating the PDF by 90-degree clockwise increments, we know that:
The new ytop is the previous xleft.
The new ybottom is 1 minus the previous xright. The new xleft is 1 minus previous ybottom.
The new xright is the previous ytop.
When we rotate another 90 degrees, we just apply the same transformation again.
Now that we know how to rotate annotations, the main problem remaining is how to store the annotations in the database now that they can be rotated. My solution was to store them in unrotated form. So, if the grader rotates the PDF by 90 degrees clockwise and then makes some annotations, when the coordinates are saved, they would first be rotated 90 degrees counterclockwise. Whenever we render an annotation, we know the unrotated coordinates and the rotation of the PDF, so we can rotate the coordinates to the correct orientation using the method I described.
And so we now have rotating PDF annotations in Markus!
1) Over the last week, I’ve been working on finishing the styling of the Student Interface. I had a PR merged by David and have just made revisions to another PR. From that point of view, there isn’t too much outstanding!
Tying up some loose ends on the final issues that I’ve worked on. Switched simple_format everywhere in app to new markdown helper to render text with Redcarpet markdown (this mostly affected remark requests, and also annotations as originally planned). Worked on technical report/presentation preparation for our final evaluation for the course that is associated with this project at my school.
Found an issue with remark_requests during my testing of the changes. Will try to work through it with Melissa as it seems she has been aware of it as well.
I plan to address any issues that will help move my final PR into the repository, so that there is nothing left over. I will also be working on my report and presentation in the coming weeks. Mostly discussing Markus features, the features that I worked on, and the technology stack, workflows, and environments that we used throughout the semester.
I finished my work on the test upload form. Editing, as well as uploading test script files seems to be working now. I don’t have a lot outstanding, but I’m going to go back and ensure the test support files are working as well as clean up some of the code we merged in but did not touch since they do not follow the hound guidelines to make it easier for whoever is looking at it next.
I tried to wrap up as much as I could this week since my exams are starting tomorrow. I managed to add comments in some of the automated test code where Prototype exists just to make it visible what should be changed. I also fixed a sorting issue on the commit column of the submissions table. I ultimately wasn’t able to test out removing Prototype in the areas with automated test code very well from master, which is why I resorted to adding the comments in.
So I submitted a pull request for the nested file selector and also committed a fix for a previous pull request regarding the late penalties. Also investigated a couple problems with the annotation rotations sometimes not working and the marking state. The annotations not rotating was difficult for me to reproduce (got it after David mentioned to try Firefox, but it only happened once) so I’m not sure what the cause of the problem is and will continue looking at it this week.
1. Last week I’ve tried to make the create individual groups button a background process.
2. A road block was figuring out how to setup resque and active job work. I was able to resolve the initial error I had. But i still have problems running the job. When i do job.perform_now, it works fine, but its not run as a background job. And when I do perform_later, the job is not performed and I don’t see any errors either. Is there a way to see the status of jobs?
3. By Wednesday I plan to hopefully get perform_later working