Skip navigation


Just met a problem when I tried to serialize a PHP DateInterval object in HHVM (at least for 3.9.1). Turns out the DateInterval is unserializable. Create a bit workaround for this.

<?php

$dateinterval1 = new DateInterval('PT1H');
$baseDate = new DateTimeImmutable();
$date1 = $baseDate->add($dateinterval1);
$string1 = $dateinterval1->format('%y years %m months %d days %h hours %i minutes %s seconds');

$dateinterval2 = DateInterval::createFromDateString($string1);
$date2 = $baseDate->add($dateinterval2);

$string2 = $dateinterval2->format('%y years %m months %d days %h hours %i minutes %s seconds');
if ($string1 == $string2) {
    print "Formats are equal\n";
}
if ($date1 == $date2) {
    print "Objects are equal\n";
}
if ($date1->getTimestamp() == $date2->getTimestamp()) {
    print "Timestamp are equal\n";
}

The test can be seen here: https://3v4l.org/HvLFP


Usually before committing a file we need to check modified files against the code convention before committing to the code repository.

Here’s a single line to run modified files in Git against PHPCS.

git ls-files -m | grep '\.php$' | xargs ./vendor/bin/phpcs -s --standard=etc/phpcs/ruleset.xml

Code above assumes you install PHPCS using composer and have your own standard located in the etc/phpcs/ruleset.xml.

UPDATE

To check all uncommited files, run this

git ls-files --others --exclude-standard | grep '\.php$' | xargs ./vendor/bin/phpcs -s --standard=etc/phpcs/ruleset.xml

I just watched The Last: Naruto The Movie a couple of days ago and I recalled that it’s been almost a quarter of decade since I last read the mangascan.

Reading Naruto in Kindle

Reading Naruto in Kindle

So I got a complete 2GB of mangascan pictures from my friend from volume 1 until volume 72. I’ve been a fan of Kindle e-book reader and I want to read the mangascan in my Kindle device. Here’s how I converted the PNG and JPG files to PDF so it can be readable in Kindle.

Basically what I need is imagemagick library to convert the images to PDF. Here is how to use the imagemagick to do the conversion.

As long as the JPG/PNG files is named with proper file naming, doing a batch conversion in zipped files is as simple as this. It shouldn’t take too long to convert all of the images to PDF. In my case it took less than an hour. The quality of the PDF is not that bad, but I think we can configure the imagemagick to increase the quality. I assume it reduces the quality by a bit.

for zipfile in $(find . -type f -iname &quot;*.zip&quot; | sort -n); do
    echo &quot;$zipfile&quot;
    filename=$(basename &quot;$zipfile&quot;)
    filename=&quot;${filename%.*}&quot;
    echo &quot;$filename&quot;
    unzip $zipfile -d $filename
    echo &quot;Converting....&quot;
    find $filename | sort -n | tr '\n' ' ' | sed &quot;s/$/\ ${filename}.pdf/&quot; | xargs convert -verbose
done

See? Pretty simple, right? (The fact that it’s really simple is why I posted here. Might be useful for me in the future).


To accept Angular $http.post that is formatted as JSON in Yii2, just set this in the Yii2 application component.

        'request' => [
            'parsers' => [
                'application/json' => 'yii\web\JsonParser',
            ]
        ],

To use the data, don’t use global $_POST. Instead use

$data = Yii::$app->getRequest->post();

So I some times need to run a monthly cron job. And I want to set a parameter for duration spanned from first day and last day in the current month.

This is how I do it.

if [ -z “$STARTTIME” ] || [-z “$ENDTIME”]; then
STARTTIME=`date -d “-$(($(date +%d)-1)) days” +%Y-%m-%dT00:00:00Z`;
ENDTIME=`date -d “+1 month -$(date +%d) days” +%Y-%m-%dT23:59:59Z`;
fi

echo $STARTTIME
echo $ENDTIME


For quite some time I’ve been looking for a very easy way to deploy a small service using Java that is accessible through HTTP and self-hosted, or in other words, it doesn’t need a installed server. I was initially thinking about using embedded Tomcat or Jetty by writing the server code manually.

But then it turns out that there is this project from Spring built specifically for this kind of application: the Spring Boot. As quoted from the web,

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that can you can “just run”.

By using this framework, I only need to focus on building the service rather than writing the HTTP server. And running the service is just as simple as using plain old `java -jar`.

The whole source code can be seen in this URL https://github.com/petrabarus/springboot-opsworks-example.

I started by using the sample code from Spring Boot.

import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;

@Controller
@EnableAutoConfiguration
public class SampleController {

    @RequestMapping("/")
    @ResponseBody
    String home() {
        return "Hello World!";
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(SampleController.class, args);
    }
}

The skeleton code for the controller can not be much simpler than this.

And here’s the POM file.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.petrabarus.maleskoding</groupId>
    <artifactId>springboot-opsworks-example</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.6.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <!-- Sets to use Jetty. No particular reasons -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <dependency>
            <!-- For deployment ready -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <!-- Creates directory for OpsWorks config -->
                <directory>src/deploy</directory>
                <targetPath>../deploy</targetPath>
            </resource>
            <resource>
                <!-- Creates config directory for external config --> 
                <directory>src/config</directory>
                <targetPath>../config</targetPath>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <!-- Creates JAR -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <!-- Creates zip distributable -->
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <descriptor>src/assembly/dep.xml</descriptor>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>
</project>

The XML code below is the minimum configuration to run the service. (The spring-boot-starter-jetty is used to make the service runs using Jetty instead of the default embedded Tomcat).

<!-- cut -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.6.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <!-- Sets to use Jetty. No particular reasons -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>

<!-- cut -->

To build the JAR, I use this plugin

<!-- cut -->
    <build>
        <!-- cut -->
        <plugins>
            <plugin>
                <!-- Creates JAR -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
<!-- cut -->

Building the JAR is simply just by executing

$mvn clean install

and the JAR will be in the `target` directory, e.g. target/springboot-opsworks-example-1.0-SNAPSHOT.jar I run it using the usual java -jar command

$target/springboot-opsworks-example-1.0-SNAPSHOT

I can see the result by using curl

$curl localhost:8080
Hello World!

Now it’s time to deploy it using OpsWorks. In this example I use `HTTP archive`, but it’s better to use `S3 archive` to provide better security since it can use IAM credentials.

Screenshot from 2014-09-20 00:02:21

The ZIP-ed file for deployment can be created using `spring-boot-maven-plugin`

<!-- cut -->
    <build>
        <!-- cut -->
        <plugins>
            <plugin>
                <!-- Creates zip distributable -->
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <descriptor>src/assembly/dep.xml</descriptor>
                </configuration>
            </plugin>
<!-- cut -->

Here’s the assembly XML configuration

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
    <id>bin</id>
    <formats>
        <format>zip</format>
    </formats>
    <fileSets>
        <fileSet>
            <directory>${project.build.directory}</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>*.jar</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}/config</directory>
            <outputDirectory>config</outputDirectory>
            <includes>
                <include>*.xml</include>
                <include>*.properties</include>
                <include>*.yml</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}/deploy</directory>
            <outputDirectory>deploy</outputDirectory>
        </fileSet>
    </fileSets>
</assembly>

Now I can have a very simple build and distribution script like below. This can be use for Jenkins. When a new change is pushed to the git repository, Jenkins will download the change, build, test the source, and then pack and upload the binary.

$mvn clean install assembly:single && s3cmd put -P target/*.zip s3://path/to/the/upload.zip

As we know, deploying in OpsWorks is just a matter of click.

Screenshot from 2014-09-20 00:02:07

Note that deploying the OpsWorks app doesn’t mean running the service automatically. For that I need to use a deploy hook. Chef provides a way to execute a ruby script on steps in the deployment. Using the `before_restart.rb` I can execute a task that happens after the app directory changes its link from the old directory to the new deployed directory.

The content of `before_restart.rb` script is in below

script "runjar" do
    interpreter "bash"
    user "root"
    cwd release_path
    code <<-EOH
        java -jar *.jar > /var/log/springbootext1/app.log 2>&1 &
    EOH
end

I added the file in the `src/deploy` directory and I declare it as a resource in the POM file.

    <build>
        <resources>
            <resource>
                <!-- Creates directory for OpsWorks deploy hook -->
                <directory>src/deploy</directory>
                <targetPath>../deploy</targetPath>
            </resource>

The next question is how to shutdown the running service and update the new JAR. Spring Boot provides a production-ready feature called the actuator. Here I can put a shutdown for the service that will turn off the running service. To add the actuator, I define the dependency in the POM file.

<!-- cut -->
        <dependency>
            <!-- For deployment ready -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
<!-- cut -->

And in the deploy hook, before the run service script I added new script

script "shutdown" do
    interpreter "bash"
    user "root"
    cwd release_path
    code <<-EOH
        curl -XPOST "http://localhost:8080/shutdown" > /var/log/springbootext1/app.log 2>&1
    EOH
end

That script send a POST request to the current running service to shut itself down. As default the shutdown actuator is not enabled by default. I still need to add new configuration. To do this, I added a new file `scr/config/application.properties` and I added this line.

endpoints.shutdown.enabled=true

Spring Boot has a very flexible way of configuring the application. The simplest way is to have `config/application.properties` file in the JAR directory. The application JAR will check what’s inside the file and override the configuration.

The deploy directory also needs to be declared as resource in the POM file

<!-- cut -->
    <build>
        <resources>
            <!-- cut -->
            <resource>
                <!-- Creates config directory for external config --> 
                <directory>src/config</directory>
                <targetPath>../config</targetPath>
            </resource>
        </resources>
            <!-- cut -->

So now I have a minimum skeleton for deploying a small standalone HTTP service. Keep in mind to restrict the 8080 port by using AWS Security Group so that the 8080 port is only accessible to appropriate instances.

Regarding the deployment, I’m guessing there will be few seconds downtime between the shutdown and running new service. This can be even much longer if I put some long task in the shutdown listener. I’m still thinking how to do this more seamlessly. Ideas needed😉

Another thing I can do is passing the custom JSON in the OpsWorks to the `application.properties` configuration file.

I can define something like this.

{
    "springboot-example": {
        "config": {
            "server.port" : 3333,
            "management.port": 3334
        }
    }
}

It’s a good idea to make the server port and the management port more configurable among other things. And I can write that JSON in the `application.properties` using the deploy hook `before_symlink.rb` and modify the `before_restart.rb` to use the custom JSON for the port numbers. This is very flexible since I can define the custom JSON in the Stack level and also in the deployment level.


Just another snippet. By using Chef’s PHP cookbook, we can easily install Zend Opcache. That if we still use PHP 5.4 since 5.5. have the opcache in the default distribution.

Put this in the recipe

php_pear "opcache" do
  package_name "ZendOpcache"
  action :install
  preferred_state "beta"
  zend_extensions ["opcache.so"]
  directives node['php']['opcache']['directives']
end

and this in the attributes

default['php']['opcache']['directives'] = {
    'memory_consumption' => 128,
    'interned_strings_buffer' => 8,
    'max_accelerated_files' => 4000,
    'revalidate_freq' => 60,
    'fast_shutdown' => 1,
    'enable_cli' => 1,
    'save_comments' => 0,   
}

I imported a CSV in pandas like below

>>> import pandas
>>> df = pandas.read_csv('file.csv',names=['count', 'province', 'city', 'district', 'region', 'area'])
>>> df.head()
   count province         city           district region area
0   7923     Aceh   Aceh Barat   Arongan Lambalek            
1    628     Aceh   Aceh Barat     Johan Pahlawan            
2    235     Aceh   Aceh Barat        Woyla Timur            
4   3900     Aceh   Banda Aceh                         

using SQL, I can do something like this

    SELECT SUM(count) AS sum, district 
        FROM table WHERE city = 'Aceh Barat' 
        GROUP BY district 
        ORDER BY sum DESC

but using pandas python library, I can achieve the same using.

>>> import pandas, numpy
>>> df = pandas.read_csv('file.csv',names=['count', 'province', 'city', 'district', 'region', 'area'])
>>> df[df['city'] == 'Aceh Barat'].groupby('district').aggregate(numpy.sum).sort(['count'], ascending=False)
                  count
district               
Arongan Lambalek   7923
Johan Pahlawan      628
Woyla Timur         235

>>> df[df['city'] == 'Aceh Barat'].groupby('district').aggregate(numpy.sum).sort(['count'], ascending=False)
                  count
district               
Arongan Lambalek   7923
Johan Pahlawan      628
Woyla Timur         235

>>> df[df['city'] == 'Medan']
        count        province   city            district region area
10340  108769  Sumatera Utara  Medan                 NaN    NaN  NaN
10341     759  Sumatera Utara  Medan        Medan Amplas    NaN  NaN
10342     579  Sumatera Utara  Medan        Medan Amplas    NaN  NaN
10343    1272  Sumatera Utara  Medan        Medan Amplas    NaN  NaN
10344     769  Sumatera Utara  Medan        Medan Amplas    NaN  NaN
10345     379  Sumatera Utara  Medan        Medan Amplas    NaN  NaN
10346     988  Sumatera Utara  Medan        Medan Amplas    NaN  NaN
10347    4395  Sumatera Utara  Medan          Medan Area    NaN  NaN
10348    5598  Sumatera Utara  Medan         Medan Barat    NaN  NaN

>>> df[df['city'] == 'Medan'].groupby('district').aggregate(numpy.sum).sort(['count'], ascending=False)
                    count
district                 
Medan Tuntungan      7425
Medan Tembung        6349
Medan Barat          5598
Medan Timur          5378
Medan Amplas         4746

Just a simple trick I did today.

Basically I want to remove the circle button in the radio button and use the label as the choice for the button.

So instead of having this

Screenshot from 2014-03-06 13:21:31

I want to have this

Screenshot from 2014-03-06 13:21:45

I can do this just using CSS without Javascript. Here’s the JS Fiddle.

http://jsfiddle.net/petrabarus/pPgS7/

 


This is just a very simple snippets, yet I can’t find it anywhere. I guess this rarely met.

Here’s how to use multiline input using Yii ConsoleCommand. In the console command class, use `$args` parameter in the console action.

public function actionIndex($args=array()){
   print_r($args)
}

Then you can execute something like command below which tries to input a JSON string to the console command.

$yii command index '{
   "name": "value"
}'

and the console will return

Array
(
    [0] => {
   "name": "value"
}
)
Ikuti

Kirimkan setiap pos baru ke Kotak Masuk Anda.

Bergabunglah dengan 36 pengikut lainnya

%d blogger menyukai ini: