Draw this shape without picking up your pen

For many years, while in a meeting or in a moment of free time, I have tried to draw this shape without picking up my pen or drawing over the same two points twice.

shape

At best I would get 1 line away, but never completed the shape.

I wanted to know if it was even possible. So I wrote some python code to try every possible combination.

But, the code is below.

#!/usr/bin/env python3

import copy
import sys

lines = {
        1:[2,3],
        2:[1,3,4,6,7],
        3:[1,2,5,6,7],
        4:[2,5,6,7],
        5:[3,7],
        6:[2,3,4,7,8],
        7:[2,3,5,6,8],
        8:[6,7]
    }

def check(cstate):
    for offset in lines:
        if sorted(lines[offset]) != sorted(cstate[offset]):
            return
    print("Solution!")
    sys.exit()

def iteration(clocation, cstate):

    if len(cstate) == 8:
        check(cstate)

    for ilocation in lines[clocation]:
        nstate = copy.deepcopy(cstate)
        y = nstate.get(clocation, [])
        x = nstate.get(ilocation, [])

        if ilocation in y:
            continue

        y = y + [ilocation]
        x = x + [clocation]

        nstate[clocation] = y
        nstate[ilocation] = x
        iteration(ilocation, nstate)

iteration(1, {})
iteration(2, {})

The lines list is an abstraction of the possible points in the shape and where they can connect to. Point 1 is the top point, 2 and 3 are the top corners of the square, 4 and 5 are the far left and right points of the triangle, etc.

Starting at points 1 and 2. Point 1 is functionally the same as points 4, 5 and 8, while point 2 is the same as 2, 3, 6 and 7. No need for unnecessary iterations. Give its current location, the code recursively builds lines to all possible connection points. If no points are available, it just returns.

It breaks when all possible links are met, as seen by the check function. This is done by checking if every point is touched at least one, and then iterating through all points to see if that point is connected to every possible other line.

Turns out it is not possible.

Sucks.

My python3 Programming Environment

UPDATE: I have since started using a very good vimrc. I recommend it over mine listed below. My only modification is that I removed all line numbers, eww.

I ssh into a FreeBSD jail with everything setup.

The Jail runs on code.mydomainname.com, which has an internet-routable IPv6 address – and IPv4 behind a NAT, (boo!)

I have a virtualenv already built-out. (more about my pip list later)

The set my ~/.bashrc to execute source enter-env.sh (even though I run ksh)

My REPL is ptpython, which just requires touch ~/.ptpython/config.py.

I use gitlab, since they offer free repositories, and then periodically manually backup my code at other locations. If there are automatic ways of doing this, I would be interested.

My project’s gitlab wiki has copy-paste instructions to install all necessary packages, both on FreeBSD and Debian (well….Ubuntu) and subsequent python3 packages that you install with pip.

My default browser is vim, and I set ~/.vimrc to: set ts=4 / set expandtab. I used to set syn on, but that does not seem necessary anymore.

My project requires a PostgreSQL database, so I included the very simple instructions on installation and configuration in the gitlab wiki.

Finally, though I typically code off of a FreeBSD Jail, everything is configured to run on Debian. The main reason it works on Debian is because my personal computer (before my Chromebook took over) is was Mint, but I intend to run this code on a FreeBSD server, primarily for ZFS. I used to code on a Raspberry Pi, but it was too slow.

It takes me about 5 minutes to rebuild this environment, in the event that it goes down (which it never does).

Thoughts?

Adding Arbitrary XML to python-docx

I am thankful to the developers of python-docx, they did a great job, especially since OpenXML is beyond confusing. However, I have two respectful criticisms: Python-docx lacks several key features and though it is properly written…its really confusing to follow the code.

Its just a few steps. Identify the entry-point, create a new tag, and append it to the document.

from docx.oxml.shared import OxmlElement # Necessary Import
tags = document.element.xpath('//w:r') # Locate the right  tag
tag = tags[0] # Specify which  tag you want
child = OxmlElement('w:ARBITRARY') # Create arbitrary tag
tag.append(child) # Append in the new tag

And that’s it!

I also found inserting xml-snippet into docx using the python-docx api online (giving credit where credit is due). Defining the variables:

from docx.oxml.shared import qn
child.set( qn('w:val'), 'VALUE') # Add in the value

Thoughts?

Duplicate a Django modelformset_factory Form

I created a formset_factory and wanted to have a simple “click me to add another form”. This seemed like a routine task, but the solutions I found online were unnecessarily complicated or required me to install a separate Django app, which I had no intention of doing.

So I created my own…

The only pre-requirement that this needs besides standard Django is jQuery.

So here is a rough overview of how this works:

  • Create a modelformset in my views.py and send it to the template.
  • Add in a link that’s executed to trigger the new form adding.
  • Django’s formset_factory’s required management_form creates the id_form-TOTAL_FORMS hidden variable. The jQuery must update this value.
  • Have jQuery locate the current form and create a blank copy from.
  • Update the name and id parameters of the copied form using jQuery
  • Identify where to paste the new form
  • Paste it there!

Here is my views.py snippet. In my case, the model is called “Component” and the related form is called “ComponentForm”. I define them as follows:

ComponentFormSet = modelformset_factory(Component, form=ComponentForm)
componentformset = ComponentFormSet( queryset=Component.objects.none() )

The queryset must be set to Component.objects.none() for whatever reason, otherwise you will get the latest Component value. I pass the “componentformset” in the context to the template.

Next, the HTML must be rendered in the template as follows. Noticed that I used componentformset.0 with the “.0“. Why? Because componentformset, being a modelformset_factory, is a set of forms, not an individual form. We have an individual form, so I am only going to display the first one in the list. After that, the template includes a tbody called “formtemplate”. This will later tell our jQuery where to copy our template from. Finally, the <a> tag is necessary to tell jQuery when to add a new form. The newcomponents 

is where the new form will be pasted.

{{ componentformset.management_form }}
<tbody id="formtemplate">
{{ componentformset.0 }}
tbody>

<tbody id="newcomponents">
tbody>
<a href="#" id='addForm'>Add Componenta>

Next is the Javascript. (In my actual production code I put this above the HTML, but you could really put this anywhere since it’ll only trigger when the page fully renders).

<script type="text/javascript">
    $(document).ready(function() {
      var addForm = $('#addForm');
      var formNumberObject = $('#id_form-TOTAL_FORMS');

      var addForm = function(e) {
        e.preventDefault();
        newFormCount = parseInt(formNumberObject.val()) + 1;
        formNumberObject.val( newFormCount );

        var tabletemplate = $('#formtemplate tr').clone();
        var pastehere = $('#newcomponents');

        changevalues = tabletemplate.find('[id^=id_form-0]');
        changevalues.each( function(i, index) {
          currentid = $(this).attr('id').replace(/(id_form-)[0-9]+/, 'id_form-' + (newFormCount-1) );
          $(this).attr('id', currentid);

          currentname = $(this).attr('name').replace(/(form-)[0-9]+/, 'form-' + (newFormCount-1) );
          $(this).attr('name', currentname);

        });

        tabletemplate.appendTo(pastehere);
      }
      addForm.on('click', addForm);
    });
  
script>

The JS does the following. This is in order of the logic of the program, not in order of the code above, but you should be able to piece it together.

  • Identify the ‘addForm’ <a> link and set it to execute the function ‘addForm’ (yes, they have the same name, but you can change that)
  • Identify the id_form-TOTAL_FORMS by ID in the rendered HTML. Again, this is produced by the management_form part of our formset_factory.
  • Identify the number of forms. I suppose I could have just set this to 0 by default, but I’ll have the JS do it for me.
  • When the user clicks the ‘addForm’ link, it will execute the function ‘addForm’, which does the following:
    • Add 1 to the current newFormCount value.
    • Create a copy of the form and store it in “tabletemplate”.
    • Identify where to paste the data, identified by “newcomponents”.
    • Find each instance where the ID is in the RegEx pattern “id_form-0”
    • Iterate for each instance, and replace the number 0 with the current number. This will keep the individual component name intact, but update the count.
  • Append the newly created form to the “pastehere” tbody.

With that, you should be able to add a new form with the click of a button!

Thoughts? Comments? Please do let me know so I can fix any mistakes or update the code as needed. And remember…Free Palestine!

Custom Django Fixture Imports

I needed to convert an XML document into a customize Django model with modifications to the based on programmable logic. Converting it to my model’s fixture would take too long and be unnecessary work, so I instead opted to manually convert the data.

I figured I could just import the Django model object, as is follows:

from tester.models import Control
a = Control()

However, I got the following vexing error in red:

$ python code.py
Traceback (most recent call last):
File "code.py", line 1, in
from tester.models import Control
File "/home/nahraf/src/beater/tester/models.py", line 5, in
class Control(models.Model):
File "/home/nahraf/src/beater/tester/models.py", line 6, in Control
family = models.CharField(max_length=40)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/fields/__init__.py", line 1012, in __init__
super(CharField, self).__init__(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/fields/__init__.py", line 146, in __init__
self.db_tablespace = db_tablespace or settings.DEFAULT_INDEX_TABLESPACE
File "/usr/local/lib/python2.7/dist-packages/django/conf/__init__.py", line 46, in __getattr__
self._setup(name)
File "/usr/local/lib/python2.7/dist-packages/django/conf/__init__.py", line 40, in _setup
% (desc, ENVIRONMENT_VARIABLE))
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

In short, the solution is to set your Django application’s settings prior to importing the Django object. (My “tester” application is called “beater” cuz I beat up on it 🙂

My corrected code is as follows:

import os
# This must be executed before the import below
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "beater.settings")
import django
django.setup()
from tester.models import Control
Control()

After that, the code was able to import and utilize object. I hope this helps!

Free Palestine, Boycott Apartheid Israel!