Function – convert list of numbers (comma separated) to range (compress)

Standard

Example: 1, 3, 4, 5, 6 to 1,3-6

Implementation using PHP (For other language, you just need to modify some part of it)

function commaToRange($commaString)
{
	$rangeString = "";
	
	$arr = explode (",", $commaString);
	// to remove space
	$commaString = str_replace(" ", "", $commaString);

        // as the scope is integer, step is set to 1
	$step = 1;
		
	// if there are at least 2 numbers
	if (count($arr)> 1) 
	{
		$start = 0;
			
		for ($i = 1; $i < count($arr); $i++)
		{
			// if current range ends (=discontinued), print the last value of the range and print ',' to indicate start of new range 
			if ($arr[$i] - $arr[$i-1] > $step)
			{
				$rangeString .= $arr[$i-1];
				$rangeString .= ",";
				$start = $i;
			}
			// if current range keeps continuous, do nothing. (if the range keep continuous until second number, print the first value of the range and '-' to indicate range)
			else
			{
				if ($i - 1 == $start)
					$rangeString .= $arr[$i-1]."-";
			}
				
			// if the element is last, force printing
			if (count($arr) -1 == $i)
					$rangeString .= $arr[$i];
			}
	}
	// if there are only one number or less, return input itself
	else 
		$rangeString = $commaString;
		
	return $rangeString;
}

[XE] 회원 가입 시, 사용자가 수정 불가능한 항목 설정하기

Standard

http://study.prl85.com/xe-관리자만-수정-가능한-회원-정보-항목-설정하기/
에서는 회원 정보 수정 시, 관리자만 수정 가능한 항목을 설정하는 방법을 다루고 있습니다.

이 글에서는 이를 응용하여 회원 가입 시 사용자가 수정 불가능한 항목을 설정하는 방법을 다루겠습니다.
(활용: 특정 서비스 인증키.
즉, 회원 가입/정보 수정 시 사용자가 임의로 수정할 수는 없지만, 관리자가 정한 값을 본인 회원 정보에서는 보여주고 싶은 경우)

회원 정보 수정 때만 아니라, 회원 가입시에도 동일한 함수가 항목들을 출력하는 부분을 처리합니다.

xe – modules – member – member.admin.view.php에서
function _getMemberInputTag($memberInfo, $isAdmin = false)

다만 회원 정보 수정 때와 회원 가입 때 $readonly를 처리하는 부분이 조금 다릅니다.
회원 정보 수정 시에는, 로그인된 정보에서 관리자인지를 가려내서 수정 가능/불가능 여부가 가려지지만, 회원 가입시는 로그인된 정보라는 것이 없기 때문이죠 (로그인되지 않은 상태에서만 회원 가입이 가능하기 때문).
역으로 이 점을 이용해서, 로그인된 정보가 없을 때 (=회원 가입) 원하는 항목을 수정 불가능하게 만들면 됩니다.

$readonly = '';

if (Context::get('logged_info') == null) // 회원 가입시
    $readonly = 'readonly="readonly"';

if (Context::get('logged_info')
    && Context::get('logged_info')->is_admin != 'Y') // 회원 정보 수정시 (관리자만 가능)
    $readonly = 'readonly="readonly"';

회원 가입시에만 혹은 회원 정보 수정시 (이 경우는 관리자만)에 수정이 불가능하게 하려면 해당 항목만 남겨두면 되겠지요.

나머지 사항은 위의 링크를 참고하시면 되겠습니다.

[Ubuntu 14.04] Setting process affinity in kernel mode (2/2 – Example code)

Standard

Prerequisite)
Prerequisite and all steps from https://study.prl85.com/ubuntu-14-04-setting-process-affinity-in-kernel-mode-12-kernel-modification

Sample code (cpu_affinity_user.c)

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sched.h>
#include <errno.h>
#include <linux/unistd.h>

void printCoreList()
{
	int i = 0;
	
	pid_t p = 0;	// meaning current process
	cpu_set_t mask;
	size_t len = sizeof(cpu_set_t);

	printf("(Current available CPU Core ID List:");	
	sched_getaffinity(p, len, &mask); // get available (movable) cpu cores

	bool printed = false;
	for (i = 0; i<CPU_SETSIZE; i++) 
	{
		if (CPU_ISSET(i, &mask))
		{
			printed = true;
			printf(" %d", i);
		}
	}
	
	if (printed == false)
		printf(" None");
	printf(")\n");
}

double measureTime(int calledID)
{
//	printf("Work - Called from cpu core %d\n", calledID);
	printf("Work - My allocated cpu core is %d\n", sched_getcpu());
		
	struct timeval currenttime;
	int i;
	
	// measure start time
	gettimeofday( &currenttime, 0 );

	long cur_time1 = 1000000 * currenttime.tv_sec + currenttime.tv_usec;
	double sec1 = cur_time1 / 1000000.0;
	
	// do some work
	for(i = 0; i < 5000000; i++)
		printf("%s", "\r");

	// measure end time
	gettimeofday( &currenttime, 0 );

	long cur_time2 = 1000000 * currenttime.tv_sec + currenttime.tv_usec;
	double sec2 = cur_time2 / 1000000.0;
	
	return sec2 - sec1;
}

int main()
{
	srand(time(NULL));

	int i = 0, j = 0, cpuChanged = 0;

	pid_t p = 0;	// meaning current process
	size_t len = sizeof(cpu_set_t);
	cpu_set_t new_mask;

	int numCpuCore = get_nprocs();		// get total number of cpu core
	int currentCore;	

	printf("Total number of CPU Core: %d\n", numCpuCore);
	printf("Current allocated CPU Core ID: %d\n", currentCore = sched_getcpu());	// get current allocated core

//	printCoreList(); // uncomment to see cpu affinity
	
	// case 1: normal mode (no cpu core fix)
	printf("<Doing some work without fixing the cpu core...>\n\n");

	int numOfRepetition = 30; // number of task repetition
	for (i = 0; i < numOfRepetition; i++) 
	{
		printf("[%3d/%3d] ", i+1, numOfRepetition);
		double elapsedTime = measureTime(currentCore = sched_getcpu());	// do work

		int newCore = sched_getcpu();	// what is current core after work?
		if (currentCore != newCore) // if the allocated cpu core is changed 
		{
			printf(" After work, my allocated CPU Core ID is moved to %d\n", currentCore = newCore);	
			cpuChanged++;
		}
	}
	printf("* Number of CPU core allocation change: %d (Out of %d trials, %.1lf%%)*\n", cpuChanged, numOfRepetition, (double) cpuChanged/(double) numOfRepetition*100.0);
	
	// case 2: special mode (cpu core fix)
	printf("\n<Randomly assigning another core...>\n");
	while(1)
	{
		int newcpuID = rand() % numCpuCore;
		if (newcpuID != currentCore)
		{
			CPU_ZERO(&new_mask);
			CPU_SET(newcpuID, &new_mask);
			break;
		}
	}
	
	cpuChanged = 0;
	
	// set to new core
	sched_setaffinity(p, len, &new_mask);
	printf("<New allocated CPU Core ID: %d>\n", sched_getcpu());
	
	printf("<Doing some work after fixing the cpu core...>\n");
	
	for (i = 0; i < numOfRepetition; i++) 
	{
		printf("[%3d/%3d] ", i+1, numOfRepetition);
		double elapsedTime = measureTime(currentCore = sched_getcpu());	// do work

		int newCore = sched_getcpu();	// what is current core after work?
		if (currentCore != newCore) // if the allocated cpu core is changed 
		{
			printf(" After work, my allocated CPU Core ID is moved to %d\n", currentCore = newCore);	
			cpuChanged++;
		}
	}
	printf("* Number of CPU core allocation change: %d (Out of %d trials, %.1lf%%)*\n", cpuChanged, numOfRepetition, (double) cpuChanged/(double) numOfRepetition*100.0);	
	return 0;
}

This code will execute measureTime() 30 times without cpu core fixed, then 30 times with cpu core fixed.
Each measureTime() takes some time, possibility of core allocation change, as shown in result.

How to run)

gcc cpu_affinity_user.c -o affinitytest
./affinitytest

Result)

Part 1 – CPU Core information, and initial allocated core

Total number of CPU Core: 4
Current allocated CPU Core ID: 1
(Current available CPU Core ID List: 0 1 2 3)

Part 2 – CPU core movement before fixing the cpu core

<Doing some work without fixing the cpu core...>
[  1/ 30] Work - My allocated cpu core is 1
 After work, my allocated CPU Core ID is moved to 0
[  2/ 30] Work - My allocated cpu core is 0
 After work, my allocated CPU Core ID is moved to 1
[  3/ 30] Work - My allocated cpu core is 1
[  4/ 30] Work - My allocated cpu core is 1
 After work, my allocated CPU Core ID is moved to 0
[  5/ 30] Work - My allocated cpu core is 0
 After work, my allocated CPU Core ID is moved to 3
[  6/ 30] Work - My allocated cpu core is 3
[  7/ 30] Work - My allocated cpu core is 3
[  8/ 30] Work - My allocated cpu core is 3
[  9/ 30] Work - My allocated cpu core is 3
[ 10/ 30] Work - My allocated cpu core is 3
[ 11/ 30] Work - My allocated cpu core is 3
 After work, my allocated CPU Core ID is moved to 2
[ 12/ 30] Work - My allocated cpu core is 2
 After work, my allocated CPU Core ID is moved to 3
[ 13/ 30] Work - My allocated cpu core is 3
[ 14/ 30] Work - My allocated cpu core is 3
 After work, my allocated CPU Core ID is moved to 0
[ 15/ 30] Work - My allocated cpu core is 0
[ 16/ 30] Work - My allocated cpu core is 0
[ 17/ 30] Work - My allocated cpu core is 0
[ 18/ 30] Work - My allocated cpu core is 0
[ 19/ 30] Work - My allocated cpu core is 0
[ 20/ 30] Work - My allocated cpu core is 0
 After work, my allocated CPU Core ID is moved to 3
[ 21/ 30] Work - My allocated cpu core is 3
[ 22/ 30] Work - My allocated cpu core is 3
[ 23/ 30] Work - My allocated cpu core is 3
 After work, my allocated CPU Core ID is moved to 0
[ 24/ 30] Work - My allocated cpu core is 0
[ 25/ 30] Work - My allocated cpu core is 0
[ 26/ 30] Work - My allocated cpu core is 0
 After work, my allocated CPU Core ID is moved to 3
[ 27/ 30] Work - My allocated cpu core is 3
[ 28/ 30] Work - My allocated cpu core is 3
 After work, my allocated CPU Core ID is moved to 0
[ 29/ 30] Work - My allocated cpu core is 0
 After work, my allocated CPU Core ID is moved to 1
[ 30/ 30] Work - My allocated cpu core is 1
* Number of CPU core allocation change: 12 (Out of 30 trials, 40.0%)*

Part 3 – CPU core movement after fixing the cpu core

<Randomly assigning another core...>
<New allocated CPU Core ID: 0>
<Doing some work after fixing the cpu core...>
[  1/ 30] Work - My allocated cpu core is 0
[  2/ 30] Work - My allocated cpu core is 0
[  3/ 30] Work - My allocated cpu core is 0
[  4/ 30] Work - My allocated cpu core is 0
[  5/ 30] Work - My allocated cpu core is 0
[  6/ 30] Work - My allocated cpu core is 0
[  7/ 30] Work - My allocated cpu core is 0
[  8/ 30] Work - My allocated cpu core is 0
[  9/ 30] Work - My allocated cpu core is 0
[ 10/ 30] Work - My allocated cpu core is 0
[ 11/ 30] Work - My allocated cpu core is 0
[ 12/ 30] Work - My allocated cpu core is 0
[ 13/ 30] Work - My allocated cpu core is 0
[ 14/ 30] Work - My allocated cpu core is 0
[ 15/ 30] Work - My allocated cpu core is 0
[ 16/ 30] Work - My allocated cpu core is 0
[ 17/ 30] Work - My allocated cpu core is 0
[ 18/ 30] Work - My allocated cpu core is 0
[ 19/ 30] Work - My allocated cpu core is 0
[ 20/ 30] Work - My allocated cpu core is 0
[ 21/ 30] Work - My allocated cpu core is 0
[ 22/ 30] Work - My allocated cpu core is 0
[ 23/ 30] Work - My allocated cpu core is 0
[ 24/ 30] Work - My allocated cpu core is 0
[ 25/ 30] Work - My allocated cpu core is 0
[ 26/ 30] Work - My allocated cpu core is 0
[ 27/ 30] Work - My allocated cpu core is 0
[ 28/ 30] Work - My allocated cpu core is 0
[ 29/ 30] Work - My allocated cpu core is 0
[ 30/ 30] Work - My allocated cpu core is 0
* Number of CPU core allocation change: 0 (Out of 30 trials, 0.0%)*

 

[Ubuntu 14.04] Setting process affinity in kernel mode (1/2 – kernel modification)

Standard

Prerequisite)

Step 1 and 2 from http://study.prl85.com/building-ubuntu-kernel/
(=Ready to compile kernel)

Procedure)

1. Find the file containing sched_setaffinity function from non-compiled kernel source directory.
(In this case, kernel/sched/core.c)

bsw@bsw-P5K:~$ cd linux-3.13.0-orig/
bsw@bsw-P5K:~/linux-3.13.0-orig$ grep -R "long sched_setaffinity" *
include/linux/sched.h:extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask);
kernel/sched/core.c:long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)

2. In kernel/sched/core.c, add EXPORT_SYMBOL_GPL(sched_setaffinity); after the end of sched_setaffinity() definition.

long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
{
cpumask_var_t cpus_allowed, new_mask;
struct task_struct *p;
int retval;
...
out_unlock:
free_cpumask_var(new_mask);
out_free_cpus_allowed:
free_cpumask_var(cpus_allowed);
out_put_task:
put_task_struct(p);
return retval;
}
EXPORT_SYMBOL_GPL(sched_setaffinity);

3. In kernel/sched/core.c, add EXPORT_SYMBOL_GPL(sched_getaffinity); after the end of sched_getaffinity() definition.

long sched_getaffinity(pid_t pid, struct cpumask *mask)
{
        struct task_struct *p;
        unsigned long flags;
        int retval;

        rcu_read_lock();

        retval = -ESRCH;
        p = find_process_by_pid(pid);
        if (!p)
                goto out_unlock;

        retval = security_task_getscheduler(p);
        if (retval)
                goto out_unlock;

        raw_spin_lock_irqsave(&p->pi_lock, flags);
        cpumask_and(mask, &p->cpus_allowed, cpu_active_mask);
        raw_spin_unlock_irqrestore(&p->pi_lock, flags);

out_unlock:
        rcu_read_unlock();

        return retval;
}
EXPORT_SYMBOL_GPL(sched_getaffinity);

4. Build new kernel and reboot
(Refer to step 5~9 from http://study.prl85.com/building-ubuntu-kernel)

Reference)
http://stackoverflow.com/questions/1151285/setting-process-affinity-in-kernel-mode
http://study.prl85.com/building-ubuntu-kernel

[Ubuntu 14.04] Building Linux Kernel

Standard

Procedure)

1. Download kernel source of current version

apt-get source linux-image-$(uname -r)
bsw@bsw-P5K:~$ apt-get source linux-image-$(uname -r)

Reading package lists... Done
Building dependency tree
Reading state information... Done
Picking 'linux' as source package instead of 'linux-image-3.13.0-44-generic'
NOTICE: 'linux' packaging is maintained in the 'Git' version control system at:
http://kernel.ubuntu.com/git-repos/ubuntu/ubuntu-trusty.git
Need to get 125 MB of source archives.
Get:1 http://kr.archive.ubuntu.com/ubuntu/ trusty-updates/main linux 3.13.0-55.92 (dsc) [11.8 kB]
Get:2 http://kr.archive.ubuntu.com/ubuntu/ trusty-updates/main linux 3.13.0-55.92 (tar) [116 MB]
Get:3 http://kr.archive.ubuntu.com/ubuntu/ trusty-updates/main linux 3.13.0-55.92 (diff) [8752 kB]
Fetched 125 MB in 23min 56s (87.1 kB/s)
...
 linux-3.13.0/virt/kvm/async_pf.c
 linux-3.13.0/virt/kvm/coalesced_mmio.c
 linux-3.13.0/virt/kvm/ioapic.c
 linux-3.13.0/virt/kvm/iommu.c
 linux-3.13.0/virt/kvm/kvm_main.c

2. Configure build environment (one-time)

sudo apt-get build-dep linux-image-$(uname -r)
sudo apt-get update
sudo apt-get install curses-dev
bsw@bsw-P5K:~$ sudo apt-get build-dep linux-image-$(uname -r)
[sudo] password for bsw:
Reading package lists... Done
Building dependency tree
Reading state information... Done
Picking 'linux' as source package instead of 'linux-image-3.13.0-44-generic'
The following NEW packages will be installed:
  asciidoc docbook-dsssl docbook-utils docbook-xml docbook-xsl gawk jadetex
  kernel-wedge libaudit-dev libdw-dev libdw1 libelf-dev libiberty-dev
  libnewt-dev libosp5 libostyle1c2 libsgmls-perl libslang2-dev libsp1c2
  libunwind8 libunwind8-dev lynx lynx-cur makedumpfile openjade sgml-data
  sgmlspl sp transfig xmlto xsltproc
0 upgraded, 31 newly installed, 0 to remove and 3 not upgraded.
Need to get 11.1 MB of archives.
After this operation, 51.3 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 http://kr.archive.ubuntu.com/ubuntu/ trusty/main gawk amd64 1:4.0.1+dfsg-2.1ubuntu2 [781 kB]
...
Setting up xmlto (0.0.25-2) ...
Setting up docbook-dsssl (1.79-7ubuntu1) ...
Processing triggers for sgml-base (1.26+nmu4ubuntu1) ...
Setting up docbook-utils (0.6.14-3ubuntu1) ...
Processing triggers for libc-bin (2.19-0ubuntu6.6) ...

3. Confirm the location of kernel source (/linux-3.13.0)

Screen Shot 2015-06-16 at 10.34.18 PM

4. Example of kernel modification (keep settings) (in linux-3.13.0 directory)
cf) If you have things to modify, do that instead of this.
cf) If you don’t have things to change or just want to test kernel compile, then go to next step (step 5)

This takes the current configuration for each architecture/flavour supported and calls menuconfig to edit its config file. The chmod is needed because the way the source package is created, it loses the executable bits on the scripts.
(from https://wiki.ubuntu.com/Kernel/BuildYourOwnKernel)

chmod a+x debian/scripts/*
chmod a+x debian/scripts/misc/*
fakeroot debian/rules clean
fakeroot debian/rules editconfigs

5. Build the kernel (might take awhile…) (in linux-3.13.0 directory)

fakeroot debian/rules clean
fakeroot debian/rules binary-headers binary-generic

6. Deb packages are created after successful build

cd ..
ls *.deb

Screen Shot 2015-06-17 at 12.16.00 AM

7. Before install deb packages, install linux-tools for right version (one-time)
(3.13.0-55 should be replaced to your kernel version)
(You might see errors when installing linux-tools, but that’s okay)

sudo apt-get install linux-tools-3.13.0-55
sudo apt-get install -f

8. Install these package to test new kernel (3.13.0-55.92 should be replaced to your kernel version, the string after generic_ and before _amd64)

sudo dpkg -i linux*3.13.0-55.92*.deb

When install deb packages, you should see messages like below (no errors)

...
Generating grub configuration file ...
Found memtest86+ image: /boot/memtest86+.elf
Found memtest86+ image: /boot/memtest86+.bin
Found linux image: /boot/vmlinuz-3.13.0-55-generic
Found initrd image: /boot/initrd.img-3.13.0-55-generic
Found linux image: /boot/vmlinuz-3.13.0-44-generic
Found initrd image: /boot/initrd.img-3.13.0-44-generic
Found linux image: /boot/vmlinuz-3.13.0-32-generic
Found initrd image: /boot/initrd.img-3.13.0-32-generic
Found Windows Recovery Environment (loader) on /dev/sda1
Found linux image: /boot/vmlinuz-3.13.0-55-generic
Found initrd image: /boot/initrd.img-3.13.0-55-generic
Found linux image: /boot/vmlinuz-3.13.0-44-generic
Found initrd image: /boot/initrd.img-3.13.0-44-generic
Found linux image: /boot/vmlinuz-3.13.0-32-generic
Found initrd image: /boot/initrd.img-3.13.0-32-generic
done
Setting up linux-tools-3.13.0-55-generic (3.13.0-55.92) ...

To confirm the deb packages are correctly installed (=you are ready to boot using the new kernel), type cat /boot/grub/grub.cfg | grep menuentry
You can see “Ubuntu with Linux 3.13.0-55-generic”, the version of compiled kernel.

Screen Shot 2015-06-17 at 12.56.52 AM

9. Reboot and print current kernel version

sudo reboot

After reboot, print current kernel version.

bsw@bsw-P5K:~$ uname -r
3.13.0-55-generic

Reference)
https://wiki.ubuntu.com/Kernel/BuildYourOwnKernel
http://askubuntu.com/questions/270381/how-do-i-install-ncurses-header-files

[XE] 회원 정보 수정 시, 관리자만 수정 가능한 항목 설정하기

Standard

xe – modules – member – member.admin.view.php에서
function _getMemberInputTag($memberInfo, $isAdmin = false)
이 함수가 회원정보 수정 시 항목들을 출력하는 부분을 처리하는 함수이다.

1. 기본 정보의 경우, 쭉 내려와서 if($formInfo->isDefaultForm) 아래에서 다음 부분을 찾는다.

1.1. 이메일, 홈페이지, 블로그 같이 이미 조건문에 명시적으로 나와있는 경우
여기선 예시로 이메일의 경우를 살펴본다. (1.8.2 기준 495 라인 쯤)

else if($formInfo->name == 'email_address')
{
    $formTag->type = 'email';
    $inputTag = '<input id="email_address" name="email_address" type="email" value="'.$memberInfo['email_address'].'" />';
}

else if($formInfo->name == 'email_address')
{
    $readonly = '';
    if (Context::get('logged_info') && Context::get('logged_info')->is_admin != 'Y')
        $readonly = 'readonly="readonly"';

    $formTag->type = 'email';
    $inputTag = '<input type="email" name="email_address" id="email_address" value="'.$memberInfo['email_address'].'"'.$readonly.' />';
}

수정한다.


1.2. 이름, 닉네임처럼 조건문에 나와있지 않은 경우
여기서는 예시로 이름의 경우를 살펴본다. (1.8.2 기준 510 라인 쯤)

else
{
    $formTag->type = 'text';
    $inputTag = sprintf('<input type="text" name="%s" id="%s" value="%s" />',
        $formInfo->name,
        $formInfo->name,
        $memberInfo[$formInfo->name]);
}

위에

else if ($formInfo->name == 'user_name')
{
    $readonly = '';
    if (Context::get('logged_info') && Context::get('logged_info')->is_admin != 'Y')
        $readonly = 'readonly="readonly"';

    $formTag->type = 'text';
    $inputTag = sprintf('<input type="text" name="%s" id="%s" value="%s" %s/>',
        $formInfo->name,
        $formInfo->name,
        $memberInfo[$formInfo->name],
        $readonly);
}

추가한다.

(즉, 아래와 같이 되면 된다)
Screen Shot 2015-06-16 at 3.06.29 PM

여러 항목을 추가할 때에는 추가한 항목들이 다 else 위에 있으면 된다
(else if 구문끼리의 순서는 관계 없음)


2. 확장 변수로 지정된 항목의 경우,
}//end isDefaultForm 아래에서 다음 부분을 찾는다.

$formTag->type = $extendForm->column_type;
if($extendForm->column_type == 'text')
{
    $template = '<input type="text" name="%column_name%" id="%column_name%" value="%value%" />';
}

수정할 확장 변수가 텍스트인 경우 if($extendForm->column_type == ‘text’)보다 먼저 조건 확인이 되어야 한다. (그래야, 다른 텍스트형 확장 변수와는 다르게 처리할 수 있으니까)

즉, 다음과 같이 내용을 추가한다 (ext_var는 원하는 확장변수의 변수명을 쓰면 된다)
(기존 if($extendForm->column_type == ‘text’) 구문이 else if로 변경된 것을 알 수 있다)

$formTag->type = $extendForm->column_type;
if($extendForm->column_name == 'ext_var')
{
    $readonly = '';
    if (Context::get('logged_info') && Context::get('logged_info')->is_admin != 'Y')
        $readonly = 'readonly="readonly"';

    $template = '<input type="text" name="%column_name%" id="%column_name%" value="%value%" '.$readonly.'/>';
}
else if($extendForm->column_type == 'text')
{
    $template = '<input type="text" name="%column_name%" id="%column_name%" value="%value%" />';
}

(여기서는 텍스트 형 변수 두 개를 처리했다.)
Screen Shot 2015-06-16 at 4.09.46 PM

팁)
– 관리자 여부와 상관없이 무조건 회원정보 수정에서 불가하게 하려면, 다음 두 줄을 없애거나 주석 처리하면 된다.

// $readonly = ”;
// if (Context::get(‘logged_info’) && Context::get(‘logged_info’)->is_admin != ‘Y’)

– 2번에서, text 형태인 것이 확실하다면 if …. else if 구조로 바꿀 필요 없이, text 조건문 안에 다음과 같이 변경해도 된다. (막상 이렇게 보니, 이게 더 효율적일 수도 있겠다 싶다.)

if($extendForm->column_type == 'text')
{
    $readonly = '';
    // 위의 그림처럼 여러 확장 변수를 처리할 경우를 대비해서, 의도적으로 if 문 분리
    if ($extendForm->column_name == 'ext_var')
    {
        if (Context::get('logged_info') && Context::get('logged_info')->is_admin != 'Y')
            $readonly = 'readonly="readonly"';
    }

    $template = '<input type="text" name="%column_name%" id="%column_name%" value="%value%" '.$readonly.'/>';
}

참고 링크)
http://www.xpressengine.com/qna/20457366

Compiling telegram-cli on Mac OSX 10.13 (with homebrew)

Standard

Test environment) Mac OSX 10.13 (High Sierra) with homebrew
(I prefer homebrew as it doesn’t require superuser permission, compared to macports)

Changes)
The way installing required packages (step 3) and compiling package (step 4) are updated in the official page, so I reflected the changes.

Procedure)
1. Install homebrew (refer to http://brew.sh) if not installed

2. Clone from GitHub Repository

git clone –recursive https://github.com/vysheng/tg.git && cd tg

3. Install required packages (bison requires to be installed in homebrew for solving problem installing libevent)

brew install bison
export PATH=”/usr/local/opt/bison/bin:$PATH”
# to use installed bison permanently
echo ‘export PATH=”/usr/local/opt/bison/bin:$PATH”‘ >> ~/.bash_profile

brew install libconfig readline lua python libevent jansson

4. Compile telegram-cli
(7.0.3_1, the version of readline, can be changed according to update; change it to match your installed version)

# edit lua-tg.c to comment line 664~666 (get_peer())

export CFLAGS=”-I/usr/local/include -I/usr/local/Cellar/readline/7.0.3_1/include -I/usr/local/Cellar/openssl/1.0.2l/include
export LDFLAGS=”-L/usr/local/lib -L/usr/local/Cellar/readline/7.0.3_1/lib -L/usr/local/Cellar/openssl/1.0.2l/lib
./configure

# before executing make, edit Makefile and remove -I/usr/local/include in CFLAGS (line 3 in my case)

# (before edit)
# CFLAGS=-I/usr/local/include -I/usr/local/Cellar/readline/7.0.3_1/include – I/usr/local/Cellar/openssl/1.0.2l/include
# (after edit)
# CFLAGS=-I/usr/local/Cellar/readline/7.0.3_1/include -I/usr/local/Cellar/openssl/1.0.2l/include

make

(Screenshot – end of source compile)

5. Run

bin/telegram-cli -k tg-server.pub

(You need to config the client by entering phone number including country code and code – one-time setting)

(Screenshot – successful configuration, you can see online notification)

cf) When you see “CONFIGURE: ERROR: CANNOT RUN C COMPILED PROGRAMS.” error when trying to install packages, execute xcode-select –install in terminal to (re)install Xcode command line development tools.
https://study.prl85.com/resolving-configure-error-cannot-run-c-compiled-programs-error-when-using-home-brew/

Reference) 
https://github.com/vysheng/tg (Official telegram-cli page)
https://stackoverflow.com/questions/44187405/issues-building-doxygen-with-cmake (solving libtool installation problem)
https://github.com/vysheng/tg/issues/996 (solving lua-tg.c compile problem)

Resolving “configure: error: cannot run C compiled programs.” error when using home-brew

Standard

Symptom)
You might see “configure: error: cannot run C compiled programs.” error when trying to install some package using homebrew.

(Example)
Screen Shot 2015-06-12 at 11.00.07 PM

Solution)
It happened to me when upgraded to a new major release of Mac OSX. (e.g. from 10.10 to 10.11)
Open terminal, execute following command, and install Xcode command line development tools.

xcode-select –install

After installation, homebrew will work as expected.

즉, xcode command line develop tool을 재설치해서 해결한다는 의미입니다.

Reference)
http://stackoverflow.com/questions/19594719/install-any-version-of-ruby-with-rvm-on-mavericks

(Updated) Creating Wi-Fi AP using Raspberry Pi

Standard

(Update) After the Raspbian being updated, the way setting Wi-Fi AP is changed a bit.


1. Installing Raspbian (It’s explained how it can be done with Mac OS X; however it doesn’t differ much for Windows or Linux too)
(Skip to step 2 if your Raspberry Pi already works with Raspbian.)
(You also can use image without noobs, but it might be complex)

1-1. Download NOOBS
(NOOBS is an easy operating system installer which contains Raspbian. It also provides a selection of alternative operating systems which are then downloaded from the internet and installed.)

Download NOOBS from http://downloads.raspberrypi.org/NOOBS_latest.
(If above link doesn’t work well, then download NOOBS from https://www.raspberrypi.org/downloads)

1-2. Format the MicroSD card with FAT32 partition.
(In my case, using SD Association’s SD formatter with 64 GB memory formatted the card as exFAT. However, the Raspberry Pi only detected FAT32-formatted memory, so use other tools for formatting; like Disk Utility in Mac with specifying partition type as FAT32 (FAT in DIsk Utility))

(old) 1-2. Download SD Association’s SD formatter.
Download the formatter from https://www.sdcard.org/downloads/formatter_4/eula_mac.
After download, install by executing pkg file.

(old) 1-3. Execute SD Association’s SD formatter.
Insert SD card you want to use on Mac, execute SD Association’s SD formatter, then format the card with selecting “overwrite format”

1-3. Copy NOOBS files to the SD CARD
Uncompress the downloaded NOOBS archive file (e.g. NOOBS_v1_4_1.zip)
After then, copy all files to the root of the SD card.
(Files including bootcode.bin, BUILD-DATA, …. should come to the root directory like below.)

Screen Shot 2015-06-12 at 12.37.33 PM

1-4. Turn on raspberry pi
Detach the sd card from Mac, then insert it to raspberry pi.
Boot raspberry pi. When NOOBS run, select Raspbian as operating system to install.
(Optional: set language as English (US))


2. Setting IP of Ethernet Interface (in case of static IP)
Refer to https://www.modmypi.com/blog/how-to-give-your-raspberry-pi-a-static-ip-address-update. However, you should’t assign your wireless LAN IP address (wlan0 interface in the example) to /etc/dhcpcd.conf.

3. Setting IP of Wireless LAN interface, AP configuration
Refer to https://frillip.com/using-your-raspberry-pi-3-as-a-wifi-access-point-with-hostapd.

However, I needed to exclude ieee80211n=1 in /etc/hostapd/hostapd.conf (after channel setting) to get worked. (802.11n mode is enabled even without the settings)

After setting things according to the link, you can see the AP.
You can also make AP created automatically on each boot by below commands (one-time):

sudo update-rc.d hostapd enable
sudo update-rc.d dnsmasq enable

Reference)
https://www.modmypi.com/blog/how-to-give-your-raspberry-pi-a-static-ip-address-update.
https://frillip.com/using-your-raspberry-pi-3-as-a-wifi-access-point-with-hostapd
(Deprecated) good reference from my lab mate’s blog http://blog.naver.com/solar0ryu/220391354960