Wednesday, April 22, 2015

4/22/15 - LibriFox Audio Downloading

Today, Finn and I worked on setting up a way to download the audiobook mp3s. It was hard because there is very sparse documentation for the Firefox OS file system API. For example, on this page, only one example of a "selector" for enumerate is given. We wanted to find all the files in the librifox/ directory, and eventually Finn guessed that you could do #enumerate('path/'), which turned out to work. There also isn't really a good way to access the filesystem short of using their API, so when we ran into trouble we weren't sure if our problem was in the file write code or the code we were inputting to read the filenames back to see if they were written.  There is no native file browser in Firefox OS.

Two new objects were added to app.js, a BookDownloadManager, which handles the downloading of chapter and book audio files, and a BookPlayerPageGenerator, which sets up the book.html user interface.

One thing I don't like about the code in this stage is how much object generation is done just in the body of app.js. For example, BookPlayerPageGenerator needs to know about three elements on the page, and right now we are creating the instance and setting up the selectors right in the body of the file, which adds clutter. App.js is getting really big, so we really need to look into splitting it into smaller files. I'm not sure how this works with jQuery Mobile though.

Here's a picture that shows today's progress.

You can see on the console there (under the not well formed errors, which are the most vague and unhelpful error messages ever), that the downloaded chapter gets written to 'librifox/book-id/chapter-index.mp3'.

jQuery Mobile's built in sliders were terrible to use as progress bars because they are designed to be interactive, and we don't want the user sliding them around while a file is downloading.  I ended up making my own progress bar that's just a div nested inside another div, which requires way less setup code than what we would need to do for jQuery mobile sliders.

None of this code has tests written yet, so that's something we will work on tomorrow.

One thing I was unsure of when writing the 'generator' objects is how to handle the args hash being undefined.  Right now I have the line var args = args || {};, which sets the args to an empty object if it's excluded. I'm thinking that it might be better not to do that at all, because the object won't function correctly without those arguments, and it's probably better to fail explicitly right at the point it tries to set variables from the args, rather than later on when the code tries to use them and finds them to be undefined.

Tuesday, April 21, 2015

4/21/15 - Gitignore

I haven't blogged in a while because I was preparing for the UMD programming contest last week, but today Finn and I worked on refactoring the book page of LibriFox.

I also wanted to blog in order to write this down in case I needed to do it again:
I put all my Learn C the Hard Way exercises into a git repository so that I would have access to their revision history, but I forgot about all the compiled files and ended up with this as the repo folder.  I don't have make set up to use the .out suffix, so I couldn't just add the compiled files to the gitignore.  Instead I found this guide online and set up my .gitignore following it:
File: .gitignore

# ignore everything
*
# Don't ignore directories, so we can recurse into them
!*/
# Don't ignore other important files
!.gitignore
!*.c
!*.java
!*.py
!*.rb
Then, to remove all the files I didn't want that had already been committed, I did git rm -rf . --cached, which removed all the files from my git path, while keeping them on the local machine. Then I did git add . to add all the files allowed by the gitignore back into the path.
This isn't the perfect solution, because every time I add a new file type I'll have to add it manually, but it works for now. I ended up with a much cleaner directory.

Also I found a javascript web mocking library called Nock, so hopefully that will allow us to test the HttpRequestHandler object easily.

Wednesday, April 8, 2015

4/8/15 - File Name Too Long

Today I kept working on the SearchResultsPageGenerator, but I'm having trouble getting it to work because I'm getting this error: NS_ERROR_FILE_NAME_TOO_LONG.  Apparently this is a problem with windows, and I couldn't find any info on how to fix it.  I tried it with one of the flame devices, and that didn't work either (same error). I tried a different Firefox OS app I had, and it worked fine, so this problem is specific to the librifox app.

Tuesday, April 7, 2015

4/7/15 - Windows Shell


Since I use windows on my laptop, I've had to use git through cmd.exe, which is very feature-lacking. It doesn't have tab support and copying/pasting is buried in the menus with no keyboard shortcut. I followed this tutorial in order to get Console2 running with git. I installed Console2 to my Program Files (x86) directory, and figured out that when you change your settings through the menu, they will silently revert back unless Console2 is running in administrator mode, since it doesn't have permission to write to the program files directory otherwise.

I also started refactoring the book search results page into a BookSearchPageGenerator just like I did with ChapterListPageGenerator. I also started writing tests for it, but I'm not sure the best method for removing the http dependencies. Right now I'm making a mock of the http parser, and adding the methods. It's also tough to figure out how much is really necessary to test for, since UI is pretty complex. For example, is it important to test that the appended elements are <li>s? I don't think it is.

4/4/15 - UMD Contest Problems

Today I did two 2013 UMD contest problems: 3 - Guessing Game I and 4 - Tree Isomorphism. Guessing Game I was really easy, and I had already done Tree Isomorphism with Sam on Wednesday and Thursday, but I decided to do it again because Sam did the typing (and most of the thinking) on the last one, and I remembered our approach to the problem well enough to re-solve it. I've noticed that a lot of times I'll read one of these UMD problems and just have no idea what to do, and before talking through it with Sam, Tree Isomorphism was definitely one of those cases where I just had no clue how to approach it.  After seeing the solution once, though, I was able to come up with it again on my own.  I didn't keep track of time, but it probably took about an hour and a half, which isn't very good considering I had already seen the solution once.

One thing about our approach to this problem that confused me and slowed me down was the List<List<TreeNode>> type returned by #permutations(). I couldn't remember our previous solution exactly, so I had to play around with the recursion to get the method to work correctly with the return type. Another thing that threw me off was the choice between List<TreeNode> children and rootNode.children in method arguments. I found that it made the most sense to do the former, because a root node might not always be present, such as when the #permutations() List<List<TreeNode>> was in use. For example, I originally had #treeEquals() take two root nodes and compare children (rather than taking two lists of nodes), but I realized that this would require me to add additional root nodes when all I had was a list of children, such as when checking the permutations of one tree against the other.

I also looked at 5 - Guessing Game II, and it's the same problem—I don't have enough experience to be able to come up with a strategy. I did work through their solution, and I think understand it pretty well, although I wouldn't have been able to come up with that on my own.

Monday, April 6, 2015

4/6/15 - Permutations in Ruby

I rewrote my ruby permutations algorithm to use yield instead of return. This is a lazy algorithm: rather than generating all permutations at once, it generates them as they are needed. So the line permutations(%w[a b c d]).first(5) only generates the first 5 permutations of the array. Here is the implementation: As it turns out, this function is already built into ruby! This statement does the exact same thing.

Sunday, April 5, 2015

4/5/15 ChaptersListPageGenerator code and tests

Repo diff
ChaptersListPageGenerator code
ChaptersListPageGenerator tests

For some reason, there are two ways to test equality in our tests, assert.equal() and expect(). I think the former is the mocha expression, and the latter is the chai expression. I tried to convert all our tests over to the expect() syntax. I also found this page, which was helpful for writing the expect statements.

In testing the chapters list page generator, I made my own stub for HttpRequestHandler, which is used to fetch the RSS chapter data that populates the chapters list. There's a stubbing/mocking library we might want to look into as well.

I wasn't quite sure how to test the output of #generatePage since it's all within the page elements, and this is what I ended up with. I also found that I had to explicitly instantiate the <ul> targeted by #pageGenerate as a jQuery Mobile listview, otherwise this line in app.js would cause an error saying that the listview had not been initialized.

I added a property to karma.conf.js to allow console.log statements to be outputted to the server console, which is helpful for debugging the tests

I don't think we need to test the private methods of ChapterListPageGenerator; they aren't part of any public interface, so there is no risk of cascading changes causing problems beyond #generatePage. if something is changed.

I looked at how to make public and private methods in an object, and how inheritance works in JavaScript:

With a Foo() object set as Bar's prototype, all new Bar objects to send anything that they don't know how to handle up the message chain to Foo. So a method defined in Bar would override an identical method in Foo, but a method defined in Foo and not in Bar will work as though it is being called on Foo directly. This source was helpful in figuring stuff out.