Plone portal_css Order Matters

My Plone instances run with EEA Faceted Navigation. But they appear differently between debug mode and production mode with my custom theme. For example, after clicking on the Faceted Criteria tab, we should see Faceted Add Buttons that help assigning widgets. The problem is that Faceted Add Buttons do not appear when debug mode is set as off.

With Chrome browser element inspector, we can check CSS details and find where goes wrong. It is collective.js.jqueryui.custom.min.css missing when I run Plone in production mode.

My workaround is go to portal_css in ZMI, and move down collective.js.jqueryui.custom.min.css. The working order is ploneCustom.css, faceted_edit.css, faceted_view.css, and collective.js.jqueryui.custom.min.css.


TAL Expression on Conditional Repeat

TAL (Template Attribute Language) Expressions are used in Zope Page Templates (ZPT) to allow template elements to be replaced, repeated, or omitted. The tal:repeat statement replicates a sub-tree of your document once for each item in a sequence. Here is an example to conditionally repeat and display values based on its value quantity and position.

<div tal:define="choices context/my_field|nothing"
  <tal:onlyone condition="python: len(choices) == 1">
  <tal:field i18n:translate="">Primary</tal:field>:
  <span tal:replace="python: view.term_title(choices[0])" />
  <tal:many condition="python: len(choices) > 1"
            repeat="choice choices">
    <tal:first condition="repeat/choice/start">
    <tal:field i18n:translate="">Primary</tal:field>:
    <span tal:replace="python: view.term_title(choice)" />
    <br />
    <tal:field i18n:translate="">Secondary</tal:field>:
    <tal:others condition="not:repeat/choice/start">
    <span tal:replace="python: view.term_title(choice)" />
    <span class="separator" tal:condition="not: repeat/choice/end">,</span>

Another common usage is to test a variable before inserting it (the first example tests for existence and truth, while the second only tests for existence):

<p tal:condition="request/message | nothing"
   tal:content="request/message">message goes here</p>

<p tal:condition="exists:request/message"
   tal:content="request/message">message goes here</p>


Sprint Like Mad

荷蘭 Arnhem 是 Four Digits 公司的所在地,它們舉辦了十一月 Plone Sprint,為期五天,共 35 人參與。

活動裡,有個 Don't Break The Build 規則,會場的大螢幕持續顯示 CI server 的狀態,如果爛掉了,會把爐主的名字秀出來,然後爐主要請其他人吃蛋糕。一週的 sprint 後,多數人都增加不少肥肉。

活動結束時,還有 Party 和 Award。決定 Sprint Award 的方法,是利用分貝計,看哪個隊伍的歡呼聲最大。

技術上的成果包括: New Theme for Plone 5, New Way to Work with JavaScript: Mockup (widgets), Remove Selected Portal Tools from Plone, Make main_template More HTML5 Friendly,更多記錄在 Day 1, Day 2, Day 3, Day 4, Wrapup


Plone Header I18N

On creating a new Plone instance, you will be asked to set its title and description. If localized strings are used for the title field, they are literally displayed in <head><title>Title Here</title></head>. We can not easily switch the the title strings based on a chosen language.

Maybe plone.app.multilingual will take care of this issue, as a whole multilingual story. Anyway, I try to solve this issue by manipulating viewlets.

My theme is based on Sunburst, that uses main_template.pt as the starting point. plone.htmlhead provider (viewlet manager) is where we need to hack into:

<div tal:replace="structure provider:plone.htmlhead" />

See plone.app.layout/viewlets/configure.zcml and we will find the related viewlet manager and viewlets:

  permission="zope2.View" ...>

  class=".common.TitleViewlet" ...>

Now we know TitleViewlet in plone.app.layout/viewlets/common.py is the target:

class TitleViewlet(ViewletBase):
  index = ViewPageTemplateFile('title.pt')

  def page_title(self):
    Get the page title.

Each page has its site_title set as page_titleportal_title. With a little help from my friends -- zope.i18n.translate:

from zope.i18n import translate

def update(self):
  self.site_title = u"%s &mdash; %s" % (self.page_title,
              default='I18N Site'))

Finally we need my.theme.po in the locales folder:

#: Default: I18N Site
msgid "portal_title"
msgstr "中文名稱"


Event Listing View

event_listing 是 plone.app.events 模組裡定義的 Browser Page,可以被指定成為 Plone Site 或 Folder 的 view method 選項,提供豐富的顯示方式。

event_listing.pt 有定義 mode 變數,預設值是 'future':

tal:define="mode request/mode|string:future;"

如果 @@event_listing 沒有指定 mode 變數值,它會再檢查 _date 變數,最後決定 mode 預設值是 'date' 或 'future'。

if self.mode is None:
    self.mode = self._date and 'day' or 'future'

點選 Past 頁籤時,它會指定 'past' 給 mode 變數,此時 header_string() 會回傳 main_msgid 的翻譯值,其他情況下,還可能搭配 sub_msgid 變數值。

頁籤的連結網址,也配合變數值來產生,例如 mode_past_url 會把 'past' 傳給 _date_nav_url():

def _date_nav_url(self, mode, datestr=''):
    return '%s?mode=%s%s' % (
        datestr and '&date=%s' % datestr or ''

event_listing.pt 經由 view/mode_past_url 來指派網址值:

<a class="mode_past" href=""
  tal:attributes="href view/mode_past_url"


Transmogrifier Revisited

This is detailed sample instruction to Transmogrifier in Action on Plone 4.3.2.

$ cd src
$ ../bin/zopeskel plone crgis.transmogrifier

plone: A project for Plone add-ons

This creates a Plone project (to create a Plone *site*, you probably
want to use the one of the templates for a buildout).

To create a Plone project with a name like 'plone.app.myproject'
(2 dots, a 'nested namespace'), use the 'plone_app' template.

If at any point, you need additional help for a question, you can enter
'?' and press RETURN.

Expert Mode? (What question mode would you like? (easy/expert/all)?) ['easy']:
Version (Version number for project) ['1.0']: 0.1
Description (One-line description of the project) ['']: CRGIS Transmogrifier Package
Register Profile (Should this package register a GS Profile) [False]: True
Creating directory ./crgis.transmogrifier
Replace 0 bytes with 119 bytes (0/0 lines changed; 5 lines added)
Replace 918 bytes with 1074 bytes (0/32 lines changed; 6 lines added)
The project you just created has local commands. These can be used from within
the product.

usage: paster COMMAND

  addcontent  Adds plone content types to your project

For more information: paster help COMMAND

Update configure.zcml as follows:


  <five:registerPackage package="." initialize=".initialize" />

    description="CRGIS Transmogrifier Package Extension Profile"

  <include package="collective.transmogrifier" />
  <include package="collective.transmogrifier" file="meta.zcml" />
    title="CRGIS Importer for Temple Type"
    description="Transmogrifier Pipeline Config to Import Contents."

Update import-temple.cfg then:

pipeline =

blueprint = collective.transmogrifier.sections.csvsource
filename = crgis.transmogrifier:temple-data.csv

blueprint = transmogrify.sqlalchemy
dsn = postgresql://USERNAME:PASSWORD@localhost:5432/DB_NAME
query = SELECT id, title, description FROM TB_NAME

blueprint = collective.transmogrifier.sections.inserter
key = string:_type
value = string:Temple

blueprint = collective.transmogrifier.sections.inserter
key = string:_path
value = string:/myfolder/${item/id}

blueprint = collective.transmogrifier.sections.folders

blueprint = collective.transmogrifier.sections.constructor

blueprint = plone.app.transmogrifier.atschemaupdater

blueprint = collective.transmogrifier.sections.inserter
key = string:_transitions
value = string:publish

blueprint = plone.app.transmogrifier.workflowupdater

blueprint = plone.app.transmogrifier.reindexobject

Note that csvsource section is for CSV source, and sqlsource section is for SQL source.

Add a file crgis/transmogrifier/profiles/default/transmogrifier.txt with these:

# this file contains transmogrifier profile names to run
# on GenericSetup transmogrifier's step

Update setup.py to include SQLAlchemy and psycopg2 dependency.

Finally, edit buildout.cfg:

eggs =

zcml =


Plone5 Is On Its Way

Plone 5 正由核心團隊努力開發,目前看來已達到堪用地步,或許明年初之際,就能正式發佈。

最大的改變,是 Dexterity 成為預設的 Content Type Framework,長期挑大樑的 Archetypes 成為選項模組。這個改變屬於底層調整,對於直接使用 Plone 5 的新專案而言,操作上仍和 Plone 4 差不多。

另一個大改變,是 AJAX 架構導入 mockup 專案,它讓 Plone 與 JavaScript 模組更容易整合和測試。

像 Diazo 技術在 Plone 5 仍在努力站穩腳步,大的方向上,是期待改版的結果,能協助 JavaScript Programmer 和 Theme Designer 更容易在 Plone 專案裡工作。

範例影片: Widget DemoFolder Content Management Demo

測試 Plone 5 的過程,把看到的改版細節資訊記錄下來。舊版 plone.app.imaging 的 imaging_properties 設定值,無法在 Plone 5 出現,因為它跟 Archetypes 相依,必須進行調整,它在 control panel 的 icon 也需要調整

update on testing: https://github.com/plone/Products.CMFPlone/issues/78

$ bin/test -s Products.CMFPlone
Removing stale bytecode file /home/marr/plone5dev/src/Products.CMFPlone/Products/CMFPlone/CalendarTool.pyc
Running Products.CMFPlone.testing.CMFPloneLayer:Functional tests:
  Set up plone.testing.zca.LayerCleanup in 0.000 seconds.

  Ran 28 tests with 0 failures and 0 errors in 32.189 seconds.
Running plone.app.testing.bbb.PloneTestCase:Functional tests:
  Tear down Products.CMFPlone.testing.CMFPloneLayer:Functional in 0.000 seconds.
  Set up plone.app.testing.bbb.PloneTestCaseFixture in 5.792 seconds.
  Ran 70 tests with 2 failures and 0 errors in 0.624 seconds.
Tearing down left over layers:
  Tear down zope.testing.testrunner.layer.UnitTests in 0.000 seconds.
Total: 1061 tests, 4 failures, 0 errors in 9 minutes 22.008 seconds.

跟 Archetypes 有關的模組資訊:



Building Plone Latest

Plone 5 is coming, and calling for contribution. To get a Plone 5 development environment running, see the document for reference first, and run the following commands:

$ git clone -b 5.0  https://github.com/plone/buildout.coredev ./plone50dev
Cloning into 'plone50dev'...
remote: Reusing existing pack: 24795, done.
remote: Counting objects: 32, done.
remote: Compressing objects: 100% (32/32), done.
remote: Total 24827 (delta 19), reused 0 (delta 0)
Receiving objects: 100% (24827/24827), 19.90 MiB | 1.83 MiB/s, done.
Resolving deltas: 100% (16193/16193), done.

$ virtualenv --no-site-packages plone50py
The --no-site-packages flag is deprecated; it is now the default behavior.
New python executable in plone50py/bin/python
Installing distribute.....................done.
Installing pip...............done.

# ref 1 and 2 and 3 if run into pkg_resources.DistributionNotFound or pkg_resources.VersionConflict error
$ rm -rf plone50py/lib/python2.7/site-packages/setuptools*
$ rm -rf plone50py/lib/python2.7/site-packages/distribute*

$ cd plone50dev
$ rm -f bootstrap.py
$ wget http://downloads.buildout.org/2/bootstrap.py

$ ../plone50py/bin/python bootstrap.py
Downloading https://pypi.python.org/packages/source/s/setuptools/setuptools-0.7.2.tar.gz
Extracting in /tmp/tmpAup828
Now working in /tmp/tmpAup828/setuptools-0.7.2
Building a Setuptools egg in /tmp/tmpiv322t
Creating directory '/home/marr/plone50dev/bin'.
Creating directory '/home/marr/plone50dev/parts'.
Creating directory '/home/marr/plone50dev/eggs'.
Creating directory '/home/marr/plone50dev/develop-eggs'.
Generated script '/home/marr/plone50dev/bin/buildout'.

$ bin/buildout
# you will see lots of Getting ... Got ... messages for several minutes.

$ bin/instance fg
$ ls src


Allow Discussion

I want existing Archetypes Document items to work with collective.disqus. There is a field allowDiscussion, set as True, everything done. I find a bound method called allowDiscussion(), but do not figure out how it can help. Then I find an attribute, allow_discussion, exactly for this behavior.

Have no time yet to check if this trick works for Dexterity types.


Setting Geo Data Programmatically

collective.geo.* allows to geo-reference Plone content types and to display this geo data over a map.

>>> from Testing import makerequest
>>> root = makerequest.makerequest(app)
>>> site = root.mysite

>>> admin = root.acl_users.getUserById('admin')
>>> admin = admin.__of__(site.acl_users)

>>> from AccessControl.SecurityManagement import newSecurityManager
>>> newSecurityManager(None, admin)

>>> from zope.site.hooks import setHooks
>>> from zope.site.hooks import setSite
>>> setHooks()
>>> setSite(site)
>>> site.setupCurrentSkin(site.REQUEST)
>>> folder = site['temples']
>>> folder.objectIds()

>>> from collective.geo.geographer.interfaces import IGeoreferenced
>>> geo = IGeoreferenced(folder['63010023-JTG'])
>>> geo.coordinates
(121.52559379690797, 25.023316046141368)
>>> geo.hasCoordinates()

>>> geo.setGeoInterface('Point', (-105.08, 40.59))

Be careful that coordinates are using floats instead of strings, for example you might get data from CSV files.

Check collective.geo.geographer/README.rst for more details.


Tabbed Content Editing

collective.tabr allows for easy editing of Plone "tabbed content" using the jQuery Tools Tabs UI tool.

After successful installation, you should see the add-on listed in Plone Site Setup. Enable the add-on, you should see "Tab" and "Default Tab" from the TinyMCE toolbar menu.

However, you might run into minor issues on final display. First make sure jQuery compatibility fixes are applied. In case you need CSS tweaks, try looking for the "tabs" class name. collective.tabr/browser/tabr.js does almost the hard work, and I append 'style="list-style-type: none; margin-left: 0em"' in <ul class="tabs"> to fix the display.

< jq('<ul class="' + wysiwygTabs.TAB_CONTAINER_CLASS + \
 '"><!-- Dynamically generated tab selectors -->l</ul>');
> jq('<ul class="' + wysiwygTabs.TAB_CONTAINER_CLASS + \
 '" style="list-style-type: none; margin-left: 0em" \
 ><!-- Dynamically generated tab selectors --></ul>');

By using this visual tool, content editors can ease their job. It goes further by utilizing JavaScript in Plone without knowing HTML details.


2013 Summer Outing

第一次 Python 同好的夏季合宿,八月16日到18日,兩天兩夜在宜蘭,包棟的民宿可供 18 人住宿,場地提供 wifi 和簡易投影設備。

感謝老朋友、新朋友的參加,整體而言,活動滿意度自評 85 分以上,我已經開始期待下一次的活動了。


下午到晚間是主要的聊天時段,大家除了交換日常工作和工具使用心得,也討論 Python 活動的未來規劃,可以天馬行空聊到深夜。



View Pattern

View 是新式 Python 網站框架的重要元件,新版的 Plone 使用 View 機制來顯示動態網頁,或是處理表單內容,它可以完整取代舊版的 Skin Layer 機制。

Skin Layer 是顯示動態網頁的傳統機制,它通常透過 Restricted Python 來執行程式邏輯,包括副檔名是 .cpy 的 Controller Script 檔案,再由 Page Template 顯示畫面。但這類 Python Script 並不是一般的 Python 程式,它們只允許執行特定功能,如果存取超過安全範圍的功能,就會出現 Unauthorized: The container has no security assertions 的錯誤。

另一個常見問題是,Skin Layer 的 Script 或 Template 可以在任何 context 裡執行。以 plone_content 的 document_view 為例,通常它該和 Page 搭配,但在 /some-news-item/document_view 的情況下,Zope 仍會試圖執行它,這樣很容易遇到 AttributeError 的錯誤。

當然,也有些 Script 或 Template 屬於通用類型的設計,在多種 context 裡都適合執行,以 plone_forms 裡的 content_status_history 為例,只要內容型別實作 Workflow 功能,就適合搭配它來執行。無論如何,預計在 Plone 5 之際,Skin Layer 將大幅被 View 機制取代。

View 主要由 Python class 和 Page Template 組成,通常還搭配 JavaScript 或 CSS 等資源檔,除了產生 HTML 檔案外,也可以輸出成 JSON、Excel 檔案格式,或是匯出資料到 SQL 資料庫

在 Plone 環境裡,Browser View 是最常見的應用方式,通常也會搭配 Viewlet 或 Layer,設定進階的控制細節。


Plone Quick Upload

想在 Plone 系統裡批次上傳檔案? 暫時可以加裝 Quick UploadUploadify 之類的模組,或是試用 PloneFinder 之類的模組,日後也可能直接在目錄介面就有批次上傳的功能。

以 Quick Upload 模組為例,啟用後,要在想提供批次上傳功能的目錄,新增 Quick Upload Portlet,如果網站根目錄有了 Quick Upload Portlet,就能讓所有目錄都預設繼承這項功能。



Name from Creation Date Behavior

For Archetypes types, we can edit short name for their Add/Edit forms. For Dexterity, we have to create custom behaviors for such tasks. By default, Dexterity provides Title-to-ID behavior. However, CreationDate-to-ID behavior is more valid for my case. With help of @vitaliypodoba, I add NameFromCreationDate behavior in my recent project. To make it working Through The Web, be sure to uncheck the Name from title behavior, then check the Name from Creation Date behavior. Here is a similar implementation that might be of help. Also it is inspiring to learn the title computation and display technique.


MapWarper on Ubuntu

Command list for installing mapwarper on Ubuntu 12.10. This hopefully provides better instruction.

$ sudo apt-get install python-software-properties software-properties-common
$ sudo apt-get install build-essential make
$ sudo apt-get install libxml2-dev libxslt1-dev
$ sudo apt-get install imagemagick git
$ sudo apt-add-repository ppa:ubuntugis/ppa
$ sudo apt-get update
$ sudo apt-get install gdal-bin
$ sudo apt-get install libgdal-ruby
$ sudo apt-get install libmapscript-ruby
$ sudo apt-get install postgresql-9.1-postgis
$ sudo apt-get install ruby1.8
$ sudo apt-get install ruby1.8-dev
$ sudo apt-get install libpq-dev
$ sudo apt-get install libcurl4-openssl-dev
$ sudo apt-get install apache2-threaded-dev

$ wget http://production.cf.rubygems.org/rubygems/rubygems-1.7.2.tgz
$ tar xvpzf rubygems-1.7.2.tgz
$ cd rubygems-1.7.2/
$ sudo ruby setup.rb
$ sudo ln -s /usr/bin/gem1.8 /usr/bin/gem

$ sudo gem install rails -v=2.3.5
$ gem list
# if rake version is not (usually higher), then reinstall rake
$ sudo gem uninstall rake
You have requested to uninstall the gem:
rails-2.3.5 depends on [rake (>= 0.8.3)]
nokogiri-1.5.9 depends on [rake (>= 0.9)]
georuby-2.0.0 depends on [rake (>= 0)]
If you remove this gems, one or more dependencies will not be met.
Continue with Uninstall? [Yn]
Remove executables:
in addition to the gem? [Yn]
Removing rake
Successfully uninstalled rake-10.0.4

$ sudo gem install rake -v=

$ sudo gem install yahoo-geoplanet -v=0.2.1
# previous successful with i18n-0.6.1, later successful with i18n-0.6.4

$ sudo gem install nokogiri -v=1.5.9
$ sudo gem install georuby -v=2.0.0

$ sudo gem install pg -v=0.15.1
Fetching: pg-0.15.1.gem (100%)
Building native extensions.  This could take a while...
Successfully installed pg-0.15.1
1 gem installed
Installing ri documentation for pg-0.15.1...

Invalid output formatter

For help on options, try 'rdoc --help'

ERROR:  While generating documentation for pg-0.15.1
... MESSAGE:   exit
... RDOC args: --ri --op /usr/lib/ruby/gems/1.8/doc/pg-0.15.1/ri
    -f fivefish -t pg: The Ruby Interface to PostgreSQL -m README.rdoc
    lib Contributors.rdoc History.rdoc Manifest.txt README-OS_X.rdoc
    ext/gvl_wrappers.c ext/pg.c ext/pg_connection.c ext/pg_result.c
    --title pg-0.15.1 Documentation --quiet

$ sudo gem install fastercsv -v=1.5.5
$ sudo gem install passenger -v=4.0.3
Fetching: daemon_controller-1.1.4.gem (100%)
Fetching: passenger-4.0.3.gem (100%)
Successfully installed daemon_controller-1.1.4
Successfully installed passenger-4.0.3
2 gems installed

$ sudo gem install oauth -v=0.4.7

$ sudo a2enmod proxy
$ sudo a2enmod proxy_http
$ sudo passenger-install-apache2-module
Welcome to the Phusion Passenger Apache 2 module installer, v4.0.3.

This installer will guide you through the entire installation process.
It shouldn't take more than 3 minutes in total.

Here's what you can expect from the installation process:

 1. The Apache 2 module will be installed for you.
 2. You'll learn how to configure Apache.
 3. You'll learn how to deploy a Ruby on Rails application.

Don't worry if anything goes wrong. This installer will advise you
on how to solve any problems.

The Apache 2 module was successfully installed.

Please edit your Apache configuration file, and add these lines:

   LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/ \
   PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-4.0.3
   PassengerDefaultRuby /usr/bin/ruby1.8

After you restart Apache, you are ready to deploy any number of
Ruby on Rails applications on Apache, without any further
Ruby on Rails-specific configuration!

Deploying a Ruby on Rails application: an example

Suppose you have a Rails application in /somewhere.
Add a virtual host to your Apache configuration file and
set its DocumentRoot to /somewhere/public:

      ServerName www.yourhost.com
      # !!! Be sure to point DocumentRoot to 'public'!
      DocumentRoot /somewhere/public
         # This relaxes Apache security settings.
         AllowOverride all
         # MultiViews must be turned off.
         Options -MultiViews

And that's it! You may also want to check the Users Guide for security
and optimization tips, troubleshooting and other useful information:

  /usr/lib/ruby/gems/1.8/gems/passenger-4.0.3/doc/Users guide Apache.html

$ sudo vi /etc/apache2/mods-available/passenger.load
LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/ \

$ sudo vi /etc/apache2/mods-available/passenger.conf
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-4.0.3
PassengerDefaultRuby /usr/bin/ruby1.8

$ sudo a2enmod passenger

$ sudo vi /etc/apache2/sites-available/warper.mysite.org

    ServerName warper.mysite.org
    RedirectMatch ^/$ http://warper.mysite.org/warper/
    ProxyRequests off
    ProxyPass /warper/ http://localhost:3000/
        ProxyPassReverse /

$ sudo a2ensite warper.mysite.org
$ sudo service apache2 restart

$ wget http://home.gdal.org/fwtools/FWTools-linux-2.0.6.tar.gz
$ tar xvpzf FWTools-linux-2.0.6.tar.gz
$ cd FWTools-2.0.6/
$ ./install.sh
# so we have $HOME/FWTools-2.0.6/bin_safe/ for GDAL_PATH
# that will be used in development.rb or production.rb

$ sudo su - postgres
postgres$ createuser gis (the username running mapwarper)
Shall the new role be a superuser? (y/n) y
postgres$ createdb template_gis
postgres$ createlang plpgsql template_gis
postgres$ psql -f
          /usr/share/postgresql/9.1/contrib/postgis-2.0/postgis.sql template_gis
postgres$ psql -f
postgres$ createdb -T template_gis mysite_db
postgres$ exit

$ cd ~
$ git clone git://github.com/timwaters/mapwarper.git
$ cd mapwarper
$ mkdir public/mapimages
$ mkdir public/mapimages/src
$ mkdir public/mapimages/dst
$ mkdir public/mapimages/dst/png

$ vi config/environments/development.rb
# or production.rb copied from production.example

$ cp config/initializers/session_store.example config/initializers/session_store.rb
$ cp config/database.example config/database.yml
$ vi config/database.yml
  adapter: postgresql
  database: mysite_db
  username: marr
  password: topsecret

$ rake db:migrate
# when user is created, no db, rake db:create can be used;
# however, we need postgis-based db

$ cd; screen
$ cd mapwarper/script
$ ./server
# Ctrl A + D to detach screen


Learning Path

這是十幾年前的事。小湯姆國小剛畢業,暑假空檔找了短期家教,想學怎樣架設 BBS 站。標準的學習內容和步驟大概是這些:首先,把 Linux 裝起來,學點 Shell 指令,再認識基本的 C 語言,從 Hello World 試起,不久,下載 Firebird 或 Maple,照著 README 編譯。

當年的小湯姆,現在已是技術高超的軟體好手。我常想,這些學習內容和步驟,很多部份現在還是適用,它們應該是程式人員學習路徑的一部份,依照成果標的,我們可以列出 skill set,由淺入深安排成教學項目,並整理項目之間的相依關係。

這種概念,應用在各種領域,幼兒學習數位學習應用軟體學習ShowMeDo 也有使用這方法。



Plone Listing Localized Vocabulary

<tal:region condition="item_obj/region"
          tal:repeat="city item_obj/region">
  <span tal:replace="city">Value</span>
  <span class="separator" tal:condition="not:repeat/city/end">,</span>


AskBot Configuration

Check Ubuntu Postgresql Manual first, which needs more care. For example, who and where (listen_addresses) can access the database.

marr@thrust:~$ sudo apt-get install postgresql-9.1 postgresql-server-dev-9.1 postgresql-client-9.1
marr@thrust:~$ sudo -u postgres createuser -D -A -P myuser
Enter password for new role:
Enter it again:
Shall the new role be allowed to create more new roles? (y/n)
marr@thrust:~$ sudo -u postgres createdb -O myuser mydb
marr@thrust:~$ sudo vi /etc/postgresql/9.1/main/pg_hba.conf

marr@thrust:~/$ sugo apt-get install python-virtualenv
marr@thrust:~/$ virtualenv myenv
marr@thrust:~/$ cd myenv
marr@thrust:~/myenv$ source bin/activate
(myenv)marr@thrust:~/myenv$ git clone git://github.com/ASKBOT/askbot-devel.git
(myenv)marr@thrust:~/myenv$ cd askbot-devel
(myenv)marr@thrust:~/myenv/askbot-devel$ python setup.py develop
(myenv)marr@thrust:~/myenv$ pip install psycopg2

$ askbot-setup

Deploying Askbot - Django Q&A forum application
Problems installing? -> please email admin@askbot.org

To CANCEL - hit Ctr-C at any time

Enter directory path (absolute or relative) to deploy
askbot. To choose current directory - enter "."
> /home/marr/askbot

Adding new directories:
/home/marr <-/askbot
Accept? (type yes/no)
> yes
Please do not name your entire Django project 'askbot',
because this name is already used by the askbot app itself

Please select database engine:
1 - for postgresql, 2 - for sqlite, 3 - for mysql, 4 - oracle (type 1/2/3/4)
Please enter database name (required)
Please enter database user (required)
Please enter database password (required)

Copying files:
* __init__.py
* manage.py
* urls.py
* django.wsgi
Creating settings file
settings file created

copying directories:  * doc
* cron
* upfiles

Done. Please find further instructions at http://askbot.org/doc/

$ python manage.py syncdb
WARNING!!! You are using a 'locmem' (local memory) caching backend,
which is OK for a low volume site running on a single-process server.
For a multi-process configuration it is neccessary to have a production
cache system, such as redis or memcached.

With local memory caching and multi-process setup you might intermittently
see outdated content on your site.

Please run command

    python manage.py collectstatic
current transaction is aborted, commands ignored until end of transaction block

Creating tables ...
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_user_permissions
Creating table auth_user_groups
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table django_admin_log
Creating table south_migrationhistory
Creating table livesettings_setting
Creating table livesettings_longsetting
Creating table djkombu_queue
Creating table djkombu_message
Creating table followit_followuser

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no):

$ python manage.py syncdb
$ python manage.py migrate askbot
WARNING!!! You are using a 'locmem' (local memory) caching backend,
which is OK for a low volume site running on a single-process server.
For a multi-process configuration it is neccessary to have a production
cache system, such as redis or memcached.

With local memory caching and multi-process setup you might intermittently
see outdated content on your site.

Please run command

    python manage.py collectstatic

Map Warper Configuration

The challenge is from bringing together old Ubuntu 10.10 and Rails with Geo libraries, especially GDAL, mapscript and mapserver.

update /etc/apt/sources.list source URL to old-releases.ubuntu.com and add deb http://ppa.launchpad.net/ubuntugis/ppa/ubuntu maverick main deb-src http://ppa.launchpad.net/ubuntugis/ppa/ubuntu maverick main

At http://code.mapwarper.net/wiki/DevServerConfig you will see instructions to install postgresql-8.3-postgis, but at http://code.mapwarper.net/wiki/InstallationOne says to install postgresql-8.4

My installation is postgresql-8.4

What is /var/lib/maps for? It is easy to run `sudo chgrp -R maps /var/lib/maps`, but I don't know why `mkdir /var/lib/maps` needed.

for Apache, don't know if Passenger and XSendFile are essential.

for PostGIS, it says postgis user, that I think it is typo for postgres user.

Make sure ruby1.8-dev is installed, or you will run into error "mkmf Not Found".

svnadmin init /var/local/svn --> sudo svnadmin create /var/local/svn

added sderle to group svn. --> sudo usermod -aG svn gis

imported r30 from http://svn2.geothings.net/warper/ to /warper --> not yet and don't know how

For Postgresql 8.4, lwpostgis.sql and spatial_ref_sys.sql files are changing their paths.

psql -f ... lwpostgis.sql --> psql -f /usr/share/postgresql/8.4/contrib/postgis-1.5/postgis.sql template_gis

psql -f ... spatial_ref_sys.sql --> psql -f /usr/share/postgresql/8.4/contrib/postgis-1.5/spatial_ref_sys.sql template_gis

At InstallationOne, it says template_gis, but at InstallationTwo, it says template_postgis.

Refer to Ubuntu Postgresql Manual, createuser sderle --> createuser -D -A -P gis

sudo apt-get install libgdal1-dev --> this helps to solve gdal-config not found issue.

ERROR: permission denied for relation geometry_columns

Diazo: Bridging Designers and Programmers

很高興能在 PyConTW 2013 介紹 Diazo 工具,可惜準備時間不夠,沒辦法把 Diazo 多樣應用的可能性呈現出來,只能先簡介它的機制和概念。我在投影片裡整理的範例,主要是參考 David Bain文件,這也是既有文件中最詳實的內容。

有聽眾問到 Diazo 是否有支援 HTML5,網路上確實有範例,這些進階技巧,期待有機會試出來跟大家分享。


Diazo is a smart approach to theming a website. Diazo does its magic by building on top of XSLT and provides a set of basic rules. Even better is that an easy-to-use in-browser rich editor is coming for designers. Most modern webservers supporting for XSLT transformations also ease the deployment. In this talk, we will learn and demo how Diazo is working.
In general, designers work with static HTML while programmers work on codes and frameworks. Often, they hardly collaborate without bumping into each other.
Diazo eases the process of theming a website, by isolating users from having to understand how developers build websites with frameworks. Diazo does its magic by building on top of XSLT. Raw XSLT is too complex for everyday use, so Diazo provides a simple and user-friendly set of basic rules that get compiled into XSLT behind the scenes. Even better is that an easy-to-use in-browser rich editor is coming for designers to create themes without needing filesystem access or knowledge of Python. Most modern webservers already support for XSLT transformations, so deploying Diazo via WSGI, Ngnix, Varnish or Apache is simple and straightforward.


PyLadies Reviewed

PyLadies 是怎樣的團體呢? 透過學習和互助,像是提供專業能力和職涯成長的活動,它致力協助更多女生成為 Python 社群的一份子。Python 社群本身有個多樣化原則鼓勵各式各樣使用者,依照自己最感興趣、最適合的方式,成為 Python 社群的一份子。

在三月間,PyCon 2013 舉辦義賣活動獲得一萬美金的資助,用來協助更多女生進入 IT 圈,或是參與 open source 活動,初期的想法是贊助女生去參加 DjangoCon。

PyLadies 的成員散佈全球,目前已成立十餘個 chapter,有個 starting kit 說明成立 chapter 的注意事項:

Nashville PyLadies
NYC PyLadies
PyLadies Austin
PyLadies DC
PyLadies Montréal
PyLadies PDX
PyLadies SF
PyLadies Stockholm
PyLadies Vienna

參考 Plone 基金會的範本,PyLadies 也公佈自己的 Code of Conduct 公約,要求社群朋友共同維護平等友善的交流環境

已經舉辦過的活動,包括 hackathon, ladies' night, workshop 等,網路上找得到許多影片記錄,包括 Selena Deckelmann 在 OSDC 的演講

男生可以參加 PyLadies 活動嗎? 這點由活動主辦人決定,常見的方式是以女生優先為主,已參加的女生可帶一個男生到場。如果 PyLadies 活動和 User Group 合辦,就更容易達到性別中立的效果。不管男生是否能夠到場,早點明確宣佈原則,對大家都有好處。


Python For 3D Artists

你對 3D 動畫及程式開發感興趣嗎?CodeAcademy 原本就有許多 Python 課程,現在多了 3D 動畫研究群組,讓學員利用 Python 工具來進行設計創作。

首先,要在 CodeAcademy 完成註冊,或是使用 gmail 之類的帳號登入,沒多久,應該會看到 CodeAcademy 寄信來提示如何進行下一步,並提醒你可以去做習題。

如果你想找 3D 動畫研究群組,要從 Edit Account Settings 的 Settings 點選 Become a Beta Tester 後,再直接到 http://www.codecademy.com/groups/python-for-3d-artists 這個網址。


PyLadies Taiwan Bootstrapping

So many awesome things happen in the PyCon Taiwan 2013. One of my favorites is the discussion to build a PyLadies chapter. On Apr 29, I talk to imacat about Selena Deckelmann's OSDC speech, and ask if anyone is interested to make PyLadies Taiwan real. Finally we decide in the PyCon lightning talk session, announcing a PyLadies BoF, to call for participation. Things go well and there are 10+ ladies sign up for further discussion.

Photos by toomore

There's already a dedicated group for female engineers in Taiwan -- WoFOSS. Surely the PyLadies core team needs to figure out their vision and goals. With confidence, I see the picture becoming clear.

The following is the quote from the initial email:

對於 PyLadies,我至少有兩個初衷,一是女生朋友在資訊領域,本來就該有一半的發言權或影響力,二是 Python 能有效促成前面命題的落實。 軟體資訊包含了數理、心理、藝術等不同領域面向,理應適合女生朋友投入發展,但不平衡的現況,代表有些社會因素,壓抑了這個發展。 Python 鼓勵 diversity,拿掉不必要的門檻,是個值得長期投入的培力工具和環境。
我是男生,只會協助起個頭,不會限制 PyLadies 在台灣的發展方式,但,總期待有人願意來主導 PyLadies 的成長。


Quotes of The Day

  • 一杯清水因滴入一滴污水而變污濁,一杯污水卻不會因一滴清水的存在而變清澈。
  • 這世上有三樣東西是別人搶不走的:一是吃進胃裡的食物,二是藏在心中的夢想,三是讀進大腦的書。
  • 馬在鬆軟的土地上易失蹄,人在甜言蜜語中易摔跤。
  • 世界沒有悲劇和喜劇之分,如果你能從悲劇中走出來,那就是喜劇,如果你沉緬於喜劇之中,那它就是悲劇。
  • 如果不讀書,行萬里路也不過是個郵差。
  • 當你的鄰居在深夜兩點彈鋼琴時你別氣惱,你可以在四點鐘時叫醒他,並告訴他你很欣賞他的演奏。
  • 如果你只是等待,發生的事情只會是你變老了。
  • 真正的朋友不是在一起有聊不完的話,而是即使不說一句話也不覺得尷尬。
  • 時間是治療心靈創傷的大師,但絕不是解決問題的高手。
  • 寧願做過了後悔,也不要錯過了後悔。


World Plone Day 2013

World Plone Day 2013 在四月24日舉行,台北場地點在中研院人社中心。今年參加的朋友,有半數是好奇 Python 的初學者,由此可見 Python 得到越多越多的關注。

在 2000 年之際,為了找尋 open source 版本的 WebDAV 實作,我發現了 Zope 系統,因為它是用 Python 寫成,讓我踏上 Python 學習之路。回顧那段歷史,有兩個故事值得一提:

Python 在 2000 年的發展時期裡,Zope 社群和公司扮演了重要的角色,公司創辦人 Jim Fulton 和 Paul Everitt 在 1994 就參加過最早的 Python workshop,並出力促成 Python Software Foundation。

Greg Stein 利用 Python 開發商業軟體,改善 CGI forking 的效能問題,促成 Microsoft 在 1996 就"用"了 Python

Plone 最早只是 Zope 平台上的應用程式,在 2003 之際,成為當時廣受注目的 CMS 軟體。從產品的角度來看,Plone 算是相當成熟的軟體系統,如果預設的功能符合需要,直接使用,幾乎不需要懂 Python。對我而言,除了在日常工作使用它之外,最大的樂趣,是把它當作學習 Python Web Technology 的遊樂場,開發網站過程該注意到的許多議題,Plone 系統大抵都能具體而微地展示出來。

對 Python 感興趣的朋友,趕快購買 PyCon Taiwan 2013 門票哦,早鳥票限時且限量,錯過就可惜了。


PyCon Taiwan 2013 the Prank and the Truth

Happy April Fools' Day! Though it's quite late now.

很可惜地,Guido, Larry, Yukihiro 今年真的不會同時在台灣 Python 年會出現,PyCon Taiwan 2013 四月1日的那篇文章,真的只是給四月1日用的。

希望沒有人因為這個玩笑,想讓我去過明年的清明節 ^^|||

話說回來,今年的 PyCon Taiwan 真的夠猛,豪華的主題演講,豐富的兩天三軌議程,連串的閃電秀,良葛格的先修課程被秒殺,還有台灣微軟帶來強力支援,天啊,太夢幻了,但,這些都是真的!









日治時期,以舊城扼守左營海港為由,強制遷走城內居民,例如昔日北門內街兩側都是大戶人家,後來國民政府拆除舊舍,改成眷村。可參考李仙得 (Charles Le Gendre) 的舊照片


PyCon2013 Young Coder

PyCon US 2013 有個 The Young Coder: Let's Learn Python 教學課程,學員對象預設是年滿十二歲的青少年,從學習 Python 入門知識開始,最後是利用 Raspberry PiPyGame 來撰寫遊戲,並贈送 Python For KidsHello World! Computer Programming for Kids and Other Beginners 書籍。

參加 PyCon US 的會眾,可以帶小孩去參加教學課程,但這可不是托兒服務。實際參加的三十五位學員分成兩天,第一天的年齡大概是十歲到十二歲,第二天的年齡大約是十三到十六歲,有些學員的家長就是軟體工程師,有些則完全不知道什麼是程式設計。

講師是 Katie CunninghamBarbara Shaurette,現場還搭配近十位助教,助教要盡量盯著學員的螢幕,成為講師的耳目,讓講師能專注在內容解說,同時也能掌握學員的狀況。



Online Map Rectifying

New York Public Library Map Warper 提供地圖校正的線上服務,它將館藏的地圖,開放給使用者進行對應校正,成果就能搭配 Open Street Map 來顯示。

程式碼主體是 Ruby on Rails,在 Ubuntu 12.04 環境下,啟動前要安裝 cgi-mapserver,順利的話,連帶把 libgdal 裝好,想用 MySQL 的話,就執行 sudo apt-get install mysql-server mysql-common mysql-client libmysqlclient-dev。還有 curl 和 git,以及 libmagickcore-dev libmagickwand-dev。

身為 Rails 菜鳥,最簡單的安裝方式,當然還是 apt-get install ruby-rails,但這樣裝的版本會很舊,提示建議要先裝 nodejs (套件名稱不是 node 要小心) 和 RVM (Ruby Version Manager),在安裝 RVM 前,先確認 Ubuntu 已裝好下列套件:

$ sudo apt-get install build-essential libssl-dev libpcre3-dev libncurses5-dev libreadline6-dev。

執行 curl -L https://get.rvm.io | bash -s head --autolibs=3 --ruby 後,留意裝的 ruby 版本號碼,例如 2.0.0-p0 之類,如果不是自己想要的版本,就要再想法子更新。

按照訊息提示,執行 source /home/marr/.rvm/scripts/rvm 就可以使用了,終於可以 gem install rails 啦。

執行了 nypl-warper/script/server 後,出現訊息:

Missing the Rails 2.3.5 gem. Please `gem install -v=2.3.5 rails`,
 update your RAILS_GEM_VERSION setting in config/environment.rb
 for the Rails version you do have installed,
 or comment out RAILS_GEM_VERSION to use the latest version installed.

此處的 `gem install -v=2.3.5 rails` 對我而言,像是繞路的陷阱,執行到 Fetching: rails-2.3.5.gem 時,遇到:

rails's executable "rails" conflicts with railties
Overwrite the executable? [yN]

選 N 的話,會結束安裝:

ERROR:  Error installing rails:
        "rails" from rails conflicts with installed executable from railties


  rubygems/core_ext/kernel_require.rb:45:in `require':
  cannot load such file -- iconv (LoadError)

為了把干擾降到最低,決定把 Ubuntu 原本裝的 ruby 相關套件都 apt-get purge 移除,刪掉 $HOME/.rvm 重裝 ruby 1.9.3 rails 2.3.5。

Rails 2.3.5 application starting on
in `to_specs': Could not find oauth (>= 0.3.5) amongst 
[actionmailer-2.3.5, actionpack-2.3.5, activerecord-2.3.5, activeresource-2.3.5,
 activesupport-2.3.5, bundler-1.3.4, rack-1.0.1, rails-2.3.5, rake-10.0.4,
 rubygems-bundler-1.1.1, rvm-] (Gem::LoadError)

再 gem install oauth

Fetching: oauth-0.4.7.gem (100%)
Successfully installed oauth-0.4.7
1 gem installed
Installing ri documentation for oauth-0.4.7...
Installing RDoc documentation for oauth-0.4.7...

遇到 in `require': cannot load such file -- geo_ruby (LoadError) 使用 gem install geo_ruby 說「沒有 geo_ruby」,改用 gem install georuby 成功,遇到 in `require': cannot load such file -- pg (LoadError) 使用 apt-get install postgresql postgresql-contrib libpq-dev 和 gem install pg 成功。

接著是 invalid multibyte char (US-ASCII) (SyntaxError) 錯誤,在檔案前面加:

#!/bin/env ruby
# encoding: utf-8

至此,總算 ./server 跑起來了,新的訊息是:

The bundled mysql.rb driver has been removed from Rails 2.2.
Please install the mysql gem and try again: gem install mysql.
Status: 500 Internal Server Error
cannot load such file -- mysql

補了 sudo apt-get install libmysqlclient-dev 再 gem install mysql 應該是搞定了。

修改 config/database.yml 後,執行 rake db:migrate 遇到:

ERROR: 'rake/rdoctask' is obsolete and no longer supported.
Use 'rdoc/task' instead.

先修改 Rakefile 把 rake/rdoctask 換成 rdoc/task

再補 sudo apt-get install libgdal1-dev 雖然可以處理 gdal-config 找不到的問題,但 gem install gdal 還是出現 libgdal not found 問題。

遇到 Can not load gdal/gdal 改成 gdal 可過關。



Open Source Economy

Open Source Economy
image from: http://www.dance-tech.net/profiles/blogs/1462368:BlogPost:20665



推薦這個影片 (via http://www.facebook.com/dongpo.deng/posts/545777462133601) --
The Future of the Open Source Economy by Paul Ramsey at FOSS4G 2009

簡報檔在 http://blog.cleverelephant.ca/2009/10/foss4g-2009-keynote.html

Paul Ramsey 以「商場競爭」和「生態演化」進行比擬,說明軟體演化的過程,競爭的是開發者的注意力,沒人用的軟體,進入滅絕狀態,沒人維護的軟體,則是走向衰危之路。進一步地看,軟體安全性也是軟體品質演化的一部份,越多人測試更新的軟體,就越有機會改善安全性。

剛好,前陣子施振榮先生在「談王道與共創共生」提到 Linux,他認為 Linux 雖然參與者眾,但對消費者的價值無法體現,因為沒有標準,參與者無利可圖,造成創新和持續的力量不足。他認為,在 Google Android 創造價值生態後,這現象有所改善了。

有趣的是,二十年前,Microsoft 對開發者的影響力算是相當大,現在競爭可多了,十年前,將 open source 視為威脅、病毒,抵抗那麼久之後,Microsoft 默默地接受和 open source 和解的事實。那麼,十年後又會是怎樣的光景呢? 且讓我們繼續看下去。


Python Beginner Resources

今天參加的聚會,討論到初學 Python 的建議和學習資源。

有中文的教學文件嗎? google 會有線索,不過,新的資源通常還是英文內容較多。除了靜態的文件外,推薦參加線上群組或實體聚會,分享交流的效果通常比自己獨自學習來得更好。這些群組都是講中文的:Google+ CommunityFacebook GroupGoogle GroupPyHUGTaipei.py

最傳統的語法文件是 http://docs.python.org/2.7/tutorial/index.html,如果啃來覺得乏味,可以考慮 a byte of pythonDive Into PythonLearn Python The Hard Way

影片式的教學資源,也越來越多。例子包括:ShowMeDohttp://learnerstv.com/Free-Computer-Science-Video-lectures-ltv163-Page1.htmhttp://www.udacity.com/http://codeacademy.com/Coursera.orgGoogle Python Class。也有人在維護文件列表

著重程式概念建立的遊戲式網站有:PythonChallengeCheckIO,利用圖解強化學習效果的 Online Python Tutor

少不了的工具是 cheatsheet 文件:http://overapi.com/python/。等到想要進階時,可以參考 The Hitchhiker's Guide to Python

Android 環境的資源:http://python-for-android.readthedocs.org/http://kivy.org/#home

Windows Azuer 環境的資源:Tutorial for Python Web Sites with Django


Set UID for Dexterity Type

When using collective.disqus in Plone, Disqus API by default looks for UID to identify the posts (comments). For the case to manually migrate Archetypes items, I need to set UID property for Dexterity items. Here is how it works:

$ bin/plonectl debug

>>> from plone.uuid.interfaces import IUUID
>>> IUUID(app.mysite.myfolder['a-sample-item'])
>>> from plone.uuid.interfaces import ATTRIBUTE_NAME
>>> setattr(app.mysite.myfolder['a-sample-item'], ATTRIBUTE_NAME, 'bc8a2fac032e4ae39c700730ac79df8f')
>>> IUUID(app.mysite.myfolder['a-sample-item'])
>>> import transaction
>>> transaction.commit()

Of course, transmogrifer would be more decent way for such case.


Why PyCon Taiwan

"First learn computer science and all the theory. Next develop a programming style. Then forget all that and just hack." -- George Carrette




為了自己,還有下一代,我們真心期待,台灣的軟體產業能轉型,技術能茁壯,這份企盼,我們把它落實為 PyCon Taiwan,也就是說,Python 年會不只是個程式語言的同好會,它就該是轉型的促進器,技術交流的平台。

Python 語法,即使兩天沒學完,兩週的時間也一定足夠,但我們知道,語法的重要性,是不如心法的,獨自學習的收獲,遠不及交流切磋的豐富。我定位 PyCon 是欣賞 (認同?) Python Zen 的同好聚會,基於這樣的出發點,即使是 Java、Perl、Ruby、PHP 的朋友,也都是我們的目標族群,因為,追求編程之道,大家都走在這路上。

今年活動規模以超過 600 人為目標,邀請國外講者的過程,感受外國友人主動貢獻的熱忱。相信,關心軟體發展的朋友那麼多,今年的舞台那麼大,每位朋友的挺身貢獻,肯定能為台灣產業的蛻變,帶來一份力量,而上台分享則是最強有力的支持,現在就行動吧!


歷史角落 總有餘音迴蕩

1999 年的 Open Source Workshop 是早期的社群專屬聚會,那時候,FreeBSD 有黑皮書,Linux 有 CLE。

2000 年的 dotcom 熱潮,上沖下洗,讓一群人看花了眼,多少也體會社群穩健發展才是長久之計。那麼,現在又如何呢?

「台灣沒有社群,只有鄉民」,即使有人不認同這樣的描述,但,我們身處怎樣的位置? 又迎向何方?

我們的初心呢? 十年後,怎樣看待自己,別人又怎樣看待我們?


Price Competition

什麼都比低價 國家就完了》的回應摘要。

  • All great companies are great first and foremost because of great products and that's because great technical people with also good appreciation on design and marketing are in the helm. Now, a casual look at the companies led by pure MBA types you get a list of corporate disasters.
  • 保持低價位並不是錯,但是,如果一個國家所有品牌,一家公司所有產品,在市場中的定位都是以低價競爭策略取勝,那這就有很大的問題。
  • 商業的本質就是在競爭中創造利潤。競爭 - 最差方法是削價競爭,最好方法是創造新產品脫離削價競爭的行列。那麼台灣對創新有何實質鼓勵? 台灣寧可每年付出兩千億的外國專利購買成本,也不願承擔創新的風險。這才是走下坡的主因!
  • 業務行銷固然重要,但產品的創新與品質才是科技公司的命脈。技術人員領導不是壞事,重點是技術人員必須要有行銷思惟,才能創造出符合市場所需的產品。
  • 有國際化競爭力的人才,八成以上都不在台灣了,剩下的兩成也早被台灣的環境給耗損掉。很多人會說台灣人才很不錯,都能在國際發光,但那是他們到國外後,靠著國外的產業人才鏈才能發光發熱。抱歉,台灣除了科技代工外,沒有其他的產業人才鏈。
  • 跟亞洲公司開會的經驗:
    香港--最國際化 懂得西方文化 英文好且懂得用英文開玩笑
    中國 日本--每間公司都聘請專業翻譯團 每個細節都會跟你確認沒聽錯
    台灣--態度最好 但大都英文不太好 不知為何不請翻譯 很多細節都必須用email再確認
  • 我是醫療服務業者,在醫院你會發現一件事很奇怪,大家寧願花2萬多元買一台蘋果,卻不願花2萬元動一個手術或買效果較好的藥物,患者還會問:我有繳健保費怎麼這麼貴,接著拿出哀鳳和哀配...也許醫院也應該從寶僑請行銷人員...
  • 這核心價值,根本就是在真實的我們自己,台灣人做了七十幾年代工,產品都是站在別人的角度來想,甚至活的洋腔洋調,但別忘了,再怎麼洋腔洋調,也應不了真的洋槍洋炮。人云:「錢買不到愛情與靈魂」靈魂與愛情是無價的,保有我們自己靈魂的原貌,形塑出來的文化,是不是還有可以給普世的美好,我想這會是相當高價的。
  • 台灣企業缺乏競爭力,原因很多,其中之一是大多數台灣老闆的心態問題,這些老闆幾乎都是將員工當作成本看待,所以想盡辦法壓榨員工(降低成本)。如果台灣老闆能夠將員工視為非固定資產,則願意主動創造好的工作環境,員工有幸福感,潛能被激發,自然有競爭力,最後達到員工與公司一起成長、雙贏的目的。


Utility to List Plone Instances

When you have multiple Plone instances running on multiple Linux boxes, you will need utilities for instance management. Here is a Python-based tool, rt.zps. It's easy to install:

$ sudo apt-get install python-psutil
$ sudo easy_install rt.zps

As its name indicates, of course you can use it to inspect Zope processes.

$ zps
CWD:      /home/user/plone1
User:     user
PID:      1234
Conf:     /home/user/plone1/parts/instance/etc/zope.conf
Address:  8081
Memory:   1.96%

CWD:      /home/user/plone2
User:     user
PID:      12345
Conf:     /home/user/plone2/parts/instance/etc/zope.conf
Address:  8082
Memory:   1.96%

You can check if any instance running for a specific port.

$ zps --port 8080


Newline to BR in Description Field

Usually we want newlines in the description field be interpreted as <br /> for Plone contents. Here is a qucik trick:

< templateId='kss_generic_macros', macro='description-field-view');"
> templateId='kss_generic_macros', macro='description-field-view');
> pps modules/Products.PythonScripts.standard"
< tal:replace="context/Description">
> tal:replace="structure python:pps.newline_to_br(pps.html_quote(context.Description()))">


Disqus Service Integration

Disqus 是一個留言服務系統,目前全球市佔率在前三名內。在 2012 年之際,版本昇級後稱為 Disqus 2012,介面和 API 有了較大的調整,增加 Community 和 Discovery 的功能

想在 Plone 裡整合這項服務,最簡單的方式是透過 collective.disqus 模組。安裝後的設定步驟,有下列要點:

先要勾選 Activate Disqus as system coment 來啟用,填寫 API key 資料。

在 Site Setup 的 Discussion 設定項目裡,勾選 Globally enable comments 來啟用留言功能。

再到 Site Setup 的 Type 設定項目,個別依照 Content Type 指定 Allow comments。

有遇到 JavaScript 變數未被嵌入的問題,造成畫面只出現 blog comments powered by Disqus 的字樣,下載 github 上的最新程式碼就解決了。


Update Plone TinyMCE

舊版 TinyMCE 編輯器和 IE 9 有相容問題,至少要昇級到 Products.TinyMCE 1.3 之後的版本,以 Plone 4.2.1 為例,它的 versions.cfg 原本的內容是:

Products.TinyMCE = 1.2.13


Products.TinyMCE = 1.3b4

重跑 buildout 後,額外會安裝的模組包括:


測試上述方式時,對新建的 Plone Site 沒問題,不過,把舊系統昇級的結果,有遇到編輯器顯示不正常的問題,猜想是 GenericSetup profile 沒有完整啟用所造成,沒時間追下去便作罷。

或者,直接改用 Plone 4.3 以上的版本,內建的 TinyMCE 就是 1.3 之後的版本。


Mapping Contributors

mr.cabot 是個工具軟體,它會讀取 GitHub、gmane、StackOverflow 的資料,試圖把專案貢獻人員的地理位置找出來,最後在地圖上標示。

主要設定檔是 mr.cabot.cfg,輸出格式預設是 Google Static Map,也可以使用 HTML 或 KML。