{"id":23968997,"url":"https://github.com/joequery/joequery.me","last_synced_at":"2025-04-13T16:23:01.582Z","repository":{"id":6993680,"uuid":"8257505","full_name":"joequery/joequery.me","owner":"joequery","description":"Source of the website http://joequery.me","archived":false,"fork":false,"pushed_at":"2014-06-05T22:50:01.000Z","size":3399,"stargazers_count":4,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-27T07:21:19.557Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joequery.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-02-17T22:10:27.000Z","updated_at":"2023-02-10T21:18:07.000Z","dependencies_parsed_at":"2022-09-13T20:43:16.078Z","dependency_job_id":null,"html_url":"https://github.com/joequery/joequery.me","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joequery%2Fjoequery.me","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joequery%2Fjoequery.me/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joequery%2Fjoequery.me/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joequery%2Fjoequery.me/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joequery","download_url":"https://codeload.github.com/joequery/joequery.me/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248741999,"owners_count":21154425,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-07T00:57:33.214Z","updated_at":"2025-04-13T16:23:01.562Z","avatar_url":"https://github.com/joequery.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"joequery.me source mirror\n=========================\n\nThis repo holds the source of the site [http://joequery.me][0].  The site is\nwritten in Python2.7 with the aid of the [Flask][1] framework.\n\nAbout this repo: notes on quality\n---------------------------------\n\nThis repo reflects my ideal workflow. The way I like to go about creating\narticles, storing metadata, or anything else could be completely different than\nyour preferences. My system is not perfect, but it is perfect *for me*. The code\nmay be of mediocre quality, simply because I would rather spend time writing\narticles than work on the thing that lets me write articles.\n\nSite features\n-------------\n\n* Easy to create static pages\n* File based blogging platform\n    + Markdown\n    + Static home page/category index pages for speed\n    + Automatic sitemap.xml generation\n    + Automatic rss feed generation\n* Code snippets can be pulled into articles from files\n    + Links to raw snippet sources automatically generated ([See example][2])\n\nRequirements\n------------\n\n* Python2.7\n* virtualenv\n* libxml2-dev\n* libxslt-dev\n\n\nHow to use the site\n-------------------\n\n### Installation\n\n    $ git://github.com/joequery/joequery.me.git\n    $ cd joequery.me\n    $ virtualenv env\n    $ . env/bin/activate\n    (env) $ pip install -r requirements.txt\n\nIf you recieve any errors during the installation of PyQuery, ensure that\nlibxml2-dev and libxslt-dev are installed on your system.\n\nNow generate the blog index pages and the home page (we explain this later)\n\n    (env) $ python genfeed.py\n    Generated rss.txt\n    Generated static rss feed\n    Generated static blog pages\n    Generated sample posts for the home page\n    Generated xml sitemap\n    Generated related posts.txt files\n    Generated tag index pages\n    Generated series index pages\n    (env) $ python runserver.py\n    * Running on http://0.0.0.0:5000/\n    * Restarting with reloader\n\nNow head to http://localhost:5000\n\n\n### Creating articles\n\nPosts are located in `joequery/blog/posts/`. To create an article, copy the\ntemplate located at `joequery/blog/posts/template` to one of the article\ncategories (currently code, math, or screencast), and rename it to be the post\nslug. For example,\n\n    $ cd joequery/blog/posts\n    $ cp -r template code/how-to-use-javascript\n\nYou can then visit http://localhost:5000/code/how-to-use-javascript and you \nwill see a generic article. You will not see this newly created article appear\non the home page yet, but we will get to that later.\n\nMove to the newly copied directory and examine the `meta.txt` file.\n\n    $ cd code/how-to-use-javascript\n    $ cat meta.txt\n    [post]\n    title: Post Title\n    description: Post description\n    time: 2012-12-07 Fri 09:53 PM\n\nThe \\[post] tag must remain on top of the `meta.txt` file. The title is the post\ntitle, the description is the excerpt that will be displayed on the home page\nand blog index pages. Note: If you want your description to span multiple\nlines, every line after the first needs to be indented: [Example][3]. The time\nis the publish time, and the time format you see above is the *required* format.\nIf you're a vim user, you can place the following in your `~/.vimrc` to have the\nF3 key generate a timestamp for you:\n\n    \" Insert timestamp\n    nmap \u003cF3\u003e a\u003cC-R\u003e=strftime(\"%Y-%m-%d %a %I:%M %p\")\u003cCR\u003e\u003cEsc\u003e\n    imap \u003cF3\u003e \u003cC-R\u003e=strftime(\"%Y-%m-%d %a %I:%M %p\")\u003cCR\u003e\n\nIf you examine the `body.html` file of the directory we created, you'll see\n\n    {% from \"macros\" import img, blogimg, snippet %} {% set p = post %}\n    {% extends \"templates/post.html\" %} {% block post %} {% filter markdown %}\n\n    {% endfilter %} {% endblock post %}\n\nYou start writing your article in the line left blank. For example, \n\n    {% from \"macros\" import img, blogimg, snippet %} {% set p = post %}\n    {% extends \"templates/post.html\" %} {% block post %} {% filter markdown %}\n\n    Headline level 2\n    ----------------\n\n    This is some content.\n\n    ### Headline level 3\n\n    More content\n\n    {% endfilter %} {% endblock post %}\n\n### Generating the home page and blog index pages\n\nSince I didn't feel like using a database for the site, I needed a way to have\nthe home page and blog index pages display the most recent articles without\nreading through the file system every time the home page is requested. My\nsolution was to create a script I would run after\n\n* Creating a new artile\n* Adding tags/series to an article (will explain soon)\n* Editing a publish time of an article\n\nThis script is called `genfeed.py`, and it's located in the top level directory\nof the project. To use it, simply make sure the virtualenv is activated and run\n\n    (env) $ python genfeed.py\n\n`genfeed.py` also creates an XML sitemap which can be reached at\nhttp://localhost:5000/sitemap as well as an RSS feed which can be reached at\nhttp://localhost:5000/feed \n\n### Series and tags\n\nPosts can have multiple tags separated by commas specified in their meta.txt\nfiles. Currently, tags can only be **one word long**, but dashes and underscores\nare okay. For example,\n\n    [post]\n    title: Debugging failed compilations with apt-file\n    description: A quick tutorial on using apt-file on Ubuntu to solve failed make\n        compilations due to missing files.\n    time: 2012-12-28 Fri 07:05 PM\n    tags: ubuntu, utilities\n\nThe `ubuntu` and `utilities` directories need to exist in the \n`/joequery/blog/posts/tags/` directory. We need these directories to be\nversioned, so I add a `.gitkeep` file to the tag directories and commit them.\n\n    $ cd joequery/blog/posts/tags\n    $ mkdir ubuntu\n    $ touch ubuntu/.gitkeep\n\nPosts with tags will automatically list the tags at the bottom of the article.\nAdditionally, every tag has its own index page generated by `genfeed.py`, such\nas http://localhost:5000/tag/ubuntu\n\nThese tag index pages have the most recent articles on top.\n\nA series is like a tag except a post can only have one series and the series\npage is ordered with the oldest articles on top. This is useful if you're\nwriting related tutorials that are to be read in a specific order.\n\nA post can have a series and have tags. For example, \n\n    [post]\n    title: Programming Language Design Issues\n    description: We begin studying programming language design and implementations\n        by examining the history of programming languages, the role of programming\n        languages, and the details on programming environments.\n    time: 2013-02-14 Thu 11:22 PM\n    series: programming-languages-4th-edition\n    tags: computer-science\n\nFor this example, it's necessary to have the directory\n`joequery/blog/posts/series/programming-languages-4th-edition` exist, versioned\nwith a `.gitkeep` file.\n\n### Blog images\n\nSuppose we have an article `easy-math` in the `math` category. So the path to\nour article would be `joequery/blog/posts/math/easy-math`. If we want to include\nimages in our article, we would do the following:\n\n    $ cd joequery\n    $ cd static/images\n    $ mkdir -p math/easy-math\n\nNow we can place images in the `static/math/easy-math` directory. Suppose we\nhave \"img1.png\", \"hello.jpg\" in the directory, and now we want to have those\nimages appear in our post.\n\nSomewhere in the `joequery/blog/posts/math/easy-math/body.html` file, we would\nwrite\n\n    {{blogimg(g,p, \"img1.png\")|safe}}\n\nThis would produce the image tag\n\n    \u003cimg src=\"/static/images/math/easy-math/img1.png /\u003e\n\n#### How it works (if you care)\n\nThe above is a bit cryptic, so I'll explain what it does. `blogimg` is what's\nknown as a macro in Jinja2, the default templating system used by Flask. The\npurpose of this custom macro is to generate an img tag. Jinja2 forces us to\ndeclare the returned string of a macro safe to render as html, hence the `safe`\nat the end.  The first argument, `g`, represents Flask's global object that\nwe're free to populate with anything. In my case, I populated it with a property\ncalled `assets`. That way I can specify different places for Flask to look for\nimages and static files on production, such as Amazon S3 (Currently I have\n`g.assets` set to the `joequery/static` directory both on development and\nproduction, but you can see the `joequery/settings.py` file where that can\neasily be changed). The second parameter, `p`, is a dictionary holding a lot of\ninformation about the current post. The last parameter is the name of the file.\n\n### Code snippets\n\nWhat I believe is the most useful feature of my site is the ability to easily\nembed source files into a post. Very simple code snippets can be written\ndirectly to the post just by indenting four spaces. However, when you want to\ncreate complex programming examples, it gets cumbersome to extract code you've\nwritten on your article, go compile it, edit it, paste it back, and repeat as\nyou find issues. Here was my solution:\n\nSuppose you're working on an article in `joequery/blog/posts/code/learn-python`.\nYou make an example python file, say `learn-lists.py`. Place that in the post\ndirectory, and then you can call that source file into the post via\n\n    {{ snippet(p, \"learn-lists.py\")|safe}}\n\nAdditionally, a link to a plain-text version of the source file (similar to\nGithub's Raw) is automatically generated for you and linked to in the source.\nThis is extremely convenient for people who wish to `wget` your code snippet\nonto a server.\n\nIn order to avoid worrying about cleaning up .o or .pyc files, an extension\nwhitelist is located in the `display_raw_source_file()` function in the \n`joequery/blog/routes.py` file. I do recommend adding any type of\nobject/bytecode file to your `.gitignore`, though.\n\n### Notes on genfeed.py\n\nNo files generated by genfeed.py are versioned. If you're pushing your repo to a\nproduction server, be sure to have genfeed.py run afterwards.\n\n### Notes on cropping the Jarnal template for blogs:\n\nResize image: 850xwhatever\nCanvas size: 675x950\n\n[0]: http://joequery.me\n[1]: http://flask.pocoo.org/\n[2]: http://joequery.me/code/environment-variable-c/\n[3]: https://github.com/joequery/joequery.me/blob/master/joequery/blog/posts/code/minify-js-commandline/meta.txt\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoequery%2Fjoequery.me","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoequery%2Fjoequery.me","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoequery%2Fjoequery.me/lists"}