tag:blogger.com,1999:blog-59802015564615037622024-03-06T02:49:50.243+01:00Can I Play With Madness?Pensieri, parole, opere ed omissioni... per mia colpa, mia colpa, mia grandissima colpa...S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.comBlogger222125tag:blogger.com,1999:blog-5980201556461503762.post-38667272490622318272015-06-29T21:00:00.000+02:002015-06-30T10:18:48.489+02:00django-cms and haystack: update index with a django signal Haystack provides the <i>HAYSTACK_SIGNAL_PROCESSOR</i> settings and it works well, <span class="short_text" id="result_box" lang="en"><span class="hps">especially</span></span> the <i>RealtimeSignalProcessor</i> for the django models.<br />
<br />
But, the problem that I had was update the search index when the user publishes a django-cms page.<br />
In fact, if you use the <i>HAYSTACK_SIGNAL_PROCESSOR</i> settings, haystack will update your index with the draft copy of the page - both if you save a plugin or a page itself - and it's not a good thing for user experience... and also for our indexes! :-)<br />
<br />
Going deep into this issue, I wrote a signal that wraps the <i>RealtimeSignalProcessor</i> and that doesn't break the django-cms publish command if there's no connection to the search engine.<br />
<br />
<pre># models.py
# other imports
import logging
# ...
logger = logging.getLogger(__name__)
# ...
def real_time_signal_processor(instance, **kwargs):
from elasticsearch.exceptions import ConnectionError
from django.conf import settings
from haystack import signals
from haystack.utils import loading
connections = loading.ConnectionHandler(settings.HAYSTACK_CONNECTIONS)
connection_router = loading.ConnectionRouter()
if hasattr(settings, 'HAYSTACK_ROUTERS'):
connection_router = loading.ConnectionRouter(settings.HAYSTACK_ROUTERS)
try:
signals.RealtimeSignalProcessor(connections, connection_router).handle_save(kwargs['sender'], instance)
except ConnectionError as e:
logger.error(e.message)
post_publish.connect(real_time_signal_processor)
</pre>
<br />
Just for curiosity, the <i>models.py</i> is a part of the django app named search, where I put all the search engine code (custom backends, forms, etc). I think it's a good practice and nice to have an isolated app that serve to search purposes.<br />
<br />
That's it!<br />
<br />
Cheers<br />
<br />
[Update] The code above catch the exception from elasticsearch client. With a generic exception, you can use that signal with your search backend. IMHO is not a good practice to catch a generic Exception, then use the appropriate one! :-)S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-26229671964449829872015-06-24T21:00:00.000+02:002015-06-24T21:00:00.866+02:00Dealing with elasticsearch reindex and haystack<blockquote class="tr_bq">
Prerequisites: some knowledge on <a href="http://django-haystack.readthedocs.org/" target="_blank">haystack</a> and <a href="https://www.elastic.co/guide/index.html" target="_blank">elasticsearch</a> and obviously <a href="https://docs.djangoproject.com/en/1.8/" target="_blank">django</a> are required.</blockquote>
<br />
When we're using e.g. synonyms or stopwords in our indices, we need to reindex our data in order to have the new settings on board. Elasticsearch documentation rises this problem and suggest how to fix, see <a href="https://www.elastic.co/guide/en/elasticsearch/guide/current/reindex.html" target="_blank">Reindex Your Data</a>. Well, let's do with haystack!<br />
<br />
Suppose we have this haystack settings:<br />
<br />
<pre>HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'search.backend.ElasticsearchEngineCustom',
'URL': 'http://127.0.0.1:9200/',
'INDEX_NAME': 'haystack',
'BATCH_SIZE': 1000
}
}
</pre>
<br />
As you can see I created a custom backend, but it's not the focus on this article, please read the links below to get an idea:<br />
<ul>
<li><a href="https://wellfire.co/blog/custom-haystack-elasticsearch-backend/" target="_blank">Stretching Haystack's ElasticSearch Backend</a></li>
<li><a href="http://www.stamkracht.com/extending-haystacks-elasticsearch-backend/" target="_blank">Extending Haystack’s Elasticsearch backend</a></li>
<li><a href="http://stackoverflow.com/questions/27802628/search-for-multiple-words-elasticsearch-haystack" target="_blank">Search for multiple words elasticsearch haystack</a></li>
</ul>
As a sample, for this article the backend module looks like:<br />
<br />
<pre>from haystack.backends.elasticsearch_backend import ElasticsearchSearchBackend
class ElasticsearchEngineBackendCustom(ElasticsearchSearchBackend):
def __init__(self, connection_alias, **connection_options):
super(ElasticsearchEngineBackendCustom, self).__init__(connection_alias, **connection_options)
self.setup_complete = True
class ElasticsearchEngineCustom(ElasticsearchSearchEngine):
backend = ElasticsearchEngineBackendCustom
</pre>
<br />
Setting <i>self.setup_complete </i>to <i>True</i> avoids the 'put index' call from haystack setup and permits us to use <i>INDEX_NAME</i> as index alias name.<br />
<br />
Now we have to manage all the haystack index setup via management commands overriding <i>rebuild_index</i> and creating the <i>reindex_index</i> command, let's do it.<br />
<br />
In a module named <i>utils</i>, I created the <i>current_index</i> function that is an utility function that return the current index in use and the next version number for the current index (we'll use the number on management commands). Below the code:<br />
<i> </i>
<br />
<pre>INDEX_TEMPLATE = "{}_v{}"
def number_sequence():
n = 0
while True:
yield n
n += 1
def current_index(es_client, index_name):
version = number_sequence()
index = INDEX_TEMPLATE.format(index_name, version.next())
if not es_client.indices.exists_alias(name=index_name):
return INDEX_TEMPLATE.format(index_name, 0), 1
while not es_client.indices.exists(index=index):
index = INDEX_TEMPLATE.format(index_name, version.next())
return index, version.next()
</pre>
<br />
The guard for <i>exists_alias</i> is used to know if the rebuild_index has been run at least once. If no alias is present, there is no index. The version number added to the name start from 0. The default index, when the <i>rebuild_index</i> command is called will be <i>haystack_v0</i>.<br />
An objection is the use of <i>while not...</i> because the function search from zero to current index version number and it could be a great number and for each number hits the elasticsearch; it could be more efficient having two indexes name. Take this as a "quick win" solution and improving it!<br />
<br />
Let's go to write the <i>reindex_index</i> command, the steps are:<br />
<ul>
<li>Delete the new index ignoring the errors</li>
<li>Create the new index with the current index settings and fields mapping</li>
<li>Reindex data from current index to new index</li>
<li>Zero downtime: remove from alias the current index and add the new index</li>
<li>Delete current index, that is old. The new one is used </li>
</ul>
<pre>from elasticsearch import Elasticsearch
from elasticsearch.helpers import reindex
from django.core.management.base import BaseCommand
from django.conf import settings
from search.utils import current_index, INDEX_TEMPLATE
class Command(BaseCommand):
def __init__(self):
super(Command, self).__init__()
self.es_client = Elasticsearch(hosts=settings.HAYSTACK_CONNECTIONS['default']['URL'])
self.index_alias = settings.HAYSTACK_CONNECTIONS['default']['INDEX_NAME']
self.current_index, version = current_index(self.es_client, self.index_alias)
self.new_index = INDEX_TEMPLATE.format(self.index_alias, version)
# Update settings with fields mapping
self.index_settings = settings.ELASTICSEARCH_INDEX_SETTINGS
self.index_settings.update(self.es_client.indices.get_mapping()[self.current_index])
def handle(self, *args, **options):
self.es_client.indices.delete(index=self.new_index, ignore=[404, 400])
self.es_client.indices.create(index=self.new_index, body=self.index_settings)
reindex(self.es_client, self.current_index, self.new_index)
update_aliases = {
"actions": [
{"remove": {"index": self.current_index, "alias": self.index_alias}},
{"add": {"index": self.new_index, "alias": self.index_alias}}
]
}
self.es_client.indices.update_aliases(body=update_aliases)
self.es_client.indices.delete(index=self.current_index)
print(u"Successfully reindex.")
</pre>
<br />
Now we need to override <i>rebuild_index</i> command with:<br />
<ul>
<li>Rewriting <i>clear_index</i> call</li>
<li>Creating the alias using the <i>INDEX_NAME</i> from haystack settings</li>
<ul>
<li>delete all index that match <i>haystack_v*</i></li>
<li>create the index "v0" with haystack settings</li>
<li>create the alias <i>haystack</i> to <i>haystack_v0</i></li>
</ul>
<li>Call the <i>update_index</i></li>
</ul>
<pre>from elasticsearch import Elasticsearch
from django.conf import settings
from django.core.management import call_command
from haystack.backends.elasticsearch_backend import ElasticsearchSearchBackend
from haystack.management.commands import rebuild_index
from search.utils import INDEX_TEMPLATE
class Command(rebuild_index.Command):
def __init__(self):
super(Command, self).__init__()
self.es_client = Elasticsearch(hosts=settings.HAYSTACK_CONNECTIONS['default']['URL'])
self.index_name = INDEX_TEMPLATE.format(settings.HAYSTACK_CONNECTIONS['default']['INDEX_NAME'], 0)
self.index_alias = settings.HAYSTACK_CONNECTIONS['default']['INDEX_NAME']
def _create_index_alias(self):
self.es_client.indices.delete(index=self.index_name.replace("0", "*"))
self.es_client.indices.create(index=self.index_name,
body=ElasticsearchSearchBackend.DEFAULT_SETTINGS)
print(u"Created index {}".format(self.index_name))
self.es_client.indices.put_alias(index=self.index_name, name=self.index_alias)
print(u"Added index {}_v0 to alias {}.".format(self.index_name, self.index_alias))
def handle(self, **options):
self._create_index_alias()
call_command('update_index', **options)
</pre>
<br />
Instead of <i>ElasticsearchSearchBackend.DEFAULT_SETTINGS</i> you should use your elasticsearch settings. The links above explained how to make it.<br />
A nice improvement is having the yes/no options, the rebuild command is <span class="short_text" id="result_box" lang="en"><span class="hps">destructive</span></span>.<br />
<br />
Any suggestions will be appreciated!
That's it. Enjoy! :-)<br />
<br />
CheersS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-30072955268303458602015-06-18T21:00:00.000+02:002015-06-19T09:19:52.849+02:00Django Haystack Elasticsearch: index pdf filesIn this article I would like to explain how to index pdf files into a haystack elasticsearch backend and to follow you need some <span class="short_text" id="result_box" lang="en"><span class="hps">knowledge about <a href="https://docs.djangoproject.com/" target="_blank">django</a> and <a href="http://django-haystack.readthedocs.org/" target="_blank">haystack.</a></span></span><br />
<span class="short_text" id="result_box" lang="en"><span class="hps">Elasticsearch configuration is not treated.</span></span><br />
<br />
<b>Beginning </b><br />
<b><br /></b>
IMHO, haystack documentation is not very clear about "FileIndex", or better, yes but only for Solr backend, see <a href="http://django-haystack.readthedocs.org/en/latest/rich_content_extraction.html" target="_blank">Rich Content Extraction</a>; for elasticsearch backend you need to get your hands dirty :-)<br />
<br />
<b>Issue</b> <br />
<ul>
<li>The pdf files for index are located into the django media directory under document folder and subfolders.</li>
</ul>
<br />
<b>That we need</b><br />
<ol>
<li>Retrieve all files and put some data into a list of dictionaries</li>
<li>A pdf file model, haystack requires a model in order to perform index</li>
<li>A custom haystack elasticsearch backend, we need to override the <i>extract_file_contents</i> method</li>
<li>A <i>search_indexes.py</i> file </li>
</ol>
<u>Solving 1.</u><br />
<br />
This is simple, walk through the directories and store the full path into a list of dictionaries.<br />
I left the exercise to the reader.<br />
The final result is to obtain a result like this:<br />
<br />
<pre>[
{"path": "/path/to/media/my_fantastic_pdf.pdf, "url": "media/url/my_fantastic_pdf.pdf"},
{"path": "...", "url": "..."},
...
]
</pre>
<br />
<u>Solving 2.</u><br />
<br />
First of all we need a model, not managed:<br />
<br />
<pre>class PdfFileInfo(models.Model):
path = models.CharField(max_length=250)
url = models.CharField(max_length=250)
objects = PdfFileInfoManager()
def get_absolute_url(self):
return self.url
class Meta:
managed = False
</pre>
<br />
As you can see we don't have a real table, then we need to create a custom QuerySet and Manager in order to supply to this lack.<br />
Searching around the net I've found this article <a href="http://ramenlabs.com/2010/12/08/how-to-quack-like-a-queryset/" target="_blank">how to quack like a QuerySet</a> that explains how to have a copy of original django QuerySet and having some nice tricks.<br />
<br />
Below the code of QuerySet:<br />
<br />
<pre>class PdfFileInfoQuerySet(object):
def __init__(self):
# avoid circular dependencies
from .models import PdfFileInfo
self.pdf_files = []
docs = retrieve_files() # remember it's your homework :-P
for pk, doc in enumerate(docs):
doc['id'] = pk
self.pdf_files.append(PdfFileInfo(**doc))
def __iter__(self):
for pdf_file in self.pdf_files:
yield pdf_file
def __repr__(self):
return repr(self.pdf_files)
def __getitem__(self, k):
if not isinstance(k, (slice, int, long)):
raise TypeError
assert ((not isinstance(k, slice) and (k >= 0))
or (isinstance(k, slice) and (k.start is None or k.start >= 0)
and (k.stop is None or k.stop >= 0))), "Negative indexing is not supported."
if isinstance(k, slice):
return self.pdf_files[k]
else:
return self.pdf_files[k:k + 1][0]
def count(self):
return len(self.pdf_files)
def all(self):
return self._clone()
def filter(self, *args, **kwargs):
return self._clone()
def exclude(self, *args, **kwargs):
return self._clone()
def order_by(self, *ordering):
return self._clone()
def _clone(self):
qs = PdfFileInfoQuerySet()
qs.pdf_files = self.pdf_files[:]
return qs
</pre>
<br />
Note on a pitfall: assign the pk to the model ensures that indexer will create all the documents into the index, otherwise it will create only one document (the last item).<br />
<br />
And for the Manager:<br />
<br />
<pre>class PdfFileInfoManager(models.Manager):
def all(self):
return PdfFileInfoQuerySet()
</pre>
<br />
<u>Solving 3.</u><br />
<br />
Creating a custom backend... The "easy" part :-)<br />
I choose pyPdf for extracting pdf contents. [<a href="http://code.activestate.com/recipes/511465-pure-python-pdf-to-text-converter/" target="_blank">Python recipe</a>] <br />
<br />
<pre>class ElasticsearchEngineBackendCustom(ElasticsearchSearchBackend):
# ...
def extract_file_contents(self, file_obj):
pdf = pyPdf.PdfFileReader(file_obj)
content = ""
for num_page in range(0, pdf.getNumPages()):
content += pdf.getPage(num_page).extractText() + "\n"
content = (" ".join(content.replace(u"\xa0", " ").strip().split())).encode("ascii", "xmlcharrefreplace")
pdf_info = {
'contents': content
}
return pdf_info
class ElasticsearchEngineCustom(ElasticsearchSearchEngine):
backend = ElasticsearchEngineBackendCustom
</pre>
<br />
You can find some other info about extending backend on my <a href="http://stackoverflow.com/questions/27802628/search-for-multiple-words-elasticsearch-haystack/30864776#30864776">stackoverflow answer</a>
<br />
<br />
<u>Solving 4.</u><br />
<br />
Cool, now we have the basis to build the index like haystack documentation says.<br />
<br />
<pre>class FileIndex(indexes.SearchIndex, indexes.Indexable):
# ...
def prepare(self, obj):
data = super(FileIndex, self).prepare(obj)
extracted_data = self._get_backend(None).extract_file_contents(open(obj.path, "rb"))
t = loader.select_template(('search/indexes/file_text.txt',))
data['text'] = t.render(Context({'object': obj, 'extracted': extracted_data}))
return data
def get_model(self):
return PdfFileInfo
def index_queryset(self, using=None):
return PdfFileInfo.objects.all()
</pre>
<br />
The template <i>search/indexes/file_text.txt</i> is very simple:<br />
<br />
<pre>{{ extracted.contents|striptags|safe }}
</pre>
<br />
That's it, run the <i>rebuild_index</i> command and see indexer in action. <br />
<br />
This is a working example, maybe require some adjustments for your purpose, e.g. I think that with a little effort you can index file if it's an "attachment file" in your django model.<br />
<br />
Any suggestions will be appreciated!<br />
Cheers!
S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com4tag:blogger.com,1999:blog-5980201556461503762.post-2757639500772319402014-03-15T18:03:00.002+01:002014-03-15T18:03:52.605+01:00duckdns e localtunnelDopo un po' di tempo... un post, giusto per tenere traccia delle sperimentazioni.<br />
<br />
BTW, cercavo un servizio per condividere una web application dal RaspberryPi e ho trovato un paio di soluzioni interessanti.<br />
<br />
<b>Dynamic DNS</b><br />
<br />
<a href="http://duckdns.org/" rel="nofollow" target="_blank">DuckDNS</a> un servizio di gratuito di DNS dinamico.<br />
Richiede la configurazione del router per IP e porte.<br />
Ad oggi mette a disposizione fino a quattro domini di terzo livello per utente, non male.<br />
<i>Nota</i>: funziona pure con Fastweb, i nuovi router prevedono la configurazione via MyFastPage.<br />
<br />
Sperimentazione: semplice form di file upload e un'applicazione <a href="http://flask.pocoo.org/" rel="nofollow" target="_blank">Flask</a> per gestire la post.<br />
<br />
<b>Localhost Anywhere</b><br />
<b><br /></b>
<a href="http://localtunnel.me/" rel="nofollow" target="_blank">localtunnel</a> e` un servizio di "<a href="http://en.wikipedia.org/wiki/Tunneling_protocol" rel="nofollow" target="_blank">tunneling</a>" ed evita di configurare DNS e router.<br />
Facile da installare, richiede <a href="http://nodejs.org/" rel="nofollow" target="_blank">nodejs</a>.<br />
Consiglio l'utilizzo di <a href="https://github.com/creationix/nvm" rel="nofollow" target="_blank">nvm</a> per gesitre le installazioni di nodejs.<br />
Molto utile in fase di sviluppo per condividere il progetto che gira in locale con l'esterno.<br />
<br />
Sperimentzione: un "hello world!" da una applicazione web <a href="http://www.tornadoweb.org/" rel="nofollow" target="_blank">Tornado</a>... d'altra pare c'e`sempre il <a href="http://www.kegel.com/c10k.html" rel="nofollow" target="_blank">C10K problem</a> da valutare... :-P<br />
<br />
<br />
SaniS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-6089040946610312262013-03-21T19:26:00.000+01:002013-03-21T19:27:12.666+01:00Rebus (7)<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdhkZSpfz5F1U-3wue7eMJpzwgofCo9G84bmkf4Pxp_CVLYp44eMPqV3eWYQpba2DwRqGrxYtCwCKiA6rFO8oXPg9vRCBGvE7m_s-knnaceexhJ5iulm0VXmZGncXraQgIjgZFe9pgomvC/s1600/the_lamb.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em;"><img border="0" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdhkZSpfz5F1U-3wue7eMJpzwgofCo9G84bmkf4Pxp_CVLYp44eMPqV3eWYQpba2DwRqGrxYtCwCKiA6rFO8oXPg9vRCBGvE7m_s-knnaceexhJ5iulm0VXmZGncXraQgIjgZFe9pgomvC/s200/the_lamb.jpg" width="200" /></a>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgB81xq4pYlFsF2AxZTmB5yawdq-ui9nsDhaEz4_XpyzHbDISgAjnE5K7WOBd_gSqFpJG8drLibYxxkXgYJhRi1Z9wxchSXwehkfcunBDdAn9C9u7YxQvhYUOujMCgPtC1MdOTGAsfAGP5z/s1600/4090783_big.jpg" imageanchor="1" style="float: left; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgB81xq4pYlFsF2AxZTmB5yawdq-ui9nsDhaEz4_XpyzHbDISgAjnE5K7WOBd_gSqFpJG8drLibYxxkXgYJhRi1Z9wxchSXwehkfcunBDdAn9C9u7YxQvhYUOujMCgPtC1MdOTGAsfAGP5z/s200/4090783_big.jpg" width="200" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Credits <a href="https://twitter.com/ngw" title="@ngw">@ngw</a>
</div>S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-27497676360825324122012-12-04T15:00:00.000+01:002012-12-04T15:00:06.832+01:00November Rain!Titolo forse non troppo azzeccato, una bella canzone dei Guns n' Roses, ma mi ispirava molto perché Novembre è stato un mese denso di conferenze.<br />
<br />
Tanto codice, tanta gente, tanti punti di vista... Never stop thinking!<br />
<br />
10/11/2012 - NodeJSConf - Brescia - <a href="http://nodejsconf.it/">http://nodejsconf.it/</a><br />
Molto ricca (forse troppo) di cloud e windows Azure, ciononostante ne sono uscito con una miriade di idee, voglia di sperimentare e molto soddisfatto.<br />
Mitici e impagabili i ragazzi del WebdeBS, organizzano sempre delle conferenze di alto livello.<br />
Una cosa molto simpatica è che ci siamo salutati con "ci vediamo la prossima settimana, o a quella dopo...".<br />
<br />
17/11/2012 - CodemotionVenezia - <a href="http://venezia.codemotion.it/">http://venezia.codemotion.it/</a><br />
H-Farm, Roncade TV... Quanti ricordi! Bella la location, c'ho passato qualche anno lavorativo...<br />
BTW, ho pure fatto un intervento "particolare", un'introduzione a Python vista da un'altra prospettiva, quella del merletto al tombolo... <br />
Dai commenti ricevuti sembra sia stata "approvata", da altri meno, nevermind! :-)<br />
Un particolare ringraziamento va al PyPerugia, la rappresentanza mi ha supportato durante la presentazione.<br />
Ci si vedrà presumibilmente ad EuroPython! :-)<br />
Mi rimangono ancora in mente le due chiacchere scambiate con "el paron de casa": mi ha fatto i complimenti per la presentazione e si è scusato per il proiettore (praticamente non proiettava bene, mi sembra un buon riassunto).<br />
Dopo tanti anni "el paron" si ricordava di me, in "eic'h" passano un sacco di persone ed è bello sentirsi dire "quando vuoi tornare, qua posto ce n'è"... un gran bel personaggio! Grazie!<br />
Tra le altre cose l'evento "Codemotion" ha portato ad un evento nell'evento, un metaevento: una "gita aziendale".<br />
Fico, molto fico che l'azienda dove lavoro sia stata presente, eravamo tutti ma proprio tutti, un bel momento di aggregazione e team building! Fico! :-)<br />
La giornata è trascorsa via veloce, tra una presentazione e l'altra, vari caffè, chiacchere con amici/colleghi di vecchia data e altri... visti la settimana precedente! :-)<br />
Peccato non esser stato intervistato, potevo far vedere il mio faccione nel web... d'altra parte io non ho cercato loro e loro non hanno cercato me! :-)<br />
<br />
24/12/2012 - AgileDay - Milano - <a href="http://www.agileday.it/">http://www.agileday.it</a><br />
Il mese si è conluso con la ciliegina sulla torta.<br />
Mi sono già segnato che ci sono da riguardare le presentazioni di Claudio Perrone, Andrea Provaglio ed Emanuele DelBono, illuminanti.<br />
Alcuni si sono lamentati che c'era poco codice, dipende... Tutto sommato "l'agile" è una serie di metodologie da applicare al contesto "software".<br />
Bravi anche qui gli organizzatori, non è facile metter in piedi un evento gratuito per 600 persone, co vuole impegno!<br />
<br />
November rain... Rileggendo il post... Non ho detto praticamente nulla... Solo un post perché sentivo il bisogno di scrivere qualcosa! :-D<br />
<br />
Prossimo evento: coderetreat, Milano 08/12/2012!!!<br />
Per chi ci sarà: ci vediamo sabato!<br />
<br />
Sani!S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-69352181742887476882012-12-04T14:43:00.001+01:002012-12-04T14:43:06.121+01:00Il Font fa il Monaco, anche su Ubuntu!Il font che assomiglia di più al Monaco è il DejaVu Sans Mono, ma ho avuto sempre una certa "invidia" per il font monospace e tondeggiante di Cupertino.
<br />
Mi sono chiesto, posso usarlo con Terminator per dare un tocco di stile al mio terminale?<br />
<br />
Le istruzioni e script per l'installazione su ubuntu sono sul mio github :)<br />
Link:
<a href="https://github.com/cstrap/monaco-font" rel="nofollow" target="_blank">Monaco for Ubuntu</a><br />
<br />
Sani<br />
<br />S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-44070003821056931172012-07-10T14:51:00.006+02:002012-07-10T14:51:53.929+02:00EuroPython 2012 - FTW!<span style="background-color: white;">Settimana scorsa si è svolta la conferenza europea di Python ed essendo fortemente appassionato al linguaggio, quest anno mi son organizzato per tempo per partecipare.</span><br />
<div>
<br /></div>
<div>
<span style="background-color: white;">Ho selezionato le track da seguire,</span><span style="background-color: white;"> una bella dose di Flask, MongoDB, Plone e "Python white magic" :)</span></div>
<div>
<br /></div>
<div>
Da buon nerd e per vincere una maglietta ho risolto i vari "giochini ad incastro" (aka "cazzilli") proposti da Google e Spotify.</div>
<div>
I "cazzilli" di Google mi hanno intrippato a tal punto che ho sentito il bisogno di risolverli tutti, una sfida personale :)<br />
<br />
Cazzilli a parte è stata una settimana impegnata e ricca di incontri, difficile riassumere tutto in poche righe una settimana di evento!<br />
<br />
L'organizzazione dell'evento è stata di alto livello, tanti complimenti, anche perché da fonti certe il prossimo anno si fa tris! :)<br />
<br />
Sani<br />
<br />
PS: tutti i video della conferenza sono già online! <a href="http://www.youtube.com/user/PythonItalia" style="background-color: white;">http://www.youtube.com/user/PythonItalia</a></div>S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-70206845419115592862012-06-18T20:30:00.000+02:002012-06-22T11:14:05.198+02:00RubyDay IT 2012<blockquote class="tr_bq">
<span style="color: red; font-size: large;">MAKE REAL CODE NOT SPECS</span></blockquote>
<br />
... mi sembrava di non aver nessun punto di riferimento, come un bambino che entra in un cinema e pretende di capire... (cit.)<br />
<br />
Sì, non l'ho capita, ho chiesto lumi e sinceramente ancora non mi è chiaro il significato :)<br />
<br />
Nel complesso bene, bravi gli organizzatori, perché è sempre impegnativo organizzare conferenze e bravi anche ai relatori che si sono impegnati a preparare i talk.<br />
<br />
E' stata una giornata per rivedere amici e respirare un po' di aria diversa dal solito.<br />
<div>
<br /></div>
Ho trovato la conferenza, un po' troppo o forse voluta, orientata alla buzzword startup e non ho visto novità rispetto a quella dell'anno scorso.<br />
Menzione con un +1 e anche +2 a Roberto De Ioris di unbit e Matt Todd di github, per dirla in parole povere, valevano il prezzo del biglietto! :)<br />
<br />
Amaro in bocca per aver visto presentare tecnologie come se fosse un minestrone, senza arrivare ad un perché sono state utilizzate e quale problema hanno aiutato a risolvere; ciononostante buono a sapere che esistono ed avere un incipt per l'utilizzo. L'emozione gioca brutti scherzi! :)<br />
<div>
<br /></div>
<div>
Ma veniamo all'argomento forte della giornata, "fare startup": è un'impresa, al di là del senso imprendioriale del termine.</div>
L'ecosistema startup è complesso: budget limitati, diverse competenze da far convivere, ambiente piccolo e dinamico, cercare finanziamenti, cercare persone che sposino la tua causa e ne facciano parte attivamente, il rischio ...<br />
Ma una e una sola cosa è fondamentale ed è avere un "business plan" che fa da padrone alla tua "idea", perché senza non vai da nessuna parte, indipendentemente dalla bontà del risultato da ottere.<br />
<br />
Alla fine le "cose" più interessanti di qualsiasi conferenza saltano fuori con le persone che si incontrano nelle fasi di networking, quali buffet, spostamenti in auto e cena :)<br />
<br />
Grazie, alla prossima!<br />
<br />
SaniS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-46234688920109128042012-04-27T14:59:00.000+02:002012-04-27T14:59:17.949+02:00Queste sì che son soddisfazioni!<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqb2NDc3RwCCCzwDYuJ12iDOf5X37Z7haaf_II6tRgODmVQ503PZWfSpKMNcMdzVHQx_le5EOPSlnwaVXjFH8gDk4zyWSa8YdUAG-X683hsUtW7Px3To6cdLjjL_Un0phUIYoAGWN4bWXU/s1600/20120421_180123.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqb2NDc3RwCCCzwDYuJ12iDOf5X37Z7haaf_II6tRgODmVQ503PZWfSpKMNcMdzVHQx_le5EOPSlnwaVXjFH8gDk4zyWSa8YdUAG-X683hsUtW7Px3To6cdLjjL_Un0phUIYoAGWN4bWXU/s320/20120421_180123.jpg" width="320" /></a></div>
<br />
Cari Djangonauti... prendetevi cura delle vostre palle e loro si prenderanno cura di voi!<br />
<br />
SaniS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-17995208826327013822012-04-22T15:03:00.000+02:002012-04-27T14:59:39.693+02:00DjangoDay 2012 - BresciaL'emozione di tenere un talk al primo djangoday italiano è stata fin troppo alta: "debito d'ossigeno".<br />
<br />
Aspetto di vedere online il video, solo per vedere che faccia cianotica avevo :)<br />
Spero solo di non aver detto castronerie, l'emozione ha vinto sulla mia preparazione... del resto era la mia prima volta con così tanta gente!<br />
<br />
E' stata una bella conferenza, ricca di argomenti e di gente simpatica, guardate i video e le slide appena saranno online, c'è da imparare.<br />
<br />
Bravi tutti, dagli organizzatori agli speaker, una "conferenza di livello" come si suol dire.<br />
<br />
E poi alla fine, in semi disparte... <a href="http://beri.it/" rel="nofollow">Marco Beri</a> mi ha fatto una domanda!!! Ho ancora gli occhi lucidi!!!<br />
<br />
Qui trovate le mie slide e una "risposta": <a href="http://bit.ly/HXG1Xa">http://bit.ly/HXG1Xa</a><br />
<br />
Ancora grazie al <a href="http://www.webdebs.org/" rel="nofollow">WebdeBS</a>! Mi auguro ci siano ancora una e più edizioni!<br />
<br />
Sani!<br />
<br />
PS:<br />
"Prendevi cura delle vostre palle e loro si prenderanno cura di voi" cit. <a href="http://it.wikipedia.org/wiki/Palle_al_balzo_-_Dodgeball" rel="nofollow">Dodgeball</a><br />
Nelle slide ci sono anche vari riferimenti alla "<a href="http://it.wikipedia.org/wiki/Guida_galattica_per_gli_autostoppisti_(romanzo)">Guida galattica per autostoppisti</a>", ma anche a <a href="http://it.wikipedia.org/wiki/Codice_morse" target="_blank">codice morse</a>, <a href="http://it.wikipedia.org/wiki/Il_grande_Lebowski" rel="nofollow">The Big Lebowski</a>, <a href="http://it.wikipedia.org/wiki/Guerre_stellari" target="_blank">Star Wars</a> e ai <a href="http://it.wikipedia.org/wiki/Monty_Python" target="_blank">Monty Python</a>... a voi trovarle! ;)S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-58856655315178903662012-02-17T14:05:00.000+01:002012-02-17T14:05:00.299+01:00SaniOggi "Un'amico (cit.)" mi ha chiesto cosa vuol dire "sani", ma non c'è solo lui che lo chiede; vediamo un po' se riesco a trovare... Google-Fu! <br />Su Wikipedia sembra sparita la pagina, nevermind! Eccola!<br /><blockquote><br /><span style="font-weight:bold;">Sani</span><br />La parola sani è una formula di saluto in dialetto bellunese. È<br />utilizzata principalmente come formula di commiato. L'origine di<br />questa forma di saluto è legata all'augurio di stare bene (rimanere<br />"sani" appunto).<br />L'attore e regista <a href="http://it.wikipedia.org/wiki/Marco_Paolini">Marco Paolini</a> nella sua opera teatrale Bestiario<br />Veneto, ricorda questo augurio in contrapposizione al ciao originario<br />dalla parola s'ciào (o s'ciàvo) in dialetto veneziano: era quindi un<br />modo per non porsi, seppure a livello di cortesia, su di un piano<br />inferiore rispetto alla persona da cui ci si accomiatava.</blockquote><br /><br />Anche se non abito più da qualche anno in terre venete, mi piace<br />"portarmi dietro" questo saluto :)<br /><br />SaniS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-57030641370640637822012-02-14T13:35:00.003+01:002012-02-14T14:10:49.082+01:00Vendita porta a portaOggi racconterò una storia, un po' romanzata.<br /><br />Ora di pranzo.<br />DRIIIN suonano alla porta.<br />E' proprio fastidioso il campanello all'ora di pranzo, ciononostante vado ad aprire.<br />Guardo fuori dallo spioncino e vedo un tipo che si muove nell'atrio e scruta le altre porte del condomino. Apro. Tengo la porta socchiusa e la ostruisco con la mia persona. <br />Venditore: "Salve, scusi il disturbo, sono qui per le bollette del gas ed elettricità"<br />Io: "Eh!"<br />Venditore: "Sa, io non posso entrare, una bolletta di luce e gas, per favore!" - non ricordo se disse per favore, immaginate "tipo HipHop" che ti chiede qualcosa, ganzo fratello! Yo!<br />Io, penso: "Non ti lascio entrare no! Non so nemmeno chi sei!"<br />Io, continuo: "Beh... non c'è l'intestatario della bolletta... sa, è mia moglie!" - questa scusa ha funzionato in passato; è un po' come le frasi del <a href="http://it.wikipedia.org/wiki/Carla_(Monkey_Island)">Maestro di Spada</a>.<br />Venditore: "Nessun problema, se lei è il marito si fa comunque."<br />Io, penso: "Dannazione!"<br />Io, continuo: "Ehm... ma lei chi è?"<br />Venditore: "Sono della XXX, sono qui per bla bla bla... aumenti del gas e luce del governo Monti... lei lo sa, ha sentito al telegiornale?" - La ditta non l'avevo mai sentita, sembrava un nome inventato al momento, tra l'altro borbottato.<br />Io: "Beh sì, ma non posso venire io da voi? Ora sa..." - non avevo voglia di discutere e stavo pensando ad una strategia alternativa per dare commiato.<br />Venditore: "Eh no! Solo ora, allora le bollette?" - ho tagliato un po', è stato abbastanza cortese nel richiedermi le bollette, anche se sempre con tono/modi HipHop.<br />Io: "Mah! Non interessa... Ma.. come non posso venire da voi?"<br />Venditore: "Ma allora pagherà gli aumenti? Lo sa che..."<br />Io: "Eh sì! Rimango così. Salve, buona giornata."<br /><br />Chiudo la porta e il venditore se ne va un po' tra l'offeso e lo sconsolato, forse più offeso, lanciandomi anche una brutta occhiata, pazienza.<br /><br />Truffa? Io mi fido poco di chi viene alla porta, non si presenta (o si presenta male) e mi vuole estorcere gentilmente e ingenuamente dati e magari poi metter anche delle firme.<br /><br />Caro lettore, una volta che hanno i tuoi dati e una firma... anzi, forse la firma non serve più nell'immediato, forse poi, forse.<br />Hai capito come no?<br /><br />SaniS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-55932421936259717482012-01-01T01:00:00.001+01:002012-01-01T01:00:09.569+01:00Propositi per l'anno 2012L'anno scorso è stato un po' troppo travagliato, ma anche quest anno i santi del calendario ricominciano da Gennaio, spero di non finirli subito! :)<br /><br />Scherzi a parte, vediamo cosa porterà quest anno, un po' di mestieri da fare ne ho, mi piace quello che sto facendo e sono pessimista riguardo a questo dannato paese chiamato Italia e per il suo futuro, speriamo bene, abbiamo bisogno di ottimismo... no?<br /><br />Quinidi, come disse il poeta Tonino: "<a href="http://www.youtube.com/watch?v=4dr4JrOPc8E">L'ottimismo vola!</a>"<br /><br />BTW, Buon Anno!S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-27945541548957354892011-12-23T19:05:00.003+01:002011-12-23T19:05:00.205+01:00Buone Feste!<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzb1Y9SjMeyldLbqxnn5aKqQNQKxgx_yq6cVeXjleWuOlQXxGqAo_qucoo-U7_21mxdvCHzhFiVIhtJSoKnIP27LWLMjUbp3P0eGHAseUZF0JNEmG5mb9jx4J_c5_VaNJ0cXVWiTjaQKiP/s1600/lego-404-funny-error-page-illustration.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 216px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzb1Y9SjMeyldLbqxnn5aKqQNQKxgx_yq6cVeXjleWuOlQXxGqAo_qucoo-U7_21mxdvCHzhFiVIhtJSoKnIP27LWLMjUbp3P0eGHAseUZF0JNEmG5mb9jx4J_c5_VaNJ0cXVWiTjaQKiP/s320/lego-404-funny-error-page-illustration.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5689275922715119682" /></a><br /><br />Stacco la spina e ci si vede il prossimo anno!<br /><br />Sani!<br /><br />Immagine da: <a href="http://web-patterns.net/error-pages/lego-404-error-page/">web-patterns.net</a>S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-66947372997407286742011-07-21T19:03:00.006+02:002011-07-21T19:30:47.770+02:00Respawning per tutti!Da <a href="http://en.wikipedia.org/wiki/Spawning_%28video_gaming%29">Wikipedia</a><br /><blockquote><br />In video games, spawning is the live creation of a character or item. <strong>Respawning</strong> is the recreation of an entity after its death or destruction.<br /></blockquote><br /><br />Applichiamo questo "pattern" alla vita reale...<br /><br />Domenica, bella giornata, decidi di fare due passi in città e prender un gelato.<br />Cammini per un'oretta, ti mangi il tuo gelato con soddisfazione, finalmente sei rilassato, nessuno ti rompe, non suona il telefono... <br />Che forza!<br /><br />All'improvviso vien su nuvolo e si mette a gocciolare, pensi che son due gocce, cosa vuoi che sia!<br />Le gocce diventano pioggia equatoriale. <br />Ripensi, questa volta con un po' di vigore: "Dannazione! L'ombrello!"<br /><br />Ti guardi in giro per un posto coperto e... pfffftt (suono onomatopeico), dove prima il tuo occhio vedeva il vuoto ora c'è l'omino con gli ombrellini.<br />Non è possibile! <br /><br />Continui a camminare verso il parcheggio (o la fermata del bus, dipende), un po' a testa bassa e un po' alta per vedere dove andare e... pffftt, altro omino che ti si materializza di fianco per venderti un ombrellino.<br />"Panzesco!"<br /><br />Bene, posso concludere dicendo che:<br /><br /><blockquote><br />In città, quando piove, il <strong>Respawning</strong> è la comparsa dal nulla dell'omino che ti vende gli ombrellini e la sua scomparsa al ritorno del bel tempo.<br /></blockquote><br /><br />Quindi, la prossima volta che vedete in giro un "omino ombrellino", potrete pensare: <br /><br /><blockquote><br />"Ehi! E' stato respawnato dal server! pffftt!"<br /></blockquote><br /><br />Almeno così un sorriso riuscirete a strapparlo! :)<br /><br />Sani!S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-35908151778440938872011-06-11T13:24:00.003+02:002011-06-11T14:57:23.964+02:00RubyDay 2011 - MilanoBene, cosa spinge il sottoscritto, che predica di usare e imparare Python al RubyDay italiano?<br /><br />La risposta è semplice: "la curiosità e la voglia di crescere"<br /><br />Cominciamo allora!<br /><br /><span style="font-weight:bold;">KeyNote - Giovanni Intini</span><br /><br />Ho visto i progressi e il cammino del linguaggio e della community italiana di <a href="http://www.ruby-lang.org/en/">Ruby</a>.<br />Interessante notare che Ruby ha avuto un picco enorme con la creazione di <a href="http://rubyonrails.org/">RoR</a>, per poi stabilizzarsi.<br />Altra cosa positiva è che sembra ci sia movimento e adozione del linguaggio da parte delle aziende, che si rendono conto che i vecchi modelli di business non sono più vantaggiosi.<br />Bello sentire che nella mia regione di nascita ci sia movimento! :-)<br /><br /><span style="font-weight:bold;">Ruby on Rails survaival guide of an aged Java developer - Gian Carlo Pace</span><br /><br />Si può riassumere tutta la presentazione in due parole: resilienza e coesione.<br />Gian Carlo ha spiegato il perché di una scelta coraggiosa, quindi l'utilizzo di Ruby/RoR, per un progetto dove la barca si era ribaltata, da qui il termine resilienza; ma per far accadere tutto questo sono stati affrontati vari problemi.<br />Tra i tanti è che il team di sviluppo aveva conoscenze disomogenee (Java e Coldfusion), che il programmatore Java tende ad arroccarsi alle proprie conoscenze e che imparare un nuovo linguaggio non è banale, ma possibile.<br />Adottata però una metodologia per affrontarli, alla fine, il progetto in ritardo di un mese, è stato consegnato entro i termini e il team di sviluppo era unito e motivato, quindi coeso.<br /><br />Ora sono un gruppo di felici sviluppatori Ruby!<br /><br /><span style="font-weight:bold;">Symfony2 and RoR3 friends for an hour - Alessandro Cinelli, Sandro Paganotti, Alberto Barillà</span><br /><br />Bravi, sono riusciti in un'oretta a mostrare le differenze (molte) e similitudini (poche) tra i due framework.<br /><br />Ero interessato soprattuto da Symfony2, visto che ne sentivo parlare molto, ma sono rimasto deluso.<br />Ho visto la disperazione negli occhi di @madchicken e anche mia, quando abbiamo visto che il datamapper che è molto simile ad Hibernate, con relative annotation e la configurazione delle varie route è fatta via xml/yaml e assomigliano molto a Spring.<br />Il template engine è Twigh, che è il template engine di Django portato su PHP e con @cgabriel ci siamo detti che il vantaggio è che puoi utilizzarlo anche con Django.<br />Delusione, pensavo di trovare una sfida almeno alla pari, ma sia l'architettura che il modo di sviluppare non ci azzeccano.<br />Mi spiace che Alessandro, da sviluppatore PHP/Symfony, abbia detto che PHP non sia poi così buono e che gli sviluppatori PHP vanno insultati.<br />Vero, stanno utilizzando PHP come se fosse Java, e peccato dirlo, non sta uscendo nulla di buono per PHP... forse Yii o Lithium...<br />Apprezzabile che ci sia una community di bravi e diligenti sviluppatori PHP che si poongono a tutta la schiera di scribani e fuffari.<br />RoR3, nulla da dire, l'ho trovato semplice da configurare, poi da utilizzare... dovrei provarlo!<br />Una cosa non mi è piaciutua di Sandro, non so perché è saltato fuori con questa frase, ma dice che Python non ha un unico framework per lo sviluppo web, come lo ha Ruby, quindi c'è frammentazione.<br />Vero, ma a mio avviso, la frammentazione non c'è, la maggior parte dei progetti Python per il web ha una buona community e sono anche documentati!<br />Sinatra, ad esempio, assomiglia a Flask, ma non mi devo portar dietro altri framework, come invece lo è per Ruby, visto che necessita sempre di RoR, dettagli.<br />Qui si potrebbe discutere un sacco, alla fine usare uno o l'altro è questione di gusto e di soluzione veloce per il problema che ho sotto mano.<br />Il "chi ce l'ha più duro" è sempre in agguato!<br /><br /><span style="font-weight:bold;">A metaprogramming Spell Book for Ruby and Rails - Paolo Perrotta</span><br /><br />Complimenti, il buon Paolo mi ha aperto gli occhi sul linguaggio Ruby e tante di quelle magie che ci ha fatto vedere, alla fine sono solo codice Ruby.<br />Il suo libro è da leggere, per me è diventato <a href="http://pragprog.com/titles/ppmetr/metaprogramming-ruby">il libro per imparare Ruby</a>, altri non ce ne sono.<br />Mi spiace che ero in prima fila e ho tentato di distrarlo con una supercazzola, ma era dopo pranzo, mi ero perso un attimo in pensieri e mi mancava un pezzo di discorso <br />;-)<br />D'altra parte l'ho fatto solo in conto della nostra amicizia! :-)<br /><br />Dopo la sua presentazione, Paolo si è messo a far il maestro con carta e penna nell'atrio e a dispensare esempi, fantastico!<br />Poi ho seguito a singhiozzo gli altri interventi, stavo accusando la giornata.<br />Ricapitolo brevemente.<br /><br />"Progettare e sviluppare mobile web..." era già stata presentata al whyMCA, purtroppo però ci si è focalizzati di più su Sencha che su Sinatra. <br />Un po' spenta come presentazione, in ogni caso, bravi Matteo Collina e Daniele Bottillo (non mi ricordo chi c'era dei due) che hanno sviluppato un'applicazione per mobile cross platform e resa disponibile sui vari app store.<br /><br />Mi sono fatto una cultura sul testing con RSpec grazie a Simone Carletti (che va a profilare anche i test!) e su continuous integration/deployment con Sam Reghenzi. <br /><br />Forse sono stato breve e pecco in dettagli, vi consiglio uno sguardo su <a href="http://www.rubyday.it/">http://www.rubyday.it/</a> dove penso saranno caricati i link dei video delle presentazioni e slide.<br /><br />Dimenticavo!<br />A fine giornata c'è stata l'estrazione dei premi e io, dopo aver più o meno risolto l'enigma proposto, all'unanimità di voti, ho vinto una licenza di <a href="http://www.jetbrains.com/ruby/">Ruby Mine</a>!<br /><br />Bello Ruby!<br />Ora non mi resta che iniziare a scrivere!!! :D<br /><br />SaniS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-24275495358701144322011-06-03T12:13:00.004+02:002011-06-03T13:12:33.094+02:00Mockup your app... free of charge!Il titolo in inglese fa sempre un certo effetto... in "italiano-tecnico corrente" poteva essere una cosa del tipo "Mockuppa la tua app'aggratis", che non rende ed è obrobrioso.<br /><br />Sono partito dal seguente link<br /><blockquote><br /><a href="http://speckyboy.com/2010/01/11/10-completely-free-wireframe-and-mockup-applications/">speckyboy.com</a><br /></blockquote><br /><br />... poi, guardando le varie applicazioni proposte, mi sono piacevolmente soffermato sulle seguenti, avendo la possibilità di fare o non fare il login con un account che già possiedo.<br /><br /><span style="font-weight:bold; font-style:italic;">All inclusive</span><br /><br /><span style="font-weight:bold;"><a href="http://pencil.evolus.vn/en-US/Home.aspx">Pencil Project</a></span><br /><br />Bello, molto. Permette di far praticamente tutto quello che mi serve (o vi serve, dipende).<br />Può essere usato come addon per firefox oppure come desktop application.<br /><br />Ho provato la soluzione desktop, ma nella mia ubuntu, dopo aver esploso lo zip, l'eseguibile non parte... ma c'è la soluzione: creare uno script per indicare a xulrunner il file di init (<a href="http://code.google.com/p/evoluspencil/issues/detail?id=194">issue 194</a>)<br /><pre><br />#!/bin/sh<br />xulrunner $(dirname $0)/application.ini<br /></pre><br />Capito come no?!?! ;-) <br /><br /><span style="font-weight:bold;"><a href="http://cacoo.com/">Cacoo</a></span><br /><br />Oltre al nome che mi ha esaltato [1], è un prodotto molto carino. <br />La login può essere effettuata con twitter, facebook, Google o 'Proprietaria'.<br />L'applicazione mette a disposizione 25 fogli da colorare, dove cinque di questi sono già pronti per essere modificati.<br />Prevede una versione a pagamento se si necessitano più fogli, collaboratori ecc ed export in formati differenti (solo png per la free).<br /><br />[1] Si... sono stupidino ;-)<br /><br /><span style="font-weight:bold; font-style:italic;">Mobile</span><br /><br /><a href="http://www.mobjectify.com/">mobjectify</a> in versione beta, ma è molto carino, colorato, 'ajaxoso' e prevede l'export in archivio zip del mockup creato, visibile in anteprima sulla destra.<br /><br /><a href="http://iphonemockup.lkmc.ch/">iphonemockup</a> in versione alpha, carino, just for fun!<br /><br /><span style="font-weight:bold; font-style:italic;">Presentazioni</span><br /><br />L'intramontabile power point, ditemi chi non ha la 'propria copia' installata sul PC, vero che c'è LibreOffice, ma se non ricordo male qualcuno pensa che power point sia gratis... contenti loro...<br /><br />Io apprezzo molto i googledocs, sono online e sono portabili dovunque. Ok... Google ti spia ecc ecc... se facesse i soldi con le mie presentazioni... dovrei esser ricco anche io! :-D<br /><br />Il template che preferisco è quello con la lavagna, con il carattere comic-sans, perché quando si fa una presentazione in qualche modo si insegna qualcosa a chi ti sta ascoltando e devi renderla appetibile e divertente utilizzando, oltre al senso dello humor, anche un font adeguato :-D.<br /><br />SaniS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-84538200784277186312011-05-26T15:11:00.003+02:002011-05-26T15:14:36.137+02:00E' proprio dura la vita...<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMG6uVfF9F8qKla2-KZD-XmEclfdqRlweqs-gt3TkV9moE3XwrxuKeTWEa8HZhumz-vRK9Y_wa9mlsla7V1CAB8w7gi5JfdjvxYsRSwMvFfIxLpbBQ5Jdj_nm0cgAp0RdhL-Qi6yJfc1wW/s1600/2011-05-26+14.03.44.resized.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMG6uVfF9F8qKla2-KZD-XmEclfdqRlweqs-gt3TkV9moE3XwrxuKeTWEa8HZhumz-vRK9Y_wa9mlsla7V1CAB8w7gi5JfdjvxYsRSwMvFfIxLpbBQ5Jdj_nm0cgAp0RdhL-Qi6yJfc1wW/s400/2011-05-26+14.03.44.resized.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5611012034021247234" /></a><br /><br /><br />... per un <span style="font-weight:bold;">gatto</span>!<br /><br />Sani!S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com2tag:blogger.com,1999:blog-5980201556461503762.post-5437102298763779352011-05-19T13:07:00.004+02:002011-05-19T13:18:11.916+02:00Pronto, è la Diocesi?<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv7Dc9hPFzM0bHrBE75DTvBNaW20odA1KAVFW8jGSxYfggf96ldLvsqGqtXTLqjkBGWZhxStEJuYWQwmV9Tk1Zm2d4IbnCfgVyVBaNY1A2tLt536nr1fPPpVrCwQG52S6AkRTlipchEEcc/s1600/Schermata+2011-05-19+a+12.12.24.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 301px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv7Dc9hPFzM0bHrBE75DTvBNaW20odA1KAVFW8jGSxYfggf96ldLvsqGqtXTLqjkBGWZhxStEJuYWQwmV9Tk1Zm2d4IbnCfgVyVBaNY1A2tLt536nr1fPPpVrCwQG52S6AkRTlipchEEcc/s400/Schermata+2011-05-19+a+12.12.24.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5608382568294443410" /></a><br /><blockquote><br /><span style="font-weight:bold;">- "No, Dioukhane!"</span><br /></blockquote><br /><br /><span style="font-style:italic;">Disclaimer</span><br />E lo si fa per ridere... senza offendere nessuno.<br />Se urta, si toglie il post, basta chiedere :)<br /><br />SaniS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com1tag:blogger.com,1999:blog-5980201556461503762.post-57922465158845360922011-03-08T15:46:00.005+01:002011-03-08T15:59:16.712+01:00"Dumb" SMTP serverLo snippet seguente permette di ricevere email e di mostrarle in un terminale; dette email non verranno inviate, ma solamente visualizzate.<br /><br /><pre><br />python -m smtpd -n -c DebuggingServer localhost:1025<br /></pre><br /><br />Ricordo che in un ambiente *nix like, le porte fino alla 1024 sono privilegiate, quindi bisogna 'sudarsele' ;).<br /><br />SaniS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-47107298898590960042011-02-17T14:27:00.003+01:002011-02-17T14:50:30.421+01:00Giocare con Objective-C senza spendere una fortunaStavo pensando all'acquisto di un mac, per avere Xcode e giocare un po' con Objective-C.<br /><br />Poi ho pensato che sarebbe stato il caso di creare una VM, tenuto conto che è illegale e contrario a quanto consesso da Apple; ci sarebbero stati comunque costi di licenza.<br />Inoltre, leggendo i vari post sull'argomento, non è proprio una passeggiata creare una VM con OSX.<br />Tempo da investire: troppo per giocare :).<br /><br />Alla fine la mia ricerca è caduta sul progetto <a href="http://www.gnustep.org/">GNUstep</a> e a costo praticamente nullo, grazie alla licenza del software, ho il compilatore installato sulla mia macchina con Ubuntu. <br />Essendo multipiattaforma, il software si può installare anche su OSX e Windows.<br /><br />Il link seguente è stato il mio punto di partenza: <a href="http://www.techotopia.com/index.php/Objective-C_2.0_Essentials">Objective-C 2.0 Essential</a>.<br />Qui ho trovato i passi per installare il compilatore e per scrivere l'immancabile 'Hello World!'.<br /><br />Happy Coding! Sì o No? :)<br /><br />SaniS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-82672771980474987442011-02-15T16:42:00.004+01:002011-02-15T16:44:47.542+01:00Dilbert ha sempre una marcia in più!<a href="http://dilbert.com/strips/comic/2011-02-15/" title="Dilbert.com"><img src="http://dilbert.com/dyn/str_strip/000000000/00000000/0000000/100000/10000/3000/000/113034/113034.strip.gif" border="0" alt="Dilbert.com" style="width: 450px" /></a>S...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-88523489258102723592011-01-14T09:30:00.000+01:002011-01-14T09:30:00.333+01:00Tips'n'Tricks: Django, autocomplete e virtualenv<span style="font-style:italic;">Appunti di viaggio su virtualenv/virtualenvwrapper e Django</span>.<br /><br />Esportare i settings del progetto in Django<br />Nell'ambiente virtuale creato editare il file postactivate.<br /><pre><br />$ workon virtualenvironment<br />$ cdvirtualenv<br />$ vim bin/postactivate<br /></pre><br /><br />e aggiungere:<br /><pre><br />export DJANGO_SETTINGS_MODULE=virtualenvironment.settings<br /></pre><br /><br />Poi, si potrebbe aggiungere anche l'autocomplete in bash.<br />Scaricare django_bash_completion dal <a href="http://code.djangoproject.com/browser/django/trunk/extras/django_bash_completion">trunk</a>.<br /><br />Mettere il file scaricato all'interno della directory bin dell'ambiente virtualenv e modificare il file postactivate aggiungendo la seguente riga.<br /><pre><br />. django_bash_completion<br /></pre><br /><br />Il punto è un alias di source.<br /><br />HTH,<br />SaniS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0tag:blogger.com,1999:blog-5980201556461503762.post-17212034923649031882011-01-13T14:27:00.000+01:002011-01-13T14:27:00.255+01:00Tips'n'Tricks: python2.4, virtualenv e sqlite<span style="font-style:italic;">Come installare e usare sqlite con python2.4</span>.<br /><br />Supponendo un virtualenvwrapper configurato e una macchina Ubuntu:<br /><pre><br />$ sudo apt-get install libsqlite3-dev<br />$ workon virtualenv<br />$ pip install pysqlite<br /></pre><br /><br />HTH,<br />SaniS...http://www.blogger.com/profile/07729784166495601182noreply@blogger.com0