How to write multiple language code snippets in MkDocs

MkDocs is using markdown to generate documents on static web pages.

Recently, I was working on writing documents for a iOS project. In iOS, I would need to document 2 programming languages: Objective-C & Swift. If I write them in two separate code snippets, that would be very unreadable. So to improve the readability, I decided to put them together by using HTML Tabs.

We will need to use custom configuration to let MkDocs generate those HTML syntax with the javascript and CSS.

In mkdocs.yaml, specify the js and CSS files used for the tabs.

extra_css:
    - styles/tab.css
extra_javascript:
    - custom/tab.js

Javascript: when clicks the tab, it will hide others tab contents.

function openCode(codeName, elmnt, color) {
// Hide all elements with class="tabcontent" by default */
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}

// Remove the background color of all tablinks/buttons
tablinks = document.getElementsByClassName("tablink");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].style.backgroundColor = "";
tablinks[i].style.color = "black";
}

// Show the specific tabs content
var elements = document.getElementsByClassName(codeName);
for (i = 0; i< elements.length; i++) {
elements[i].style.display = "block";
}

// Add the specific color to the button used to open the tab content
elements = document.getElementsByClassName(elmnt.className);
for (i = 0; i< elements.length; i++) {
elements[i].style.backgroundColor = color;
elements[i].style.color = "white";
}
}

// Get the element with id="defaultOpen" and click on it
if(document.getElementsByClassName("objbutton") !== null){
var elements = document.getElementsByClassName("objbutton");
for (i = 0; i< elements.length; i++) {
elements[i].click();
}
}

CSS: for Tab styling

/* Style the tab buttons */
.tablink {
    color: black;
    float: left;
    border: none;
    outline: none;
    cursor: pointer;
    padding: 12px;
    font-size: 12px;
    width: 100px;
}

/* Change background color of buttons on hover */
.tablink:hover {
    background-color: #777;
}


/* Set default styles for tab content */
.tabcontent {
    color: black;
    display: none;
}

/* Style each tab content individually */ 
#Obj {background-color:white;}
#Swift {background-color:white;}

Then finally in markdown file, we can easily create a multi-language code snippet.

<button class="tablink objbutton" onclick="openCode('obj', this, '#03a9f4')" markdown="1">Objective-C</button> 
<button class="tablink swiftbutton" onclick="openCode('swift', this, '#03a9f4')" markdown="1">Swift</button> 

 

<div class="obj tabcontent"> 
```objectivec 
Your objective-c code goes here.
``` 
</div>

 

<div class="swift tabcontent"> 
```swift 
Your swift code goes here.
``` 
</div>

 

In HTML tags, the markdown="1" tells MkDocs do not parse its content so it will be generated as normal HTML syntax.

Here it is how it looks like.

Advertisements

How to create iOS fat dynamic framework

“Fat” means that this framework has many slices. Each slice (machine code) is built for certain architecture. The fat framework we are going to build contains i386 x86_64 armv7 armv7s arm64.

  • armv7 is for iPhone 4s
  • armv7s is for iPhone 5
  • arm64 is for iPhone 6

Firstly we need to create a target for dynamic framework: Cocoa Touch Framework

Secondly we create a new target: External Build System

Go to Build Phases -> Run script

Paste the below code snippet in there

 

#!/bin/sh
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 1. Build Device and Simulator versions
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 5. Convenience step to copy the framework to desktop directory
ditto "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${HOME}/Desktop/${PROJECT_NAME}.framework"

Build it then your fat dynamic framework will be located on your desktop! Before submitting the App to AppStore, you must strip off the simulator slice (i386 x86_64) from the framework

lipo -remove i386 Name.framework/Name -output Path/name

lipo -remove x86_64 Name.framework/Name -output Path/name

Or you can refer to this solution:

http://ikennd.ac/blog/2015/02/stripping-unwanted-architectures-from-dynamic-libraries-in-xcode/

 

Logitech G213 Prodigy Keyboard

My first mechanical keyboard was CM Storm QuickFire TK. I likes its CHERRY MX RED Switches. Unfortunately, it did not come along with me to Australia. I had to use MacBook’s keyboard for 9 months. Finally, G213 caught my eyes with its shiny LED lights, and very fair price.

G213 supports OS X, its multimedia buttons are functional, including playing iTunes music, lower/raise the volume.

Though, it is not a mechanical keyboard, its keys actually provides a similar feeling as using cherry red switches. Nonetheless, the sound of clicking is not so clear and sharp as cherry red switches.

Its RGB lights are bright, and the keyboard can support multiple colors in 4 zones at once.

For this fair price, 70AUD, it worths purchasing.

IBM Bluemix MobileFirst Services Starter for Cordova Tutorial 教學

Create an account on https://new-console.ng.bluemix.net/
Search the template: MobileFirst Services Starter, and create it.
螢幕快照 2016-06-04 11.22.21

After that, download the source code from https://github.com/ibm-bluemix-mobile-services/bms-samples-cordova-helloworld

Before installing Cordova, you will require node.js which is downloaded from https://nodejs.org/en/

If you do not have Cordova installed, then type

npm install -g cordova

Update Cordova

sudo npm update -g cordova

Go to the directory of source code, add cordova platform

cordova platform add android
cordova platform add ios

Install the IBM Bluemix plugin
cordova plugin add ibm-mfp-core

Go to /project-dir/www/js/index.js, paste your route & GUID
route: https://your-proj-name/mybluemix.net
GUID: can be found in the first line of Cloud Foundry’s log in the panel

route: ""
GUID: ""

Open xcodeproj in /project-dir/platform/ios/
If it prompts to update latest swift version, cancel it.
Go to build settings tab and edit Objective-C Bridging Header
/your-proj/plugins/ibm-mfp-core/src/ios/Bridging-Header.h
Find Runpath search Path, and add
@executable_path/Frameworks

Build Cordova
cordova build
Then run
cordova run android

Run iOS platform on Xcode
yayconnected


Cloud Foundry

Install CF CLI from https://github.com/cloudfoundry/cli/releases

Install Bluemix CLI from http://clis.ng.bluemix.net/ui/home.html

If this error occurs

panic: Config error: open config.json: permission denied

type

sudo chmod -R 777 ~/.cf

If this error occurs

panic: no supported languages found []string{“zh_TW.UTF-8”}

go to ~/.cf/config.json

set “Local” : “zh-Hant”

Download your project source code

螢幕快照 2016-06-04 12.11.58

go to /proj-dir , type

bluemix login -a https://api.ng.bluemix.net

push your project

cf your-project-name

Now you are ready to build your own project.

jQuery DataTables plugin with PHP and MS SQL

I hereby provided the code for server-side processing for PHP and MS SQL.

The environment I used was PHP 5.5 and MS SQL 2008

Since PHP 5.5 no longer supports mssql extension, hence, I used sqlsrv extension instead on Window.

<?php
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Easy set variables
*/
 
/* Array of database columns which should be read and sent back to DataTables. Use a space where
* you want to insert a non-database field (for example a counter or static image)
*/
// add your columns here!!!
$aColumns = array( 'columnName1', 'columnName2' );
 
/* MSSQL Database infomation */
$host = 'localhost';
$connectionInfo = array("Database"=>"yourdb", "UID"=>"yourUser", "PWD"=>"yourPassword", "CharacterSet"=>"UTF-8");
$conn = sqlsrv_connect($host,$connectionInfo);
if($conn){
 //echo "Connection Established";
}else{
 echo "Connection could not be Established";
 die ( 'Can not connect to server' );
}
 
/* Indexed column (used for fast and accurate table cardinality) */
$sIndexColumn = "id";
 
/* DB table to use */
$sTable = "Your Table";
 
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* If you just want to use the basic configuration for DataTables with PHP server-side, there is
* no need to edit below this line
*/
 
/*
* Local functions
*/
function fatal_error ( $sErrorMessage = '' )
{
header( $_SERVER['SERVER_PROTOCOL'] .' 500 Internal Server Error' );
die( $sErrorMessage );
}
 
 
/* Ordering */
$sOrder = "";
if ( isset( $_POST['order'] ) )
{
 $sOrder = "ORDER BY ";
 if ( $_POST['columns'][0]['orderable'] == "true" )
 {
 $sOrder .= "".$aColumns[ intval( $_POST['order'][0]['column'] ) ]." ".
 ($_POST['order'][0]['dir']==='asc' ? 'asc' : 'desc');
 }
}
 
/* escape function */
function mssql_escape($data) {
if(is_numeric($data))
return $data;
$unpacked = unpack('H*hex', $data);
return '0x' . $unpacked['hex'];
}
 
/* Filtering */
$sWhere = "";
if ( isset($_POST['search']['value']) && $_POST['search']['value'] != "" ) {
$sWhere = "WHERE (";
for ( $i=0 ; $i<count($aColumns) ; $i++ ) {
$sWhere .= $aColumns[$i]." LIKE '%".addslashes( $_POST['search']['value'] )."%' OR ";
}
$sWhere = substr_replace( $sWhere, "", -3 );
$sWhere .= ')';
}
/* Individual column filtering */
for ( $i=0 ; $i<count($aColumns) ; $i++ ) {
if ( isset($_POST['columns'][$i]) && $_POST['columns'][$i]['searchable'] == "true" && $_POST['columns'][$i]['search']['value'] != '' ) {
if ( $sWhere == "" ) {
$sWhere = "WHERE ";
} else {
$sWhere .= " AND ";
}
$sWhere .= $aColumns[$i]." LIKE '%".addslashes($_POST['columns'][$i]['search']['value'])."%' ";
}
}
 
/* Paging */
$top = (isset($_POST['start']))?((int)$_POST['start']):0 ;
$limit = (isset($_POST['length']))?((int)$_POST['length'] ):5;
$sQuery = "SELECT TOP $limit ".implode(",",$aColumns)."
FROM $sTable
$sWhere ".(($sWhere=="")?" WHERE ":" AND ")." $sIndexColumn NOT IN
(
SELECT TOP $top $sIndexColumn FROM
$sTable $sOrder
)
$sOrder";
$rResult = sqlsrv_query($conn, $sQuery);
if($rResult === false){
 die(sqlsrv_errors(SQLSRV_ERR_ERRORS));
}
 
/* Data set length after filtering */
$sQueryCnt = "SELECT * FROM $sTable $sWhere";
$rResultCnt = sqlsrv_query($conn, $sQueryCnt );
$iFilteredTotal = sqlsrv_num_rows( $rResultCnt );
 
/* Total data set length */
$sQuery = "
SELECT COUNT(id)
FROM $sTable
";
$rResultTotal = sqlsrv_query($conn, $sQuery );
$aResultTotal = sqlsrv_fetch_array($rResultTotal, SQLSRV_FETCH_NUMERIC);

$iTotal = $aResultTotal[0];
 
 
/* Output */
$output = array(
"draw" => intval($_POST['draw']),
"recordsTotal" => $iTotal,
"recordsFiltered" => $iFilteredTotal,
"data" => array()
);
 
 
while ( $aRow = sqlsrv_fetch_array( $rResult, SQLSRV_FETCH_ASSOC) )
{
 $row = array();
 for ( $i=0 ; $i<count($aColumns) ; $i++ )
 {
 /* General output */
 $row[$aColumns[$i]] = $aRow[ $aColumns[$i] ];
 }
 $output['data'][] = $row;
}
 
echo json_encode( $output );
 
?>

 

Intel Galileo 2 with USB WiFi Dongle (RT3070)

The WiFi dongle I am using here is Edimax EW-7711UMn

Here I will talk about how to use it on Intel Galileo 2

prerequisite

Install Linux on Intel Galileo 2

Establish communication through terminal

Step 1.

This USB Wifi dongle is supported by Intel Galileo 2, so we don’t need to install driver.

Just plugin it on the board.

$ iwconfig

Find the dongle identifier as “wlp0s20f3u1”

螢幕快照 2015-10-11 21.00.31

The example here is based on WPA WiFi Router

killall wpa_supplicant
ifconfig wlp0s20f3u1 up
wpa_passphrase "YOUR ESSID" "YOUR PASSWORD" > /tmp/wpa.conf 
wpa_supplicant -BDwext -i YOURWIFIIDENTIFIER -c/tmp/wpa.conf

Then you will see “Successfully initialized wpa_supplicant”

If it appears “ifconfig: SIOCSIFFLAGS: Operation not possible due to RF-kill”, when you are entering “ifconfig wlp0s20f3u1 up”.

rfkill unblock all

You can scan to search nearby SSID

iwlist YOURWIFIIDENTIFIER scan

Make a file “udhcpc.sh” in /etc as below code

#!/bin/sh
# udhcpc script edited by Tim Riker <Tim@Rikers.org>
[ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1

RESOLV_CONF="/etc/resolv.conf"
[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
[ -n "$subnet" ] && NETMASK="netmask $subnet"

case "$1" in
  deconfig)
    /sbin/ifconfig $interface 0.0.0.0
    ;;

  renew|bound)
    /sbin/ifconfig $interface $ip $BROADCAST $NETMASK

    if [ -n "$router" ] ; then
      echo "deleting routers"
      while route del default gw 0.0.0.0 dev $interface ; do
        :
      done

      for i in $router ; do
        route add default gw $i dev $interface
      done
    fi

   echo -n > $RESOLV_CONF
    [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF
    for i in $dns ; do
     echo adding dns $i
      echo nameserver $i >> $RESOLV_CONF
    done
    ;;
esac
exit 0

Then run

udhcpc -i YOURWIFIIDENTIFIER -p /var/run/udhcpc.pid -S -s /etc/udhcpc.sh

You will see like this

螢幕快照 2015-10-11 21.15.59

It works now!!