Expat-IT Tech Bits




Search this site:


/ (289)
  Admin/ (123)
    Apache/ (10)
      HTTPS-SSL/ (4)
      PHP/ (3)
      performance/ (2)
    Cherokee/ (1)
    LAN/ (4)
    LVM/ (6)
    Monitoring/ (2)
      munin/ (2)
    SSH/ (6)
    SSL/ (1)
    Samba/ (1)
    VPN-options/ (7)
      OpenVPN/ (1)
      SSH-Proxy/ (3)
      Tinc/ (1)
      sshuttle/ (1)
    backups/ (17)
      SpiderOak/ (1)
      backuppc/ (5)
      dirvish/ (1)
      misc/ (6)
      rdiff-backup/ (1)
      rsync/ (1)
      unison/ (2)
    commandLine/ (24)
      files/ (8)
      misc/ (10)
      network/ (6)
    crontab/ (1)
    databases/ (15)
      MSSQL/ (2)
      MySQL/ (8)
      Oracle/ (3)
      PostgreSQL/ (1)
    dynamicDNS/ (2)
    email/ (11)
      Dovecot/ (1)
      deliverability/ (1)
      misc/ (1)
      postfix/ (7)
      puppet/ (1)
    iptables/ (3)
    tripwire/ (1)
    virtualization/ (9)
      VMware/ (1)
      virtualBox/ (8)
  Coding/ (14)
    bash/ (1)
    gdb/ (1)
    git/ (3)
    php/ (5)
    python/ (4)
      Django/ (2)
  Education/ (1)
  Hosting/ (27)
    Amazon/ (18)
      EBS/ (3)
      EC2/ (10)
      S3/ (1)
      commandline/ (4)
    Godaddy/ (2)
    NearlyFreeSpeech/ (3)
    Rackspace/ (1)
    vpslink/ (3)
  Linux/ (31)
    Android/ (1)
    Awesome/ (3)
    CPUfreq/ (1)
    China/ (2)
    Debian/ (8)
      APT/ (3)
      WPA/ (1)
    audio/ (1)
    encryption/ (3)
    fonts/ (1)
    misc/ (6)
    remoteDesktop/ (1)
    router-bridge/ (3)
  SW/ (45)
    Micro$soft/ (1)
    browser/ (2)
      Chrome/ (1)
      Firefox/ (1)
    business/ (28)
      Drupal/ (9)
      KnowledgeTree/ (6)
      Redmine/ (2)
      SugarCRM/ (7)
      WebERP/ (2)
      WordPress/ (1)
      eGroupware/ (1)
    chat/ (1)
    email/ (1)
    fileSharing/ (2)
      btsync/ (1)
      mldonkey/ (1)
    graphics/ (2)
    research/ (2)
    website/ (6)
      blog/ (6)
        blosxom/ (3)
        rss2email/ (1)
        webgen/ (1)
  Security/ (15)
    IMchat/ (2)
    circumvention/ (2)
    cryptoCurrency/ (1)
    e-mail/ (4)
    greatFirewall/ (1)
    hacking/ (1)
    password/ (1)
    privacy/ (2)
    skype/ (1)
  Services/ (1)
    fileSharing/ (1)
  TechWriting/ (1)
  xHW/ (14)
    Lenovo/ (1)
    Motorola_A1200/ (2)
    Thinkpad_600e/ (1)
    Thinkpad_a21m/ (3)
    Thinkpad_i1300/ (1)
    Thinkpad_x24/ (1)
    USB_audio/ (1)
    scanner/ (1)
    wirelessCards/ (2)
  xLife/ (17)
    China/ (9)
      Beijing/ (5)
        OpenSource/ (3)
    Expatriation/ (1)
    Vietnam/ (7)


  • 2019/06
  • 2016/07
  • 2016/05
  • 2016/02
  • 2016/01
  • 2015/12
  • 2015/11
  • 2015/06
  • 2015/01
  • 2014/12
  • 2014/11
  • 2014/10
  • 2014/09
  • 2014/07
  • 2014/04
  • 2014/02
  • 2014/01
  • 2013/12
  • 2013/10
  • 2013/08
  • 2013/07
  • 2013/06
  • 2013/05
  • 2013/04
  • 2013/02
  • 2013/01
  • 2012/12
  • 2012/10
  • 2012/09
  • 2012/08
  • 2012/07
  • 2012/06
  • 2012/05
  • 2012/04
  • 2012/03
  • 2012/01
  • 2011/12
  • 2011/11
  • 2011/10
  • 2011/09
  • 2011/08
  • 2011/07
  • 2011/06
  • 2011/05
  • 2011/04
  • 2011/02
  • 2010/12
  • 2010/11
  • 2010/10
  • 2010/09
  • 2010/08
  • 2010/07
  • 2010/06
  • 2010/05
  • 2010/04
  • 2010/03
  • 2010/02
  • 2010/01
  • 2009/12
  • 2009/11
  • 2009/10
  • 2009/09
  • 2009/08
  • 2009/07
  • 2009/06
  • 2009/05
  • 2009/04
  • 2009/03
  • 2009/02
  • 2009/01
  • 2008/12
  • 2008/11
  • 2008/10
  • 2008/09
  • Subscribe XML RSS Feed

    Creative Commons License
    This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

    This site has no ads. To help with hosting, crypto donations are accepted:
    Bitcoin: 1JErV8ga9UY7wE8Bbf1KYsA5bkdh8n1Bxc
    Zcash: zcLYqtXYFEWHFtEfM6wg5eCV8frxWtZYkT8WyxvevzNC6SBgmqPS3tkg6nBarmzRzWYAurgs4ThkpkD5QgiSwxqoB7xrCxs

    Wed, 27 Jul 2016

    /SW/graphics: Fixing Simple Photo Issues at the Command Line

    (Without having to startup a huge program like gimp or photoshop.)

    These utilities are also drawn from the ImageMagick[1] graphics suite. Imagemagick is available for all of Linux, Windows, and the Mac environment[2]. Some examples:

    I have not yet found an Imagemagick manual that has the gift of making difficult tasks seem easy. Here[3][4][5] are some suggestions for manuals.

    [1] http://www.imagemagick.org/script/index.php
    [2] http://www.imagemagick.org/script/binary-releases.php
    [3] http://www.imagemagick.org/script/command-line-tools.php
    [4] http://linux.about.com/library/cmd/blcmdl1_ImageMagick.htm
    [5] http://www.imagemagick.org/Usage/

    posted at: 03:59 | path: /SW/graphics | permanent link to this entry

    Sun, 07 Feb 2016

    /SW/business/WordPress: Drupal 6 to WordPress 4 Migration

    With many thanks to this[1] post for doing most of the work. Note that I have a simpler situation with only one user and no URL aliases.

    Prepare your freshly install WordPress 4.4 database by truncating default posts / pages / comments after installation.

    TRUNCATE TABLE wordpress.wp_comments;
    TRUNCATE TABLE wordpress.wp_links;
    TRUNCATE TABLE wordpress.wp_postmeta;
    TRUNCATE TABLE wordpress.wp_posts;
    TRUNCATE TABLE wordpress.wp_term_relationships;
    TRUNCATE TABLE wordpress.wp_term_taxonomy;
    TRUNCATE TABLE wordpress.wp_terms;

    Migrate tags:

    INSERT INTO wordpress.wp_terms (term_id, name, slug, term_group) SELECT d.tid, d.name, REPLACE(LOWER(d.name), ' ', '-'), 0 FROM drupal.term_data d INNER JOIN drupal.term_hierarchy h USING(tid);
    INSERT INTO wordpress.wp_term_taxonomy (term_id, taxonomy, description, parent) SELECT d.tid `term_id`, 'category' `taxonomy`, d.description `description`, h.parent `parent` FROM drupal.term_data d INNER JOIN drupal.term_hierarchy h USING(tid);

    Copy over Drupal posts to your WordPress database.

    INSERT INTO wordpress.wp_posts (id, post_author, post_date, post_content, post_title, post_excerpt, post_modified, post_type, post_status, to_ping, pinged, post_content_filtered) SELECT DISTINCT n.nid `id`, n.uid `post_author`, FROM_UNIXTIME(n.created) `post_date`, r.body `post_content`, n.title `post_title`, r.teaser `post_excerpt`, FROM_UNIXTIME(n.changed) `post_modified`, n.type `post_type`, IF(n.status = 1, 'publish', 'private') `post_status`, '', '', '' FROM drupal.node n, drupal.node_revisions r WHERE n.vid = r.vid;
    UPDATE wordpress.wp_posts SET post_type = 'post' WHERE post_type <> 'page' OR post_type <> 'post';

    Update post to tag / category relationship:

    INSERT INTO wordpress.wp_term_relationships (object_id, term_taxonomy_id) SELECT nid, tid FROM drupal.term_node;

    Update tags / category post count:

    UPDATE wordpress.wp_term_taxonomy tt SET `count` = (SELECT COUNT(tr.object_id) FROM wordpress.wp_term_relationships tr WHERE tr.term_taxonomy_id = tt.term_taxonomy_id);

    The following code is supposed to help fix taxonomy:

    UPDATE IGNORE wordpress.wp_term_relationships, wordpress.wp_term_taxonomy SET wordpress.wp_term_relationships.term_taxonomy_id = wordpress.wp_term_taxonomy.term_taxonomy_id WHERE wordpress.wp_term_relationships.term_taxonomy_id = wordpress.wp_term_taxonomy.term_id;

    Insert comments to posts:

    INSERT INTO wordpress.wp_comments (comment_post_ID, comment_date, comment_content, comment_parent, comment_author, comment_author_email, comment_author_url, comment_approved) SELECT DISTINCT nid, FROM_UNIXTIME(timestamp), comment, thread, name, mail, homepage, ((status + 1) % 2) FROM drupal.comments;

    Update post comments count:

    UPDATE wordpress.wp_posts SET `comment_count` = (SELECT COUNT(`comment_post_id`) FROM wordpress.wp_comments WHERE wordpress.wp_posts.`id` = wordpress.wp_comments.`comment_post_id`);

    You can avoid this step if you omit copying the teaser / post_excerpt post field. Or, after the fact:

    UPDATE wp_posts SET post_excerpt = NULL WHERE post_excerpt is not null;

    My tag category links did not display out of the box, and this fixed that:

    In backend --> Settings --> Permalinks set a custom value ("topics" for instance) for category base.

    And finally, the comments that I imported are not displaying properly yet. At this point I do not care enough to try to fix it, so caveat emptor.

    [1] http://www.jamediasolutions.com/blog/migrating-drupal-to-wordpress.html

    posted at: 03:49 | path: /SW/business/WordPress | permanent link to this entry

    Mon, 02 Dec 2013

    /SW/Micro$soft: Windows Sucks

    So I last made daily use of a Microsoft operating system on my desktop around about '00. It was that pig Win98, which drove me right into the arms of Linux, and I have never looked back since. (And no, Macs do not even tempt me. OSX might have some really shiny apps, but as an OS it is inferior to Linux, IMO.)

    Fast forward to '13, and most or all of the damn banks in China insist on the use of Internet Explorer for their online banking. (Biting my tongue....) For various reasons, I am having to do this more and more, so thought it might be nice (and more secure) to be doing so on a legal, UP-TO-DATE, Win-something-or-other.

    I managed to get a real cheap (legal, licensed, unopened packaging) copy of Win7 off of Taobao. Installed it in a virtual machine under Linux, typed in the serial number and had it accepted. And Windows Update did not work. Dies with some kind of (standard for Microsoft) completely useless and unintelligible error message. Probably has something to do with my accidentally clicking through the license code screen, and then adding the code after the fact.

    And then I poured the rest of my afternoon down the drain, doing the Windows dance: tried a dozen different things, including an attempt to upgrade the same install from the same DVD image that failed (at the very end!) miserably. Finally I had to scrub the whole thing and start from scratch, being careful to give Microsoft it's little code at exactly the appointed time, and no other.

    Ten years later, Windows still sucks.

    posted at: 06:16 | path: /SW/Micro$soft | permanent link to this entry

    Thu, 18 Jul 2013

    /SW/business/Drupal: Drupal: How to Delete Users Without Content

    I run a community Drupal 6 site that allows anyone to register, and my MySQL dumps were starting to get pretty big. I just reduced the number of users from 105,121 to 98 by deleting all users who had contributed no content or comments. There seems to be no easy way to do this, so here is my way. It is a little complicated:

    mysql> select users.mail, node.title from users, node where users.uid=node.uid;

    will list all users with content, ie. a Drupal "node".

    mysql> select * from users where users.mail not in (select users.mail from users, node where users.uid=node.uid)

    will list all users WITHOUT content.

    mysql> select users.mail, comments.subject from users, comments where users.uid=comments.uid;

    will list all users who have made a comment, and....

    mysql> select * from users where users.mail not in (select users.mail from users, comments where users.uid=comments.uid);

    will list all users who have never made a comment. Now this

    mysql> select * from users where (users.mail not in (select users.mail from users, comments where users.uid=comments.uid)) and (users.mail not in (select users.mail from users, node where users.uid=node.uid));

    will display all users who have neither content nor comments, which would lead one to expect that this

    mysql> delete from users where (users.mail not in (select users.mail from users, comments where users.uid=comments.uid)) and (users.mail not in (select users.mail from users, node where users.uid=node.uid));

    would work. But no,

    ERROR 1093 (HY000): You can't specify target table 'users' for update in FROM clause

    Stupid, but true. Damn MySQL. So now we have to play rocket scientist to get it done, and create a temporary table of users we want to delete:

    mysql> CREATE TEMPORARY TABLE t select mail from users where (users.mail not in (select users.mail from users, comments where users.uid=comments.uid)) and (users.mail not in (select users.mail from users, node where users.uid=node.uid));

    And now finally delete the damn SPAMers (which would be the vast majority of this garbage):

    mysql> delete users from users join t on t.mail = users.mail;

    posted at: 02:31 | path: /SW/business/Drupal | permanent link to this entry

    Thu, 11 Jul 2013

    /SW/fileSharing/btsync: BitTorrent Sync

    Your own personal "dropbox". The puppet configuration below is for my personal convenience in deploying to multiple machines. BitTorrent Sync[1] is really easy to install and use without Puppet. On each machine you want to sync, just put the btsync in some convenient subdirectory, start it from within that directory, point your browser to http://localhost:8888/, and there tell it which directory to sync and what the shared "secret" is for that directory, and it should then just work for machines on the same network. Without further ado, here is my Puppet module:

    class btsync ($syncdir) {
        # BitTorrent Sync: setup of multiple nodes
        # Note that because btsync is not yet packaged for Debian/Ubuntu, I am using
        # the sync directory to distribute new versions of btsync to the nodes. However,
        # this means the initial installation must be "primed" for a new installation:
        # place the btsync executable required on the new node in the sync directory, named
        # as "btsync_", ie. btsync_amd64 / btsync_i386 / btsync_x86_64 for most Linux people.
        # Note that this configures all nodes with the same basic settings, but 
        # WITHOUT shares. You must login to the webUI at http://VPN-IP:8888/
        # and manually specify shares for each machine with this configuration.
        # This line
        #       "listen" : "<%= ipaddress_zentuxnet %>:8888"
        # in btsync.conf.erb is where I am setting the webUI listen restriction.
        # Replace with "" to allow connections from anywhere.
        # btsync --generate-secret
        $btuser = 'btuser'
        $installdir = '/usr/local/btsync'
        user { $btuser:
            ensure => present,
        file { "$installdir":
            ensure => directory,
            mode   => 740,
            owner  => $btuser,
            group  => $btuser,
            recurse => true,
            before => Exec['copybt'],
        file { "$syncdir":
            ensure => directory,
            mode   => 640,
            owner  => $btuser,
            group  => $btuser,
            recurse => true,
        # verify the latest version of btsync is installed (contained in the sync dir)
        exec { copybt:
            command => "cp $syncdir/btsync_$architecture $installdir/btsync",
            path   => "/usr/bin:/usr/sbin:/bin",
            unless => "diff $syncdir/btsync_$architecture $installdir/btsync >/dev/null",
            require => File["$syncdir"],
            notify => File["$installdir/btsync"],
        file { "$installdir/btsync":
            ensure => file,
            mode   => 740,
            owner  => $btuser,
            group  => $btuser,
        # configuration file for basic settings. Note that template is inserting
        # machine-specific values for:
        # * hostname
        # * webUI listen IP address (set to my VPN IP)
        file { "$installdir/sync.conf":
            ensure => file,
            mode   => 640,
            owner  => $btuser,
            group  => $btuser,
            require => File["$syncdir"],
            notify  => Service["supervisor"],
            content => template("btsync/sync.conf.erb"),
        # supervisord because no init.d script. And keeps the thing running if it falls down.
        # Restart fails without the custom "restart" and the sleep period.
        package { 'supervisor': }
        service { 'supervisor':
            ensure     => running,
            restart    => "/etc/init.d/supervisor stop && sleep 3 && /etc/init.d/supervisor start",
            subscribe  => File['/etc/supervisor/conf.d/btsync.conf'],
            require => Package["supervisor"],
        file { "/etc/supervisor/conf.d/btsync.conf":
            ensure => file,
            mode   => 640,
            owner  => root ,
            group  => root,
            require => Package["supervisor"],
            content => template("btsync/btsync.conf.erb")

    Two file templates are referenced, and can be downloaded from here:

    [1] http://labs.bittorrent.com/experiments/sync.html

    posted at: 03:18 | path: /SW/fileSharing/btsync | permanent link to this entry

    Sun, 07 Apr 2013

    /SW/business/SugarCRM: SugarCRM's "Silent Upgrade"

    Lately SugarCRM's up-until-recently rock-solid upgrade process has become flaky, and I have had to turn to the "silent upgrade" tool to get the job done. I have not yet stumbled across official documentation, but this[1] does the trick for me.

    The first step is to get the upgrade zip, for example SugarCE-Upgrade-6.5.x-to-6.5.12.zip, onto the server. Then just run something like this:

    php -f /home/sugartest/public_html/modules/UpgradeWizard/silentUpgrade.php /home/clayton/SugarCE-Upgrade-6.5.x-to-6.5.12.zip /tmp/sugarUpgrade.log /home/sugartest/public_html/ admin

    where most of the parameters should be fairly self-evident: the last is the account name you login to SugarCRM with, the second last is the path to the SugarCRM installation you are upgrading.

    Then you probably have to correct the permissions, as you probably ran the above as root:

    chown -R www-data:sugarcrm public_html/

    And finally login to SugarCRM and click through the menus to do the following:

    Admin --> Repair --> Rebuild Relationships

    [1] http://www.hostknox.com/tutorials/sugarcrm/silent-upgrade

    posted at: 04:01 | path: /SW/business/SugarCRM | permanent link to this entry

    Fri, 30 Mar 2012

    /SW/chat: An Unofficial but Working QQ Plugin for Pidgin

    The official Pidgin QQ support disappeared[1] quite some time ago after it stopped working. However, there is a Chinese project[2] on Google Code that is currently delivering a working Ubuntu deb package. On my Debian testing machine, to /etc/apt/sources.list, per [3] I added

    deb http://ppa.launchpad.net/lainme/libqq/ubuntu precise main


    apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 7C24E5AB949045F5

    to avoid key complaints in the install, and then:

    apt-get update
    apt-get install libqq-pidgin

    followed by a Pidgin restart, and QQ appears as an account option. All I needed to authenticate were my QQ userid and password, it just worked, and so far no sign of those annoying captchas!

    Lord, am I glad to get rid of those official, closed-source QQ clients! Running that stuff, even WebQQ, on my personal machine gave me a SEVERE case of the creeps. Mind you, it must be noted that packages pulled from PPA are unofficial, but they are 100% Open Source with the code available for all to see, and I am seeing at least five people declared as working on the project. A worthy project for someone with free time....

    [1] http://developer.pidgin.im/ticket/13193
    [2] https://code.google.com/p/libqq-pidgin/
    [3] https://code.google.com/p/libqq-pidgin/wiki/UbuntuUsers

    posted at: 21:54 | path: /SW/chat | permanent link to this entry

    Tue, 25 Oct 2011

    /SW/business/Drupal: Drupal Migrate Module Basics

    The Drupal migrate module[1] is an impressive tool for migrating databases from other web applications (or anywhere, really) into the Drupal database. It even has fairly impressive documentation[2], but not unlike a lot of other big chunks of documentation, it can be hard to extract from the documentation where to start in creating a simple functional example of the migrate module at work. Hopefully this example will help to fill that gap a little.

    First install and enable the migrate family of modules in a sandbox Drupal site:

    drush dl migrate migrate_example migrate_extras migrate_ui
    drush en migrate migrate_example migrate_extras migrate_ui

    If you then point your browser at:


    you will see the migrate module's UI, which shows a couple of example migrations ("beer" and "wine") already coded and setup for you by the migrate_example sub-module. You can play with importing and rolling back data with the UI, or with drush:

    drush help --filter="migrate"

    To create your own migration, you need to create a custom module containing the migrate code. Using a MySQL database from another application, and based upon the beer.inc example from migrate_example, I was able to get a working migrate setup with three fairly small files in a new sub-module called "migrate_test" in sites/all/modules/migrate/migrate_test/ :


    <?php /* * You must implement hook_migrate_api(), setting the API level to 2, for * your migration classes to be recognized by the Migrate module. */ function migrate_test_migrate_api() { $api = array( 'api' => 2, ); return $api; }


    name = "Migrate Test" description = "My migration data." package = "Development" core = 6.x php = 5.2 dependencies[] = taxonomy dependencies[] = imagefield dependencies[] = comment dependencies[] = migrate dependencies[] = content dependencies[] = date dependencies[] = migrate_extras files[] = migrate_test.module files[] = langex.inc ; Information added by drupal.org packaging script on 2011-09-18 version = "6.x-2.2" core = "6.x" project = "migrate" datestamp = "1316388105"


    <?php // This is the connection information for the database containing the source data. Database::addConnectionInfo('for_migration', 'default', array( 'driver' => 'mysql', 'database' => 'langex', 'username' => 'langex', 'password' => 'anypass', 'host' => 'localhost', 'prefix' => '', )); /** * To define a migration process from a set of source data to a particular * kind of Drupal object (for example, a specific node type), you define * a class derived from Migration. You must define a constructor to initialize * your migration object. By default, your class name will be the "machine name" * of the migration, by which you refer to it. Note that the machine name is * case-sensitive. * * In any serious migration project, you will find there are some options * which are common to the individual migrations you're implementing. You can * define an abstract intermediate class derived from Migration, then derive your * individual migrations from that, to share settings, utility functions, etc. */ abstract class LangexMigration extends Migration { public function __construct() { // Always call the parent constructor first for basic setup parent::__construct(); // With migrate_ui enabled, migration pages will indicate people involved in // the particular migration, with their role and contact info. We default the // list in the shared class; it can be overridden for specific migrations. $this->team = array( new MigrateTeamMember('John Doe', 'john.doe@gmail.com', t('contractor')), new MigrateTeamMember('Larry Brewer', 'lbrewer@example.com', t('Implementor')), ); } } /** * There are four essential components to set up in your constructor: * $this->source - An instance of a class derived from MigrateSource, this * will feed data to the migration. * $this->destination - An instance of a class derived from MigrateDestination, * this will receive data that originated from the source and has been mapped * by the Migration class, and create Drupal objects. * $this->map - An instance of a class derived from MigrateMap, this will keep * track of which source items have been imported and what destination objects * they map to. * Mappings - Use $this->addFieldMapping to tell the Migration class what source * fields correspond to what destination fields, and additional information * associated with the mappings. */ class LangexUserMigration extends LangexMigration { public function __construct() { // The basic setup is similar to BeerTermMigraiton parent::__construct(); $this->description = t('Language Exchange Network users'); $this->map = new MigrateSQLMap($this->machineName, array('userid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Account ID.' ) ), MigrateDestinationUser::getKeySchema() ); $query = Database::getConnection('default', 'for_migration') ->select('users', 'u') ->fields('u', array('userid', 'name', 'username', 'password', 'email_address', 'sex', 'signup_date')); // $this->source = new MigrateSourceSQL($query); $this->source = new MigrateSourceSQL($query, array(), NULL, array('map_joinable' => FALSE)); $this->destination = new MigrateDestinationUser(); // One good way to organize your mappings is in three groups - mapped fields, // unmapped source fields, and unmapped destination fields // Mapped fields // The migrate module automatically converts date/time strings to UNIX timestamps. $this->addFieldMapping('created', 'signup_date'); $this->addFieldMapping('pass', 'password'); $this->addFieldMapping('mail', 'email_address'); $this->addFieldMapping('name', 'username'); // Unmapped source fields $this->addFieldMapping(NULL, 'name') ->issueGroup(t('DNM')); $this->addFieldMapping(NULL, 'sex') ->issueGroup(t('DNM')); // Unmapped destination fields // This is a shortcut you can use to mark several destination fields as DNM // at once $this->addUnmigratedDestinations(array('theme', 'signature', 'access', 'login', 'timezone', 'language', 'picture')); } }

    Note that this is a "cross-database migration"[3]. The source data and the destination data are located on the same MySQL server, but in different databases.

    [1] https://drupal.org/project/migrate
    [2] https://drupal.org/node/415260
    [3] https://drupal.org/node/1014558

    posted at: 05:13 | path: /SW/business/Drupal | permanent link to this entry

    Sun, 18 Jul 2010

    /SW/business/Drupal: Youku & Tudou Videos in Drupal

    For websites targeting users in mainland China, one of the issues is that many common services like Youtube and Google Video are blocked / censored from within China. For this specific case of video, there are a number of similar local Chinese video services that can be used instead.

    Most ex-China video services seem to make it easy to embed their videos in other sites by prominently displaying a button which will generate the javascript code necessary for embedding a video in another site. For whatever reason, the Chinese sites do not seem to be so helpful.

    First of all, in Drupal, turn on the PHP module. Then select "Create Content" and some content type to get to the content creation page. Select "PHP code" in the "Input Format" sub-section. And finally, for a youku[1] video, paste the following code into the content area:

    <embed src="http://player.youku.com/player.php/sid/XNDg5MTMwMDQ=/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"></embed>

    This is the video generated by the above:

    Youku video links are of the form http://v.youku.com/v_show/id_XMTkwNDgzMjE2.html

    Note the part between the "id_" and the ".html", ie. XMTkwNDgzMjE2. This is the part of the link that must be swapped into the above code for XNDg5MTMwMDQ in order to make it work for a different video.

    Similarly, for tudou[2] videos, use this code:

    <iframe title="Video from TUDOU" style="WIDTH: 364px; HEIGHT: 320px" src="http://www.gmodules.com/ig/ifr?url=http://hosting.gmodules.com/ig/gadgets/file/108621208120033273647/ flash_container.xml&amp;up_File=http://www.tudou.com/v/rsOg3YPXjDg&amp;up_FlashWidth=364&amp;up_FlashHeight=320&amp;up_ContainerCol=%23ffffff" frameborder="0" scrolling="no">Use a Flash Player to play Video from TUDOU - http://sites.google.com/site/annuairevin/flash-reader</iframe>

    which produces this video:

    Tudou video links are of the form http://www.tudou.com/programs/view/eD1xQ0WTlI8/

    Swap "eD1xQ0WTlI8" in the latter link for "rsOg3YPXjDg" in the code above to make the code work for a different video.

    [1] http://www.youku.com/
    [2] http://www.tudou.com/

    posted at: 03:02 | path: /SW/business/Drupal | permanent link to this entry

    Sun, 30 May 2010

    /SW/business/Redmine: Installing Redmine on Debian Linux

    I have found Redmine to be extremely sensitive to the Ruby environment, often requiring that librairies be of exactly a certain version (not older, not newer). Configuration documentation is not sufficiently detailed. And error and diagnostic information is extremely difficult to obtain in a typical hosting account.

    So if you are trying to install Redmine in a hosting account that supports Ruby on Rails, you would be well-advised to get the application running first in a controlled environment where you have root. In my case, that was my Debian Linux desktop. After flailing around for hours in the hosting account, everything simply fell into place when I went back to basics and installed the Redmine application locally.

    These[1][2] were the main references for getting this working on Debian.

    apt-get install ruby rake rubygems libmysql-ruby
    gem install rails -v=2.3.5 (takes quite a while!)
    gem install rake -v=0.8.3
    gem install hoe -v=1.3.0
    Checkout a fresh copy of the latest Redmine stable, currently:
    svn co svn://rubyforge.org/var/svn/redmine/branches/0.9-stable redmine-0.9
    Start the native Ruby web server and see what happens:
    cd [...]/redmine-0.9
    ruby script/server production
    At this point I got a complaint about a missing database.yml. In my case, I was actually migrating Redmine from one hosting account where it suddenly broke, to another hosting account. So I installed the MySQL database from the old account to a database called mentage_redmine, then created a config/database.yml as follows:
      adapter: mysql
      database: mentage_redmine
      host: localhost
      username: mentage_redmine
      password: ***********
      encoding: utf8
      adapter: mysql
      database: mentage_redmine
      host: localhost
      username: mentage_redmine
      password: ***********
      encoding: utf8
    Restart the server: this time an "Internal Server Error" that gave very specific instructions about adding a line pertaining to cookies to the config/environment.rb file. After adding this line, it basically worked.

    In my particular case, again because I was migrating an existing application, in the new site I replaced the public/images, javascripts, stylesheets, and themes directories with those from the old site's public directory. After that, everything looked right as well.

    [1] http://www.redmine.org/wiki/1/RedmineInstall
    [2] http://www.redmine.org/wiki/1/HowTo_Install_Redmine_in_a_home_directory_on_Debian

    posted at: 07:30 | path: /SW/business/Redmine | permanent link to this entry

    Sat, 29 May 2010

    /SW/business/Redmine: Installing Redmine in a Hostgator Hosting Account

    To their credit, Hostgator[1] actually provides some documentation[2] about getting Ruby applications working in their hosting account. I, however, found them to be inadequate, and debugging information availability was little to none, so for me the magic key was getting Redmine working first on my desktop, then migrating to the Hostgator hosting account.

    One of the first things one notices when looking at the rather sparse Redmine installation manual[3] is the need for specific versions of a number of Ruby librairies. This is what I found:
    My Debian DesktopHostgator Account
    rails (2.3.5)rails (2.3.8)
    rack (1.0.1)rack (1.1.0)
    rake (0.8.3)rake (0.8.7)
    hoe (1.3.0)hoe (2.6.0)

    In the Hostgator account, I got the above librairy versions using "gem list --local". I then installed in the account the correct versions as follows:

    gem install rails -v=2.3.5
    gem install hoe -v=1.3.0

    Now transfer Redmine from desktop to Hostgator, placing it in /home/mentage/redmine-0.9.

    In /home/mentage/public_html, create the following symlink: redmine -> /home/mentage/redmine-0.9/public/

    Hostgator is using Apache to server up Ruby applications. Create a public/.htaccess[2] file with the following contents:

    AddHandler fcgid-script .fcgi 
         AddHandler cgi-script .cgi 
         Options +FollowSymLinks +ExecCGI 
         RewriteEngine On 
         RewriteCond %{REQUEST_URI} ^/notrails.* 
         RewriteRule .* - [L] 
         RewriteRule ^$ index.html [QSA] 
         RewriteRule ^([^.]+)$ $1.html [QSA]     
         RewriteCond %{REQUEST_FILENAME} !-f 
         RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]

    After that, it worked for me by pointing a browser at the redmine directory.

    [1] http://www.hostgator.com/
    [2] http://forums.hostgator.com/ruby-rails-support-t13038p8.html
    [3] http://www.redmine.org/wiki/1/RedmineInstall

    posted at: 09:08 | path: /SW/business/Redmine | permanent link to this entry

    Sun, 10 Jan 2010

    /SW/business/Drupal: My Favorite Drupal Modules

    (As of Drupal version 6.x....)

    Drupal is a very mature piece of software, with a vast number of modules to choose from, often with multiple modules vying to provide the same piece of functionality. After some trial and error, here are my candidates for "best of", modules someone new to Drupal should look into early:

    First some easily overlooked core modules:

    Third-Party modules:

    Here is someone else's list of favorites[6].

    [1] http://drupal.org/project/cck
    [2] http://drupal.org/project/views
    [3] http://drupal.org/project/image
    [4] http://drupal.org/project/image_fupload
    [5] http://drupal.org/project/lightbox2
    [6] http://www.nicklewis.org/40-essential-drupal-6-modules
    [7] http://drupal.org/project/boost

    posted at: 22:40 | path: /SW/business/Drupal | permanent link to this entry

    Thu, 17 Dec 2009

    /SW/business/Drupal: Comparisons of Drupal and Joomla

    Back some time ago when I was trying to figure out which Content Management System to use for a couple of website development clients, I do not remember seeing any definitive reviews. In the end, I think I made the correct choice (Drupal) for the situation despite the limited amount of information, but I see now that there might be some situations (event calendaring? desire for a simpler admin interface?) where Joomla might be the right choice.

    Here are some references I would like to preserve for posterity:


    posted at: 08:16 | path: /SW/business/Drupal | permanent link to this entry

    Sun, 06 Dec 2009

    /SW/business/Drupal: Drupal User Manual: How to Edit Content

    This post aims to provide the basic knowledge required to begin editing Drupal content.

    First and most basically, you require an account on the Drupal website you wish to edit. After login, if you click on any menu item to navigate to that page, if you have the privileges to edit that page, you will see an edit (编辑) button or link (this depends on the theme being used) at the top of the page. Click on edit / 编辑, then edit and save the page.

    After you have logged in, if you have been given some admin privileges on the site, you will see an Admin (管理) link in your personal menu under "My account" (我的帐户). Another way to see and edit the pages on the site is to click on "My account" / 我的帐户, and then click on "Content management/Content" (内容管理/内容). You will then be presented with a list of all the content items on the site, which you may then choose to edit individually, or perform various bulk operations on (deleted large quantities of spam posts, for instance).

    To create new content, click on "Create content" (创建内容) and select a content type. For ordinary website page content, you probably want to choose "Page" content. After you click on "Page" and write your content, do not forget to expand the "Menu settings" (菜单设置) and enter a "Menu link title" (菜单链接名称) and select the menu position from the "Parent item" (上级菜单项) dropdown list. (You probably want to select "Primary Links" or one of the items under "Primary Links".)

    Finally, you will probably want to re-arrange the order of the "Primary Links" in the navigation menu at the top of the site. To do this, click on "Admin" --> "Site building/Menus" --> "Primary links" (管理 --> 站点构建/菜单 --> "Primary links"). To change the order or position of menu items, just grab the "+" with your mouse pointer and drag'n'drop. For dropdown menus it is also good practice to click the "Expanded" (展开) checkbox to enable submenus. And finally, click "Save Configuration".

    posted at: 23:17 | path: /SW/business/Drupal | permanent link to this entry

    Wed, 14 Oct 2009

    /SW/business/SugarCRM: SugarCRM Built-in Data Tranfer Tool is Highly Developed

    SugarCRM is fundamentally a big, complicated address book, and any migration to SugarCRM can often reasonably include a wish to import a bunch of contact data from another application. In my case, I have a MySQL database.

    To get this database into SugarCRM is basically a two-step process:

    This all works quite well as of SugarCRM version 5.5. 5.2 does not work so well: e-mail addresses do not import as they *all* trigger a syntax error, Account/Contact association is lost, etc. If you are doing a substantial data import I recommend you go right for the not-yet-stable version 5.5. It is a release candidate so it will be the new stable very soon.

    posted at: 01:31 | path: /SW/business/SugarCRM | permanent link to this entry