Package installer Rosetta

| Action | Arch | Red Hat/Fedora | Debian/Ubuntu | SLES/openSUSE | Gentoo |
|—|—|—|—|—|
| Install a package(s) | pacman -S | dnf install | apt install | zypper install | emerge [-a] |
| Remove a package(s) | pacman -Rs | dnf remove | apt remove | zypper remove | emerge -C |
| Search for package(s) | pacman -Ss | dnf search | apt search | zypper search | emerge -S |
| Upgrade Packages | pacman -Syu | dnf upgrade | apt update; apt upgrade | zypper update | emerge -u world |

APT-GET – DEBIAN / UBUNTU

Commad Explanation
sudo apt-get update update repository database
sudo apt-get upgrade update system
sudo apt-get install aPackage install ‘aPackage’
sudo apt-get remove aPackage uninstall ‘aPackage’
sudo apt-cache search aPackage search for ‘aPackage’
sudo apt-cache show aPackage show ‘aPackage’ info

PACMAN – ARCH / MANJARO

Commad Explanation
sudo pacman -Syu update the repository database and update the system
sudo pacman -S aPackage install ‘aPackage’
sudo pacman -R aPackage uninstall ‘aPackage’
sudo pacman -Rs aPackage uninstall ‘aPackage’ and the dependancies which are now useless to the system
sudo pacman -Ss aPackage search for ‘aPackage’
sudo pacman -Sw aPackage donwload ‘aPackage’, but don’t install it
sudo pacman -U /path/aPackage.pkg.tar.gz uninstall ‘aPackage’ from a local path
sudo pacman -Q shows all the installed packages on the system
sudo pacman -Scc deletes every package stored in the pacman cache (/var/cache/pacman/pkg)

ZYPPER – OPENSUSE

Commad Explanation
sudo zypper update update the repository database and update the system
sudo zypper in aPackage install ‘aPackage’
sudo zypper rm aPackage uninstall ‘aPackage’

Introduction

One of the most usual tasks requested for back-end developers is generating a microservices oriented API. When we talk about microservices, we refer to small sets of endpoints, each one of them resolving a different problem, which can be deployed individually in a fast and simple way, so they are easy to escalate in case we need to take care of high amount of requests in a certain area. This is a great advantage compared to the classic monolithic architecture, which requires the deployment of all the services at once, taking more time and resources.

REST services are more efficient than SOAP services, and also easier to securize, so it’s no surprise they are becoming so popular, but deploying and testing the services can be troublesome. Fortunately there are some frameworks which provide us some easy-to-use tools.

Let’s split this issue in 3 steps:

  1. Generating the REST service using JSON.
  2. Booting the service with Spring boot.
  3. Document it and get a user-friendly interface for tests with Swagger.

In our example code, we are going to simulate a small system to handle a videogame database via REST. The code packages will be defined as follows:

  • The API package will contain all the REST API, dividing it by layers (services, data access and data transfer objects), and providing the controller with the endpoints.
  • To set up the swagger system we will need a configuration file, plus the API package classes should get new annotations to document its content.
  • Finally we will add the generic Spring boot runner, which may be used for any package and requires very little tuning.
api

Process

1. Designing a dummy RESTful web service

The first step is creating a basic structure for the REST service. We’ll split it up in different layers:

  • The controller would be VideogameController, and would contain all the endpoints, we’ll leave this for later as, we’ll talk about setting it up with swagger.
  • The interface IVideogameService will define the service layer, which would have the “normal” endpoints.
  • The IVideogameDAO gives an idea of the methods available through the Data Access Layer. In order to void much otrouble setting up a database connection or a real repository, we will mock it.

A good practice is to split the design and the implementation by using interfaces. It’s not really necessary, but it will make the code more reusable.

graph TD
A[VideogameController]
B[IVideogameService]
C[IVideogameDao]

A --> B;
B --> C;

Therefore the Service would simulate commonly known as CRUD operations: get (find), set (update), add (save) and remove (delete).

1
2
3
4
5
6
7
8
9
import org.thalion.snippet.swagger.api.dto.Videogame;

public interface IVideogameService {
Collection<Videogame> findAll();
Videogame findOne(String name);
String save(Videogame videogame);
void update(Videogame setName);
void delete(String name);
}

The service won’t have much to do today, it will only connect to the data access layer and let it handle all the database work.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thalion.snippet.swagger.api.dao.IVideogameDAO;
import org.thalion.snippet.swagger.api.dto.Videogame;

@Service
public class VideogameService implements IVideogameService {

@Autowired
private IVideogameDAO dao;

@Override
public Collection<Videogame> findAll() {
return dao.findAll();
}

@Override
public Videogame findOne(String name) {
return dao.findOne(name);
}

@Override
public String save(Videogame videogame) {
return dao.save(videogame);
}

@Override
public void update(Videogame videogame) {
update(videogame);
}

@Override
public void delete(String name) {
dao.delete(name);
}
}

The Data Access Object or DAO will actually do the hard work, it’s the one which will connect to the database.

1
2
3
4
5
6
7
8
9
10
import java.util.Collection;
import org.thalion.snippet.swagger.api.dto.Videogame;

public interface IVideogameDAO {
Collection<Videogame> findAll();
Videogame findOne(String name);
String save(Videogame videogame);
void update(Videogame videogame);
void delete(String name);
}

But in this case we want to keep it simple since we are focusing on the services layer., so instead of configuring a database connection and writting some queries, we are going to mock it with a simple Map structure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.util.Collection;
import java.util.Map;

import org.springframework.stereotype.Repository;
import org.thalion.snippet.swagger.api.dto.Videogame;

@Repository
public class VideogameDAOMocker implements IVideogameDAO {

private Map<String, Videogame> storage;

@Override
public Collection<Videogame> findAll() {
return storage.values();
}

@Override
public Videogame findOne(String name) {
return storage.get(name);
}

@Override
public String save(Videogame videogame) {
storage.put(videogame.getName(), videogame);
return videogame.getName();
}

@Override
public void update(Videogame videogame) {
storage.put(videogame.getName(), videogame);
}

@Override
public void delete(String name) {
storage.remove(name);
}
}

The Data Transfer Object or DTO isn’t really interesting right now, as it would be just as simple as a class with a couple of Strings to define its attributes. So we will skip its content for now.

Finally, we will refer to the endpoint as the Controller, and since we would be using a REST service with JSON, we will need to add its maven dependency.

1
2
3
4
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
</dependency>

The Controller for Spring MVC would be an extra layer where most of the interesting things we are studying today will happen. First of all, we are going to connect it with the service, and set up the REST via spring JAX-RS annotations:

  • RequestMapping configures the path.
  • RequestMapping states the method expects an HTTP request.
  • RequestBody gets the information from the HTTP body.
  • PathVariable gets a value from the URL.
  • ResponseStatus will store the status code to send back.
  • ResponseBody gets the information from the HTTP body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thalion.snippet.swagger.api.dto.Videogame;
import org.thalion.snippet.swagger.api.service.IVideogameService;

@RestController
@RequestMapping("/api/videogames")
public class VideogameControllerBeta {

@Autowired
private IVideogameService service;

@ResponseStatus(HttpStatus.OK)
@RequestMapping(method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public Collection<Videogame> getAllVideogames() {
return service.findAll();
}

@ResponseStatus(HttpStatus.OK)
@RequestMapping(method = RequestMethod.GET, value = "{name}",
produces = MediaType.APPLICATION_JSON_VALUE)
public Videogame getVideogameByName(@PathVariable String name) {
return service.findOne(name);
}

@RequestMapping(method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> createVideogame(@RequestBody Videogame videogame) {
String videogameCreatedId = service.save(videogame);
return new ResponseEntity<String>(videogameCreatedId, HttpStatus.CREATED);
}

@ResponseStatus(HttpStatus.NO_CONTENT)
@RequestMapping(method = RequestMethod.PUT, value = "{name}")
public void updateVideogame(@PathVariable String name,
@RequestBody Videogame videogame) {
videogame.setName(name);
service.update(videogame);
}

@ResponseStatus(HttpStatus.NO_CONTENT)
@RequestMapping(method = RequestMethod.DELETE, value = "{name}")
public void deleteInfo( @PathVariable String name) {
service.delete(name);
}
}

With this we are all set-up, so let’s find somewhere to run this code.

2. Let’s boot it!

Spring boot is a tool to generate a “just run” application, which can be set up with only a few lines of code an annotations, without any xml configuration. This makes it really interesting in order to run and test Java microservices really fast.

Let’s start by adding its maven dependencies and setting up its just run configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<dependencies>
<!-- spring boot setup ability -->
<dependency>
<groupId>org.springframework.boot>/groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

<!-- Just run configuration -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

Then, we need to set it up in the Java code itself. The longest way to configure it would be using the following annotations:

  • RestController, it’s an Spring-MVC, which sets up this class as controller for a REST service
  • EnableAutoConfiguration, this configures the boot service according to dependencies we have included. Since we used TesController, the system will consider to add Spring MVC and Tomcat.
  • ComponentScan, scans the components of the package and its children packages.

But all this 3 annotations can be reduced to a single one: SpringBootApplication (scanBasePackages = { “replace_with_main_package” }), which is the one used in the example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* Generic SpringBoot, only configured by setting the scanBasePackages
* restricts the scanned packages
*/
@SpringBootApplication(scanBasePackages = { "org.thalion.snippet.swagger" })
public class SpringbootRunner {

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

So just by running this class, a local server will be deployed, and we are ready to test the service… but that’s not intuitive. Let’s make it better.

3. Making it pretty and easy to test, plus avoiding setting up the client side

Documenting an API to make it easy to understand for other developers, and make it friendly for the testers is no easy task. Swagger is a framework which, using a few extra annotations, is able to generate a simple web user interface with REST calls to the API documented, using the metadata available. We are going to use the springfox version, as it comes already bundled with the correct annotations.

❕This was the stable version when the post was originally written.

1
2
3
4
5
6
7
8
9
10
11
12
13
<dependencies>
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>

The most usual annotations are:

  • Api: for controller classes, it sets the API endpoint documentation.
  • Apimodel: for Data Transfer Objects class names.
  • ApiModelProperty: for Data Transfer Objects attributes.
  • ApiOperation: they go above the methods or services available on an endpoint.
  • ApiParam: for input parameter on a method.
  • ApiResponse: for output parameters. You can have more than one with a set of ApiResponses (e.g. also add the 404 error, etc).

Then, in order to fully set this up, there are 2 important points to recheck: the DTO and the controller.

Let’s start with the DTO, as it’s the most straight-forward part: we only need to document the information about the class definition itself and the attributes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package org.thalion.snippet.swagger.api.dto;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

@ApiModel(value = "Videogame entity", description = "Complete data of an entity
videogame")
public class Videogame {

@ApiModelProperty(value = "The name of the videogame", required = true)
private String name;
@ApiModelProperty(value = "The developer of the videogame", required = false)
private String developer;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDeveloper() {
return developer;
}

public void setDeveloper(String developer) {
this.developer = developer;
}
}

The controller is a bit tougher, as we need to document every single endpoint.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thalion.snippet.swagger.api.dto.Videogame;
import org.thalion.snippet.swagger.api.service.IVideogameService;

import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;

@RestController
@RequestMapping("/api/videogames")
public class VideogameController {

@Autowired
private IVideogameService service;

@ResponseStatus(HttpStatus.OK)
@RequestMapping(method = RequestMethod.GET, produces =
MediaType.APPLICATION_JSON_VALUE)
@ApiOperation(value = "Get Videogames", notes = "Returns all the videogame data")
@ApiResponses({ @ApiResponse(code = 200, message = "Returns this information") })
public Collection<Videogame> getAllVideogames() {
return service.findAll();
}

@ResponseStatus(HttpStatus.OK)
@RequestMapping(method = RequestMethod.GET, value = "{name}", produces =
MediaType.APPLICATION_JSON_VALUE)
@ApiOperation(value = "Get the info for one videogame", notes = "Returns the info
from one videogame")
@ApiResponses({ @ApiResponse(code = 200, message = "Exists this information") })
public Videogame getVideogameByName(
@ApiParam(defaultValue = "default", value = "The name of the videogame to return")
@PathVariable String name) {
return service.findOne(name);
}

@RequestMapping(method = RequestMethod.POST, produces =
MediaType.APPLICATION_JSON_VALUE)
@ApiOperation(value = "Create videogame information", notes = "Create a videogame
entry")
@ApiResponses({ @ApiResponse(code = 201, message = "The videgame entry was created
successfully") })
public ResponseEntity<String> createVideogame(@RequestBody Videogame videogame) {
String videogameCreatedId = service.save(videogame);
return new ResponseEntity<String>(videogameCreatedId, HttpStatus.CREATED);
}

@ResponseStatus(HttpStatus.NO_CONTENT)
@RequestMapping(method = RequestMethod.PUT, value = "{name}")
@ApiOperation(value = "Update videogame information", notes = "Update a videogame
information entry")
@ApiResponses({ @ApiResponse(code = 204, message = "The videgame entry was updated
successfully") })
public void updateVideogame(
@ApiParam(defaultValue = "Default", value = "The name of the videogame to update")
@PathVariable String name,
@RequestBody Videogame videogame) {
videogame.setName(name);
service.update(videogame);
}

@ResponseStatus(HttpStatus.NO_CONTENT)
@RequestMapping(method = RequestMethod.DELETE, value = "{name}")
@ApiOperation(value = "Delete videogame", notes = "Deletes a videogame entry")
@ApiResponses({ @ApiResponse(code = 204, message = "The videgame entry was deleted
successfully") })
public void deleteInfo(
@ApiParam(defaultValue = "Default", value = "The name of the videogame to delete")
@PathVariable String name) {
service.delete(name);
}
}

Once all the documentation annotations have been written down, we just need to configure the API page with the help of a Docket builder, which provides the primary graphic interface for our swagger implementation.

Since we are working with an API, we are only going to worry about the URLs under the /api/ pattern, which we can select with the help of regular expressions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

@Bean
public Docket newsApi() {
return new Docket(DocumentationType.SWAGGER_2).groupName("api-videogames")
.apiInfo(apiVideogames()).select().paths(PathSelectors.regex("/api.*")).build();
}

private ApiInfo apiVideogames() {
return new ApiInfoBuilder().title("Videogames REST api POC")
.description("PoC of a REST api, to test both Springboot and Swagger")
.termsOfServiceUrl("https://creativecommons.org/licenses/by/4.0/")
.contact("abcd@mail.com")
.license("GNU General Public License v3.0").licenseUrl(
"https://www.gnu.org/licenses/gpl-3.0.en.html").version("3.0").build();
}
}

And we finally get this beautiful webpage with all the endpoints, which we can easily interact with on localhost:8080/swagger-ui.html. We can interact with the different methods and set up the arguments to do quick tests, avoiding the need to write a client or using a REST requests generator like SoapUI.

Congratulations! your demo is completely set up and ready to go.

Introduction

I was recently requested to debug a pre-.NET application Visual Basic, so I had to set up the environment for Windows 98 development… but nowdays all that software is deprecated and has no support. This is what I learned from my experience to get it up and running, but in case you can make a choice, I’d recommend you to rewrite the code in .NET, as this kind of DLL code relies platform, and things have changed a lot in 20 years.

Process

1.- Delete all the files from the previously failed VB6 installation attempts

Be careful to avoid deleting the recent Visual Studio versions, as they may have similar paths.

  • The Visual Studio 6.0 files are by default under ‘C:\Program Files (x86)’ in 64 bits systems.
1
2
3
4
5
6
7
8
9
10
11
C:\Program Files (x86)\Microsoft Visual Studio\Common
C:\Program Files (x86)\Microsoft Visual Studio\MSDN
C:\Program Files (x86)\Microsoft Visual Studio\MSDN98
C:\Program Files (x86)\Microsoft Visual Studio\VB98
C:\Program Files (x86)\Microsoft Visual Studio\VC98
C:\Program Files (x86)\Microsoft Visual Studio\*.HTM
C:\Program Files (x86)\Microsoft Visual Studio\*.TXT
C:\Program Files (x86)\Common Files\Microsoft Shared\MSDesigners98
C:\Program Files (x86)\Common Files\Microsoft Shared\MSDN
C:\Program Files (x86)\Common Files\Microsoft Shared\VS98
C:\Program Files (x86)\Common Files\Microsoft Shared\Wizards98
  • Clean up the Windows registry entrys: run ‘regedit.exe’ and delete the following keys if they exist.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
HKEY_LOCAL_MACHINE\Software\Microsoft\DevStudio
HKEY_LOCAL_MACHINE\Software\Microsoft\HTML Help Collections
HKEY_LOCAL_MACHINE\Software\Microsoft\MSVSDG
HKEY_LOCAL_MACHINE\Software\Microsoft\Visual Basic\6.0
HKEY_LOCAL_MACHINE\Software\Microsoft\Visual Component Manager
HKEY_LOCAL_MACHINE\Software\Microsoft\Visual Modeler
HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\DevStudio
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\HTML Help Collections
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\MSVSDG
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Visual Basic\6.0
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Visual Component Manager
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Visual Modeler
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\6.0
HKEY_CURRENT_USER\Software\Microsoft\DevStudio
HKEY_CURRENT_USER\Software\Microsoft\MSVSDG
HKEY_CURRENT_USER\Software\Microsoft\Visual Basic\6.0
HKEY_CURRENT_USER\Software\Microsoft\Visual Modeler
HKEY_CURRENT_USER\Software\Microsoft\VisualFoxPro
HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\6.0

2.- Modify the installation files to adapt them to current tech

First of all you will need a copy of the Visual Studio installer in your hard drive. Icopied the content of an old college licensed CD into a folder, and proceeded to edit.

  • Open ‘SETUPWIZ.INI’ with a text editor (e.g. Notepad++), and replace ‘VmPath=ie4\msjavx86.exe’, which tries to install a really old Java implementation and makes the installation process fail, with an empty va. So the first part of the file should look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[setup wizard]
eula = eula.txt
NTSP = NTsp3\nt4sp3_i.exe
NTSpMinVer = 3
IE4 = ie4\ie4setup.exe
CommonFilesMin = 50
IEIni=ie4check.ini
WFCClean = setup\wfcclean.exe
readme = readmevs.htm
pid = setup.ini
MSDN = setup.exe
Acme = acmboot.exe
AcmeId = vs98ecd1.inf
STF = setup\vs98ent.stf
DCOM98 = dcom98\dcom98.exe
MSDNID = msdn3?1.inf
NtSpUrl = ftp://ftp.microsoft.com/bussys/winnt/winnt-public/fixes/
IeUrl = http://www.microsoft.com/ie/ie40/download/
UsrUrl = http://msdn.microsoft.com/vstudio/register/default.htm
RegUrl = http://www.microsoft.com/isapi/redir.dll?Prd=vstudio&Pver=98&Ar=register
VmPath=
  • You must also edit the ‘SETUP.EXE’ properties. Go to the context menu of the file (right click as default), select properties, and got to the ‘compatibility’ tab. Check that you have selected:

    • Compatibility mode: execute as ‘Windows XP (Service Pack 3)’.
    • Configuration: ‘execute this program as administrator’.

3.- Execute the wizard installer

  1. Open the context menu of ‘SETUP.EXE’ and choose ‘run as administrator’.
  2. Don’t install ‘Source Safe’, as it fails.
  3. When we get to ‘choose the installation mode’ select ‘Custom’. Then follow these steps:
  • Do not install (as they fail):
    • Microsoft Visual FoxPro 6.0
    • Microsoft Visual InterDev 6.0
    • Microsoft Visual SourceDafe 6.0
    • ActiveX (obsolete version, generates conflict with the current version)
  • Install the unicode libraries: from the custom main menu, select the text ‘Microsoft Visual C++ 6.0’, and the button ‘Change option’ on the right side will be set as active. Click on it and follow a similar process for ‘VC++ MFC and Template Libraries’ and ‘MS Foundation Class Libraries’. Finally select all these options:
    • Static libraries
    • Shared libraries
    • Static libraries for Unicode
    • Shared libraries for Unicode
    • Browser database
    • Source code
  • Install the database: from the main ‘Custom’ menu, click on the ‘Data Access’ text , and the button ‘Change option’ on the right side will be set as active. Click on it and make sure that ‘ADO, RDS and OLE DB Providers’ is not selected. You will get a warning message saying that this component is esential for the application, but you should ignore it, as it will crash on Windows 10. Do select only the following options:
    • Microsoft ODBC Drivers
    • Remote Data Objects and Controls
    • Data environment
  • Install the tools: from the main ‘Custom’ menu, click on the ‘Enterprise Tools’ text, and the button ‘Change option’ on the right side will be set as active. Check that ‘Visual Studio Analyzer’ is not selected. Therefore, select only:
    • Aplication Performance Explorer
    • Repository
    • Visual Component Manager
    • Visual Basic Enterprise Components
    • VC++ Enterprise Tools
    • Microsoft Visual Modeler
  • As the last step, before pressing on ‘Finish’, do not let the program configure the environment vars.
    • If you have waited more than 5 minutes and the program is still ‘configuring the system’, you can assume something has gone wrong and the install has been frozen somewhere. Cancel it, clean up (see the first section on top of this post) and start all over again, reading carefully the steps.
    • If there is an error message about the Java machine you can ignore it. At that point you should be able by then to run ‘Visual Basic’ without the MSDN help package, so you get the bare bones yet fully functional experience.

4.- Execute the application

Run it always in administrator mode (right click on Visual Basic 6.0, and select ‘run as administrator’). Then, here it is, ready to run and debug ancient DLLs.

❗️ If you want it the program to run using a Microsoft Office 2010 instance, you will need to load some dependencies. Go to ‘Project/References’ and select:

  • Visual Basic for Applications
  • Visual Basic runtime objects and procedures
  • Visual Basic objects and procedures
  • OLE Automation
  • Microsoft Excel 15.0 Object Library
  • Microsoft Word 15.0 Object Library

5.- References

Install

1
2
npm install -g gulp
gulp -v # check version

Use

  1. Install for the project

    1
    2
    3
    4
    # --save-dev will only add the dependencies to dev, not production
    npm install --save-dev gulp
    npm install --save-dev gulp-concat # concat files
    npm install --save-dev gulp-uglify # minify
  2. Go to gulpfile.js:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /*
    * Dependencies
    */
    var gulp = require('gulp'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify');

    /*
    * Configure a demo task
    */
    gulp.task('demo', function () {
    gulp.src('js/source/*.js')
    .pipe(concat('todo.js'))
    .pipe(uglify())
    .pipe(gulp.dest('js/build/'))
    });
  3. With that you can run on the terminal:

    1
    gulp demo

Gulp.js API

  • gulp.task()

    • Basic use

      1
      2
      3
      4
      5
      6
      7
      # `gulp.task(nameTask, functionDefinition, callback)`
      /*
      * Configure 'demo'
      */
      gulp.task('demo', function () {
      // define 'demo' task
      });
    • Task list

      1
      2
      // A task 'statics' will run other 2 asynchronous tasks
      gulp.task('statics', ['myTask1', 'myTask2']);
    • Task dependecies

      1
      2
      3
      4
      5
      6
      gulp.task('myTask2', ['myTask'], function () {
      /*
      * 'myTask2' function
      * it will only be executed after 'myTask' has finsihed
      */
      });
    • Default task

      1
      2
      3
      4
      5
      6
      7
      8
      // it will run just by tyoing `gulp` in the terminal
      gulp.task('default', function () {
      /*
      * Default rask code
      */
      });
      // you can also make your default a list of tasks
      gulp.task('default', ['myTask1', 'myTask2']);
  • gulp.src()

    1
    2
    3
    4
    5
    6
    gulp.src('js/source/1.js') #get only 'js/source/1.js'
    gulp.src('js/source/*.js') # all the '.js' files in `js/source/`
    gulp.src('js/**/*.js') #get only '.js' files from `js/` and its subfolder
    gulp.src('!js/source/2.js') # exclude `2.js'`
    gulp.src(`static/*.+(js|css)`) # all the files which finish in `js` or `css`
    # this can be piped or be sent to `gulp.dest()`
  • pipe()

    1
    2
    3
    //read, edit stream data
    .pipe(concat('todo.js'))
    .pipe(uglify())
  • gulp.dest()

    1
    2
    // write the stream in the folder
    .pipe(gulp.dest('js/build/'))
  • gulp.watch()

    1
    2
    3
    4
    5
    6
    // check the file and execute the task when it is edited
    gulp.watch('js/source/*.js', ['myTask']);
    // you can use it with a callback too
    gulp.watch('js/source/*.js', function(){
    // callback function
    });

Plugins

1
2
# Add jshint task
npm install --save-dev gulp-jshint

Then we can do:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
* Dependencies
*/
var gulp = require('gulp'),
jshint = require('gulp-jshint'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify');

/*
* Configure the 'demo' task
*/
gulp.task('demo', function () {
gulp.src('js/source/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(concat('todo.js'))
.pipe(uglify())
.pipe(gulp.dest('js/build/'))
});

Bridge

Decouple abstraction from its implementation so that 2 can very independently

  • avoid permanent binding (so you can switch easily)
  • both elements can be extended
  • avoid recompiling one when there are changes on the other
  • 4 elements
    • abstraction (BO) - interface
    • redefined abstraction (customers BO) class
    • implementor (Data object) - interface
    • concrete implementor (customer data object) -class
  • example: client
    • Abstraction -> RefinedAstraction (Shape: Circle, Rectangle)
    • Implementor -> ConcreteImplementorA, ConcreteImplementorB (Drawing: DrawingA, DrawingB)
  • representation
    graph LR;
    A[Abstraction];
    B[Refined abstraction];
    C[Implementor];
    D[Concrete implementor];
    C-->A;
    B-.->A;  
    D-.->C;
  • consequences
    • decoupling
    • improved exetensibility
    • hiding implementation details from clients
  • Related pattern: adapter: unrelated classes working together

Builder

Splits construction and representation -> Factory vs BO

  • 4 elements
    • Director (builds something)
    • Builder (abstract) -> does the consctruction the director requires
    • ConcreteBuilder -> created externally, actually builds
    • Product (built by the Builder under the Director direction)
  • representation
    graph LR;
    A[Director];
    B[Builder: Concrete Builder];
    C[Product];
    A-->B; 
    B-->C;
  • consequences
    • Products internal representation
    • Control + isolation over construction process

Command: encapsulating invocation

Encapsulate method invocation - abstraction (e.g. single remote control for different devices: many on-off switches)

  • 4 elements
    • Client - creates command, chooses receiver
    • Receiver - knows how to perform the action
    • Concrete Command - binds action and receiver: execute() and undo()
    • Invoker (holds commands) –> ICommand (interface for all commands)
  • consequences
    • Package computation (loggng, transactional systems)
    • Decoupled job queues with “macro commands”
    • Bad stuff: time consuming, bloated commands
  • representation
    graph LR;
    A[Client];
    B[Receiver];
    C[Concrete Command];
    D[Invoker];
    E[ICommand];
    A-->B;
    A-->C;
    D-->E;

❗ Notes:

  • There can be a NoCommand (empty slot in a controller)
  • There can be an undo method (e.g. turn off lightbulb on controller)

Decorator

Structural, add behaviour to a particular object, as opposed to class objets (the others are unmodified)
(e.g. java.io.Reader/*component*/: InputStreamReader/*concreteComponent*/ and BufferedReader /*decorator*/)

  • 3 elements
    • Component (hang())
    • ConcreteComponent (hang()) //inheritance from Component
    • Decorator (hang()) //inheritance from Component, uses component
  • representation
    graph TD;
    A[Component];
    B[Concrete Component];
    C[Decorator];
    B-.->A;
    C-.->A;
    C-->B;
  • consequences
    • original object ‘not polluted’
    • flexible
    • doesn’t require source from original object
    • fewer classes than inheritance

Factory aka virtual constructor

Creational design pattern, as can’t anticipate which classes will be generated

  • 4 elements
    • Creator: abstract, provides full default implementation
    • Concrete Creator
    • Product
    • Concrete Product
  • representation
    graph LR;
    A[Creator: Concrete creator];
    B[Product: Concrete product];
    A-->B

Singleton

Unique instance without using an static class, so the class can be easily mocked and tested

1
2
3
4
5
6
7
8
9
10
11
public class Singleton{
private static Singleton instance;

private Singleton(){}
public Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
0%