Julien DuponchelleJekyll2024-03-10T20:42:48+01:00/Julien Duponchelle/julien@duponchelle.info
/scrapping/ai/Common-Crawl
/scrapping/ai/Common-Crawl2024-03-10T00:00:00+01:002024-03-10T00:00:00+01:00Julien Duponchellejulien@duponchelle.info<h1 id="what-is-common-crawl">What is Common Crawl?</h1>
<p>Common Crawl is a non-profit organization that crawls the web and freely provides its archives and datasets to the public. The organization was founded in 2007.</p>
<p>The Common Crawl corpus is a petabyte-scale archive of web pages and metadata. The dataset is hosted on Amazon Web Services (AWS) and is freely accessible to the public. The web pages in the dataset are continuously updated and are made available for download on a regular basis.</p>
<p>It’s the perfect tools to build a dataset for your AI project.</p>
<h1 id="the-dataset">The dataset</h1>
<p>The dataset is stored in Amazon S3. You can access the dataset using S3 API or by plain HTTP. S3 access is more optimized and recommended.</p>
<p>The dataset is split into multiple files. Each file is a part of the dataset and contains a subset of the web pages.</p>
<h1 id="how-to-access-the-dataset">How to access the dataset</h1>
<p>First go to https://commoncrawl.org/get-started</p>
<p>And select the last dataset available:
<img src="/assets/images/common-crawl/image.png" alt="dataset" /></p>
<p><img src="/assets/images/common-crawl/image-1.png" alt="types" /></p>
<p>You can download the whole dataset but it’s unlikely that you have the storage to store it. But you don’t need to download the whole dataset if you are interested in a specific part of the dataset. You can download only the pages that you need.</p>
<p>To extract a page from the dataset you need:</p>
<ul>
<li>The segment file of the page</li>
<li>The offset of the page in the segment file</li>
<li>The length of the page in the segment file</li>
</ul>
<p>This information is stored in the index of the dataset. The index is a file that contains the location of each URL in the dataset.</p>
<p>Once you have this information, you can perform an HTTP range request to download the page.</p>
<pre><code class="language-python">import gzip
import io
import requests
segment_file = 'crawl-data/CC-MAIN-2023-50/segments/1700679100499.43/warc/CC-MAIN-20231203094028-20231203124028-00893.warc.gz'
offset = 225013702
length = 7069
url = f'https://data.commoncrawl.org/{segment_file}'
response = requests.get(URL, headers={'Range': f'bytes={offset}-{offset+length-1}'})
if response.status_code == 206:
content = response.content
# Decompress the data
with gzip.open(io.BytesIO(content), 'rb') as f:
content = f.read()
print(content)
else:
print(f"Failed to fetch data: {response.status_code}")
</code></pre>
<h1 id="how-to-get-the-location-of-a-page-in-the-dataset">How to get the location of a page in the dataset</h1>
<h2 id="use-the-common-crawl-index-api">Use the Common Crawl Index API</h2>
<p>The Common Crawl Index API is a service that provides a simple interface to search the Common Crawl corpus. The API allows you to search for web pages that match a specific query.</p>
<p>The API is very simple you just pass the URL of the page that you are looking for and the API will return the location of the page in the dataset.</p>
<p>For example, for the page https://commoncrawl.org/faq you can use the following request:</p>
<pre><code class="language-http">http://index.commoncrawl.org/CC-MAIN-2023-50-index?url=commoncrawl.org%2Ffaq&output=json
</code></pre>
<p>You can replace <em>CC-MAIN-2023-50</em> by the last dataset available.</p>
<pre><code class="language-json">{"urlkey": "org,commoncrawl)/faq", "timestamp": "20231203094453", "url": "https://commoncrawl.org/faq", "mime": "text/html", "mime-detected": "text/html", "status": "200", "digest": "E6N62SALJEROKFK4BVRK523WLDBV67RW", "length": "7069", "offset": "225013702", "filename": "crawl-data/CC-MAIN-2023-50/segments/1700679100499.43/warc/CC-MAIN-20231203094028-20231203124028-00893.warc.gz", "languages": "eng", "encoding": "UTF-8"}
</code></pre>
<p>The Common Crawl foundation provides a full example on how to use the API and retrieve the page:
https://gist.github.com/thunderpoot/58a748565d2e5b2582520fa535821908#file-cc_fetch_page-py</p>
<p>This method is the easiest way to get the location of a specific page in the dataset but if you need to get the location of a lot of pages it’s not the best way to do it.</p>
<h2 id="use-the-index-files">Use the index files</h2>
<p>You can download all the index files from the dataset and search the location of the page in the files.</p>
<p>The file <em>cc-index.paths.gz</em> contains the location of all the index files. You can download this file and extract the location of the index files. The whole index size is around 300GB compressed.</p>
<p>Other versions of the index file <em>cc-index-table.paths.gz</em> is available. This is the same data but as Apache Parquet files. This format can be read by tools like DuckDB, Apache Spark, Trino… The usage will be similar to the usage of the AWS Athena.</p>
<h2 id="use-aws-athena">Use AWS Athena</h2>
<p>Athena is a Trino-based serverless interactive query service that makes it easy to analyze large amounts of data in Amazon S3 using standard SQL.</p>
<p>Athena is cost-effective and easy to use. There is no need to set up or manage infrastructure, and you only pay for the queries that you run.</p>
<p>You pay 5$ by TB scanned. If you correctly use the partitioning of the dataset the cost can be very low.</p>
<h3 id="setup-athena">Setup Athena</h3>
<p>You need to select the region US-East-1 (N. Virginia) to access the common crawl dataset.</p>
<p>Open the query editor and create a new database:</p>
<pre><code class="language-sql">CREATE DATABASE ccindex
</code></pre>
<p>Next you need to create a table by running the following query:
https://github.com/commoncrawl/cc-index-table/blob/main/src/sql/athena/cc-index-create-table-flat.sql</p>
<pre><code class="language-sql">CREATE EXTERNAL TABLE IF NOT EXISTS ccindex (
url_surtkey STRING,
URL STRING,
url_host_name STRING,
url_host_tld STRING,
url_host_2nd_last_part STRING,
url_host_3rd_last_part STRING,
url_host_4th_last_part STRING,
url_host_5th_last_part STRING,
url_host_registry_suffix STRING,
url_host_registered_domain STRING,
url_host_private_suffix STRING,
url_host_private_domain STRING,
url_host_name_reversed STRING,
url_protocol STRING,
url_port INT,
url_path STRING,
url_query STRING,
fetch_time TIMESTAMP,
fetch_status SMALLINT,
fetch_redirect STRING,
content_digest STRING,
content_mime_type STRING,
content_mime_detected STRING,
content_charset STRING,
content_languages STRING,
content_truncated STRING,
warc_filename STRING,
warc_record_offset INT,
warc_record_length INT,
warc_segment STRING)
PARTITIONED BY (
crawl STRING,
subset STRING)
STORED AS parquet
LOCATION 's3://commoncrawl/cc-index/table/cc-main/warc/';
</code></pre>
<p>The table is not created but if you try a query it’s not going to work.</p>
<p>You need first to repair the table:</p>
<pre><code class="language-sql">MSCK REPAIR TABLE ccindex
</code></pre>
<p>You will also need to do that when a new dataset is available.</p>
<h3 id="run-a-query">Run a query</h3>
<p>First you can try that the dataset is correctly loaded by running the following query:</p>
<pre><code class="language-sql">SELECT * FROM ccindex LIMIT 1
</code></pre>
<p><img src="/assets/images/common-crawl/image-2.png" alt="alt text" /></p>
<p>When you do a query make sure to pay attention to the cost of the query.</p>
<p><img src="/assets/images/common-crawl/image-3.png" alt="alt text" /></p>
<p>To reduce the cost makes sure to use the <em>crawl</em> and <em>subset</em> columns in your query. This will reduce the amount of data scanned because the dataset is partitioned by <em>crawl</em> and <em>subset</em>.</p>
<p>Also use <strong>LIMIT</strong> to reduce the amount of data returned by the query.</p>
<p>This request will return to the location of all the pages of the website trino.io:</p>
<pre><code class="language-sql">SELECT URL,
warc_filename,
warc_record_offset,
warc_record_length
FROM ccindex
WHERE crawl = 'CC-MAIN-2023-50'
AND subset = 'warc'
AND url_host_name = 'trino.io'
AND content_mime_type = 'text/html'
LIMIT 1000
</code></pre>
<p><img src="/assets/images/common-crawl/image-4.png" alt="alt text" /></p>
<p>You can after export it as a CSV file and use it to download the pages.</p>
<h1 id="conclusion">Conclusion</h1>
<p>Common Crawl is amazing tool to access web data without the need to crawl the web yourself. The dataset is huge and it’s perfect for bootstrapping AI projects.</p>
<p><a href="/scrapping/ai/Common-Crawl">Use Common Crawl to access web data</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on March 10, 2024.</p>
/android/Use-Proxy-With-Waydroid
/android/Use-Proxy-With-Waydroid2024-01-09T00:00:00+01:002024-01-09T00:00:00+01:00Julien Duponchellejulien@duponchelle.info<p>Waydroid is a project that allows you to run Android applications on a Linux distribution. It’s a fork of the project Anbox-Android-in-a-Box. Android applications are run in a container and do not have the overhead of emulators.</p>
<p>This article will explain how to use a proxy with Waydroid and intercept the traffic using a proxy. This can be useful to reverse engineer an API or for security testing.</p>
<h1 id="install-waydroid-on-ubuntu">Install Waydroid on Ubuntu</h1>
<p>First, you need to install Waydroid on your Ubuntu distribution. You can follow the instructions on the <a href="https://waydro.id/">official website</a>.</p>
<p>Here is a quick summary:</p>
<pre><code class="language-terminal">$ sudo apt install curl ca-certificates -y # Install curl and ca-certificates
$ curl https://repo.waydro.id | sudo bash # Add the repository
$ sudo apt install waydroid adb -y # Install Waydroid package and Android Debug Bridge
$ sudo systemctl enable --now waydroid-container # Start the service
</code></pre>
<p><strong>BE CAREFUL</strong>: Waydroid require Wayland.</p>
<p>At this point, you should be able to launch Waydroid from the application menu. You will be prompted to download the Android image with or without the Google applications. Once the download is complete, you will be able to launch Android applications.</p>
<p>If the newtork doesn’t work you can use https://github.com/waydroid/waydroid/issues/143</p>
<pre><code class="language-terminal">sudo sed -i~ -E 's/=.\$\(command -v (nft|ip6?tables-legacy).*/=/g' \
/usr/lib/waydroid/data/scripts/waydroid-net.sh
</code></pre>
<h1 id="install-a-proxy">Install a Proxy</h1>
<p>We are going to use Mitmproxy as a proxy. You can install it with the following command:</p>
<pre><code class="language-terminal">$ sudo apt install mitmproxy -y
</code></pre>
<p>Mitmproxy will be used to intercept the traffic between the Android application and the Internet. It’s an Open Source project that allows you to inspect and modify HTTP traffic. It’s also easy to script with Python.</p>
<p>Mitmproxy can be used as a command-line tool or with a web interface. We are going to use the web interface.</p>
<p>You can start Mitmproxy with the following command:</p>
<pre><code class="language-terminal">$ mitmweb -p 8888
</code></pre>
<p>This will start Mitmproxy on port 8888 and launch the web interface. You can access the web interface by opening the following URL in your browser: http://127.0.0.1:8081</p>
<h2 id="test-with-curl">Test with curl</h2>
<p>You can test the proxy with Curl. You need to set the proxy with the following command:</p>
<pre><code class="language-terminal">$ export http_proxy=http://127.0.0.1:8888
</code></pre>
<p>Next, you can test the proxy with the following command:</p>
<pre><code class="language-terminal">$ curl http://example.com
</code></pre>
<p>You should see the request in the Mitmproxy web interface.</p>
<p><img src="2024-01-09-19-54-14.png" alt="" /></p>
<p>If you try to proxy HTTPS traffic, you will get a certificate error.</p>
<pre><code class="language-terminal">$ export https_proxy="http://127.0.0.1:8888"
$ curl https://example.com
</code></pre>
<p>You can ignore the certificate error with the following command:</p>
<pre><code class="language-terminal">$ curl --insecure https://example.com
</code></pre>
<p>To make it work in Waydroid you will need to install the certificate in the Android image.</p>
<p>The certificate is located in the following directory: <code>~/.mitmproxy/</code></p>
<h1 id="setup-the-proxy-in-waydroid">Setup the proxy in Waydroid</h1>
<p>First you need to get the IP address of your computer on the container network. You can get it with the following command:</p>
<pre><code class="language-terminal">$ ip address show waydroid0
18: waydroid0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:16:3e:00:00:01 brd ff:ff:ff:ff:ff:ff
inet 192.168.240.1/24 brd 192.168.240.255 scope global waydroid0
valid_lft forever preferred_lft forever
inet6 fe80::216:3eff:fe00:1/64 scope link
valid_lft forever preferred_lft forever
</code></pre>
<p>Here the IP is 192.168.240.1</p>
<p>We restart Mitmproxy with the following command:</p>
<pre><code class="language-terminal">$ mitmweb -p 8888 --listen-host 192.168.240.1
</code></pre>
<p>Then you can configure the proxy in Waydroid with the following command:</p>
<pre><code class="language-terminal">$ adb shell settings put global http_proxy "172.17.0.1:8888"
</code></pre>
<p>You can now test in the browser a non HTTPS page.</p>
<h1 id="install-the-certificate-in-waydroid">Install the certificate in Waydroid</h1>
<p>All credit goes to <a href="https://github.com/waydroid/waydroid/issues/870">this GitHub issue</a>.</p>
<p>First you need the certificate hash.</p>
<p>This is the first line of the output of the following command:</p>
<pre><code class="language-terminal">$ openssl x509 -subject_hash_old -in ~/.mitmproxy/mitmproxy-ca-cert.pem
a8990c1d
</code></pre>
<p>Next we create an overlay directory in Waydroid:</p>
<pre><code class="language-terminal">$ sudo mkdir -p /var/lib/waydroid/overlay/system/etc/security/cacerts/
</code></pre>
<p><code>-p</code> is used to create the parent directories if they don’t exist.</p>
<p>And we copy the certificate in the overlay directory:</p>
<pre><code class="language-terminal">$ sudo cp ~/.mitmproxy/mitmproxy-ca-cert.pem /var/lib/waydroid/overlay/system/etc/security/cacerts/a8990c1d.0
$ sudo chmod 644 /var/lib/waydroid/overlay/system/etc/security/cacerts/a8990c1d.0
</code></pre>
<p>Pay attention to the extension of the certificate. It must be <code>.0</code> and the file name must be the hash of the certificate.</p>
<h1 id="remove-the-proxy">Remove the proxy</h1>
<pre><code class="language-terminal">adb shell settings put global http_proxy :0
</code></pre>
<p><a href="/android/Use-Proxy-With-Waydroid">Use a proxy with Waydroid</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on January 09, 2024.</p>
/python/projects/Oreille
/python/projects/Oreille2023-10-13T00:00:00+02:002023-10-13T00:00:00+02:00Julien Duponchellejulien@duponchelle.info<p>A small week end project: Oreille is a wrapper on OpenAPI Whisper API. It provides support for long audio files.</p>
<p>OpenAPI Whisper support only files that are less than 25 MB. Oreille will break the audio file into chunks of 25 MB’s or less. https://platform.openai.com/docs/guides/speech-to-text/longer-inputs</p>
<p>Oreille will also compute the correct timing of the subtitle when merging the output of Whisper. So once you export the subtitle the timestamp of the subtitle will be right.</p>
<p>You can open and save WAV files with pure python. For opening and saving non-wav files – like mp3 – you’ll need ffmpeg or libav.</p>
<p><a href="https://github.com/julien-duponchelle/oreille">View project on Github</a></p>
<p><a href="/python/projects/Oreille">Oreille</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on October 13, 2023.</p>
/network/How-an-HTTP-proxy-work
/network/How-an-HTTP-proxy-work2023-10-13T00:00:00+02:002023-10-13T00:00:00+02:00Julien Duponchellejulien@duponchelle.info<p>The goal of this article is to explain how a minimal HTTP/HTTPS proxy work.</p>
<h1 id="http">HTTP</h1>
<p>For an HTTP proxy the communication is simple the client etablish a TCP connection to the proxy and send the HTTP request. The proxy will parse the HTTP request and forward it to the server. The server will reply with the HTTP response and the proxy will forward it to the client.</p>
<p>The main difference is the method will be followed by the full URL of the target server.</p>
<pre><code class="language-http">GET http://www.example.org/index HTTP/1.1
Host: example.org:443
</code></pre>
<h1 id="https">HTTPS</h1>
<p>When the client open the connection to the proxy he will send the <em>CONNECT</em> HTTP method followed by the host and port of the target server.</p>
<p>It’s a classic HTTP request with headers. The proxy will stop to parse once it has read the double CRLF.</p>
<pre><code class="language-http">CONNECT example.org:443 HTTP/1.1
Host: example.org:443
</code></pre>
<p>The proxy will reply with the status 200:</p>
<pre><code class="language-http">HTTP/1.1 200 OK
</code></pre>
<p>Now we have a bidirectional tunnel between the client and the server. The proxy in the middle will just forward the data and is not going to be able to read it.</p>
<p>The client will now send the TLS handshake to the server and the server will reply with the TLS handshake. Once it’s done the communication is etablished and the client can send the HTTP request to the server.</p>
<p><a href="/network/How-an-HTTP-proxy-work">How an HTTP/HTTPS proxy work</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on October 13, 2023.</p>
/python/jsonapidoc
/python/jsonapidoc2018-06-02T00:00:00+02:002018-06-02T00:00:00+02:00Julien Duponchellejulien@duponchelle.info<p>JSON Api Doc une petite bibliothèque Open Source que j’ai publiée.</p>
<p>En manipulant des API en JSON API une chose m’a beaucoup gêné. L’utilisation des included pour éviter de dupliquer les données rend la lecture très difficile par un humain.</p>
<p>Cette bibliothèque utilisable dans un programme Python ou en cli permet tout simplement de résoudre les included et de renvoyer un objet plus simple à lire et à manipuler par un humain.</p>
<p>Par exemple:</p>
<pre><code class="language-json">{
"data": [{
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON API paints my bikeshed!",
"body": "The shortest article. Ever.",
"created": "2015-05-22T14:56:29.000Z",
"updated": "2015-05-22T14:56:28.000Z"
},
"relationships": {
"author": {
"data": {"id": "42", "type": "people"}
}
}
}],
"included": [
{
"type": "people",
"id": "42",
"attributes": {
"name": "John",
"age": 80,
"gender": "male"
}
}
]
}
</code></pre>
<p>Donnera:</p>
<pre><code class="language-json">[
{
"type": "articles",
"id": "1",
"title": "JSON API paints my bikeshed!",
"body": "The shortest article. Ever.",
"created": "2015-05-22T14:56:29.000Z",
"updated": "2015-05-22T14:56:28.000Z",
"author": {
"type": "people",
"id": "42",
"name": "John",
"age": 80,
"gender": "male"
}
}
]
</code></pre>
<p>Le code est disponible sur <a href="https://github.com/julien-duponchelle/json-api-doc/">GitHub</a></p>
<p><a href="/python/jsonapidoc">JSONApiDoc</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on June 02, 2018.</p>
/python/detect-python-code-duplicate
/python/detect-python-code-duplicate2016-12-18T00:00:00+01:002016-12-18T00:00:00+01:00Julien Duponchellejulien@duponchelle.info<p>You can detect Python code duplicate with <a href="https://www.pylint.org/">Pylint</a></p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>pylint<span class="w"> </span>--disable<span class="o">=</span>all<span class="w"> </span>--enable<span class="o">=</span>duplicate-code<span class="w"> </span>src/
No<span class="w"> </span>config<span class="w"> </span>file<span class="w"> </span>found,<span class="w"> </span>using<span class="w"> </span>default<span class="w"> </span>configuration
*************<span class="w"> </span>Module<span class="w"> </span>gns3server.compute.dynamips.nodes.ethernet_switch
R:<span class="w"> </span><span class="m">1</span>,<span class="w"> </span><span class="m">0</span>:<span class="w"> </span>Similar<span class="w"> </span>lines<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">2</span><span class="w"> </span><span class="nv">files</span>
<span class="o">==</span>gns3server.compute.dynamips.nodes.ethernet_hub:101
<span class="o">==</span>gns3server.compute.dynamips.nodes.ethernet_switch:136
<span class="w"> </span>@property
<span class="w"> </span>def<span class="w"> </span>mappings<span class="o">(</span>self<span class="o">)</span>:
<span class="w"> </span><span class="s2">"""</span>
<span class="s2"> Returns port mappings</span>
<span class="s2"> :returns: mappings list</span>
<span class="s2"> """</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span>self._mappings
<span class="w"> </span>@asyncio.coroutine
<span class="w"> </span>def<span class="w"> </span>delete<span class="o">(</span>self<span class="o">)</span>:
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="o">(</span>yield<span class="w"> </span>from<span class="w"> </span>self.close<span class="o">())</span>
<span class="w"> </span>@asyncio.coroutine
<span class="w"> </span>def<span class="w"> </span>close<span class="o">(</span>self<span class="o">)</span>:
<span class="w"> </span><span class="s2">"""</span>
<span class="s2"> Deletes this hub.</span>
<span class="s2"> """</span>
<span class="w"> </span><span class="o">(</span>duplicate-code<span class="o">)</span>
R:<span class="w"> </span><span class="m">1</span>,<span class="w"> </span><span class="m">0</span>:<span class="w"> </span>Similar<span class="w"> </span>lines<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">2</span><span class="w"> </span><span class="nv">files</span>
<span class="o">==</span>gns3server.compute.dynamips.nodes.ethernet_hub:66
<span class="o">==</span>gns3server.compute.dynamips.nodes.ethernet_switch:72
<span class="w"> </span>@property
<span class="w"> </span>def<span class="w"> </span>ports_mapping<span class="o">(</span>self<span class="o">)</span>:
<span class="w"> </span><span class="s2">"""</span>
<span class="s2"> Ports on this hub</span>
<span class="s2"> :returns: ports info</span>
<span class="s2"> """</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span>self._ports
<span class="w"> </span>@ports_mapping.setter
<span class="w"> </span>def<span class="w"> </span>ports_mapping<span class="o">(</span>self,<span class="w"> </span>ports<span class="o">)</span>:
<span class="w"> </span><span class="s2">"""</span>
<span class="s2"> Set the ports on this hub</span>
<span class="s2"> :param ports: ports info</span>
<span class="s2"> """</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span>ports<span class="w"> </span>!<span class="o">=</span><span class="w"> </span>self._ports:<span class="w"> </span><span class="o">(</span>duplicate-code<span class="o">)</span>
<span class="nv">Report</span>
<span class="o">======</span>
<span class="m">231</span><span class="w"> </span>statements<span class="w"> </span>analysed.
Statistics<span class="w"> </span>by<span class="w"> </span><span class="nb">type</span>
------------------
+---------+-------+-----------+-----------+------------+---------+
<span class="p">|</span><span class="nb">type</span><span class="w"> </span><span class="p">|</span>number<span class="w"> </span><span class="p">|</span>old<span class="w"> </span>number<span class="w"> </span><span class="p">|</span>difference<span class="w"> </span><span class="p">|</span>%documented<span class="w"> </span><span class="p">|</span>%badname<span class="w"> </span><span class="p">|</span>
+<span class="o">=========</span>+<span class="o">=======</span>+<span class="o">===========</span>+<span class="o">===========</span>+<span class="o">============</span>+<span class="o">=========</span>+
<span class="p">|</span>module<span class="w"> </span><span class="p">|</span><span class="m">2</span><span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>
+---------+-------+-----------+-----------+------------+---------+
<span class="p">|</span>class<span class="w"> </span><span class="p">|</span><span class="m">2</span><span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>
+---------+-------+-----------+-----------+------------+---------+
<span class="p">|</span>method<span class="w"> </span><span class="p">|</span><span class="m">0</span><span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span><span class="m">0</span><span class="w"> </span><span class="p">|</span><span class="m">0</span><span class="w"> </span><span class="p">|</span>
+---------+-------+-----------+-----------+------------+---------+
<span class="p">|</span><span class="k">function</span><span class="w"> </span><span class="p">|</span><span class="m">0</span><span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span><span class="m">0</span><span class="w"> </span><span class="p">|</span><span class="m">0</span><span class="w"> </span><span class="p">|</span>
+---------+-------+-----------+-----------+------------+---------+
Raw<span class="w"> </span>metrics
-----------
+----------+-------+------+---------+-----------+
<span class="p">|</span><span class="nb">type</span><span class="w"> </span><span class="p">|</span>number<span class="w"> </span><span class="p">|</span>%<span class="w"> </span><span class="p">|</span>previous<span class="w"> </span><span class="p">|</span>difference<span class="w"> </span><span class="p">|</span>
+<span class="o">==========</span>+<span class="o">=======</span>+<span class="o">======</span>+<span class="o">=========</span>+<span class="o">===========</span>+
<span class="p">|</span>code<span class="w"> </span><span class="p">|</span><span class="m">304</span><span class="w"> </span><span class="p">|</span><span class="m">48</span>.95<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>
+----------+-------+------+---------+-----------+
<span class="p">|</span>docstring<span class="w"> </span><span class="p">|</span><span class="m">167</span><span class="w"> </span><span class="p">|</span><span class="m">26</span>.89<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>
+----------+-------+------+---------+-----------+
<span class="p">|</span>comment<span class="w"> </span><span class="p">|</span><span class="m">34</span><span class="w"> </span><span class="p">|</span><span class="m">5</span>.48<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>
+----------+-------+------+---------+-----------+
<span class="p">|</span>empty<span class="w"> </span><span class="p">|</span><span class="m">116</span><span class="w"> </span><span class="p">|</span><span class="m">18</span>.68<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>
+----------+-------+------+---------+-----------+
Duplication
-----------
+-------------------------+-------+---------+-----------+
<span class="p">|</span><span class="w"> </span><span class="p">|</span>now<span class="w"> </span><span class="p">|</span>previous<span class="w"> </span><span class="p">|</span>difference<span class="w"> </span><span class="p">|</span>
+<span class="o">=========================</span>+<span class="o">=======</span>+<span class="o">=========</span>+<span class="o">===========</span>+
<span class="p">|</span>nb<span class="w"> </span>duplicated<span class="w"> </span>lines<span class="w"> </span><span class="p">|</span><span class="m">87</span><span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>
+-------------------------+-------+---------+-----------+
<span class="p">|</span>percent<span class="w"> </span>duplicated<span class="w"> </span>lines<span class="w"> </span><span class="p">|</span><span class="m">14</span>.100<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>
+-------------------------+-------+---------+-----------+
Messages<span class="w"> </span>by<span class="w"> </span>category
--------------------
+-----------+-------+---------+-----------+
<span class="p">|</span><span class="nb">type</span><span class="w"> </span><span class="p">|</span>number<span class="w"> </span><span class="p">|</span>previous<span class="w"> </span><span class="p">|</span>difference<span class="w"> </span><span class="p">|</span>
+<span class="o">===========</span>+<span class="o">=======</span>+<span class="o">=========</span>+<span class="o">===========</span>+
<span class="p">|</span>convention<span class="w"> </span><span class="p">|</span><span class="m">0</span><span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>
+-----------+-------+---------+-----------+
<span class="p">|</span>refactor<span class="w"> </span><span class="p">|</span><span class="m">7</span><span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>
+-----------+-------+---------+-----------+
<span class="p">|</span>warning<span class="w"> </span><span class="p">|</span><span class="m">0</span><span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>
+-----------+-------+---------+-----------+
<span class="p">|</span>error<span class="w"> </span><span class="p">|</span><span class="m">0</span><span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>NC<span class="w"> </span><span class="p">|</span>
+-----------+-------+---------+-----------+
%<span class="w"> </span>errors<span class="w"> </span>/<span class="w"> </span>warnings<span class="w"> </span>by<span class="w"> </span>module
-----------------------------
+--------------------------------------------------+------+--------+---------+-----------+
<span class="p">|</span>module<span class="w"> </span><span class="p">|</span>error<span class="w"> </span><span class="p">|</span>warning<span class="w"> </span><span class="p">|</span>refactor<span class="w"> </span><span class="p">|</span>convention<span class="w"> </span><span class="p">|</span>
+<span class="o">==================================================</span>+<span class="o">======</span>+<span class="o">========</span>+<span class="o">=========</span>+<span class="o">===========</span>+
<span class="p">|</span>gns3server.compute.dynamips.nodes.ethernet_switch<span class="w"> </span><span class="p">|</span><span class="m">0</span>.00<span class="w"> </span><span class="p">|</span><span class="m">0</span>.00<span class="w"> </span><span class="p">|</span><span class="m">100</span>.00<span class="w"> </span><span class="p">|</span><span class="m">0</span>.00<span class="w"> </span><span class="p">|</span>
+--------------------------------------------------+------+--------+---------+-----------+
Messages
--------
+---------------+------------+
<span class="p">|</span>message<span class="w"> </span>id<span class="w"> </span><span class="p">|</span>occurrences<span class="w"> </span><span class="p">|</span>
+<span class="o">===============</span>+<span class="o">============</span>+
<span class="p">|</span>duplicate-code<span class="w"> </span><span class="p">|</span><span class="m">7</span><span class="w"> </span><span class="p">|</span>
+---------------+------------+
Global<span class="w"> </span>evaluation
-----------------
Your<span class="w"> </span>code<span class="w"> </span>has<span class="w"> </span>been<span class="w"> </span>rated<span class="w"> </span>at<span class="w"> </span><span class="m">9</span>.70/10</code></pre></figure>
<p><a href="/python/detect-python-code-duplicate">Detect Python code duplicate</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on December 18, 2016.</p>
/politique/un-os-souverain-mais-pourquoi
/politique/un-os-souverain-mais-pourquoi2016-01-24T00:00:00+01:002016-01-24T00:00:00+01:00Julien Duponchellejulien@duponchelle.info<p>La discussion sur le système d’exploitation souverain est devenue une blague sur internet tellement cette proposition parait absurde. Mais ce qui n’était au début qu’un amendement a était adopté par les députés. La blague pourrait au final coûter au citoyen. Même si elle part probablement d’un bon sentiment.</p>
<h1 id="cest-quoi-un-système-dexploitation">C’est quoi un système d’exploitation?</h1>
<p>Le système d’exploitation c’est grosso modo la couche logicielle entre le matériel et vos applications.
C’est donc indispensable et incontournable. Les systèmes les plus connus sont Windows, MacOSX, Linux pour les PC de bureau et IOS et Android pour les téléphones portables.</p>
<h1 id="on-veut-changer-quoi">On veut changer quoi?</h1>
<p>L’amendement adopté au parlement:</p>
<blockquote>
<p>Le Gouvernement remet au Parlement,dans les trois mois suivant la promulgation de la présente loi, un rapport sur la possibilité de créer un Commissariat à la souveraineté numérique rattaché aux services du Premier ministre dont les missions concourront à l’exercice, dans le cyberespace, de la souveraineté nationale et des droits et libertés individuels et collectifs que la République protège. Ce rapport précise les conditions de mise en place, sous l’égide de ce Commissariat, d’un système d’exploitation souverain et de protocoles de chiffrement des données, ainsi que les moyens et l’organisation nécessaires au fonctionnement de cet établissement public. ».</p>
</blockquote>
<p>Mais le début de l’exposé sommaire nous renseigne plus:</p>
<blockquote>
<p>La guerre contre le terrorisme, mais aussi l’urgente nécessité de protéger dans le cyberespace les droits et libertés des citoyens alors qu’une récente décision de la Cour de Justice de l’Union Européenne a prouvé que leurs données à caractère personnel étaient exploitées en toute illégalité, appellent de la part de la représentation nationale une prise de conscience nouvelle sur les enjeux liés à l’exercice de la souveraineté de la France dans le domaine du numérique.</p>
</blockquote>
<p>On a ici deux choses:</p>
<ul>
<li>La guerre contre le terrorisme</li>
<li>Les données à caractère personnel</li>
</ul>
<p>Le détail complet est ici: <a href="http://www.assemblee-nationale.fr/14/amendements/3318/CION_LOIS/CL129.asp">http://www.assemblee-nationale.fr/14/amendements/3318/CION_LOIS/CL129.asp</a></p>
<h2 id="la-guerre-contre-le-terrorisme">La guerre contre le terrorisme</h2>
<p>C’est le premier point de l’exposé sommaire. Puisqu’à priori Google, Apple ou Microsoft ne sont pas des entreprises terroristes quel risque court-on? Et bien il se trouve que ces sociétés aient tendance à trop bien protéger nos données avec des systèmes ou seul l’utilisateur à accès. Et que même si un ingénieur de Apple voulait lire le contenu chiffré de votre téléphone il ne pourrait pas. On pourrait donc voir cette tentative de système souverain comme une volonté d’accéder à nos données par l’État.</p>
<p>Pour être efficace, il faudrait donc que les terroristes acceptent de remplacer leurs ordinateurs par des versions françaises. Autant dire que cela n’arrivera pas. D’autant plus qu’ils disposent déjà de logiciels leur permettant de chiffrer les communications sans faire confiance au chiffrement mis en place par Apple, Google ou Microsoft.</p>
<p>Et quant à l’imposer, cela reviendrait à un désastre économique qui isolerait la France du reste du monde numérique.
Imaginez vous être obligé d’acheter un téléphone français fait uniquement pour le marché français. Et le cauchemar pour les entreprises obligées d’utiliser un système différent en fonction du pays.</p>
<h2 id="les-données-à-caractère-personnel">Les données à caractère personnel</h2>
<p>Un certain nombre de ces systèmes sont fermés et pourrait contenir des portes dérobées pour le gouvernement américain. Par ailleurs, les entreprises qui les exploitent peuvent utiliser ces données sans l’accord des personnes.</p>
<p>Mais ce n’est pas le cas de Linux ou d’Android si l’on prend un dérivé. En effet le logiciel libre nous permet d’auditer le code source. On a donc déjà des solutions que l’on pourrait promouvoir.</p>
<p>Et les données personnelles doivent être protégées par la loi, quelle que soit la couche concernée. Il serait absurde que l’on empêche Google d’accéder aux données de votre téléphone via le système, mais que de toute façon il lise vos emails via Gmail.
Cela passe donc par des lois et non des solutions techniques. D’ailleurs la loi discutée à l’Assemblée renforce très fortement les pouvoirs de sanction de la CNIL.</p>
<h1 id="qui-fait-cela">Qui fait cela?</h1>
<p>Peu de pays ont essayé. L’exemple le plus connu est celui de la Corée du Nord avec Red Star OS: <a href="https://fr.wikipedia.org/wiki/Red_Star_OS">https://fr.wikipedia.org/wiki/Red_Star_OS</a></p>
<h1 id="pourquoi-il-ne-faut-pas-essayer">Pourquoi il ne faut pas essayer?</h1>
<p>Après tout quel mal il y aurait a essayer de faire un système pour les gens qui veulent et nos administrations?</p>
<p>C’est un gouffre financier. La précédente tentative de cloud souverain s’est soldée par 150 millions d’euros d’argent public gaspillé. Et c’est sans compter le tort causé aux sociétés françaises qui était déjà sur ce marché.</p>
<p>Tout ce qui reste c’est cette publicité:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/E4jGYHmkaz0" frameborder="0" allowfullscreen=""></iframe>
<p>Le numérique en plus n’a pas besoin de grand projet pour créer de l’emploi, financer un projet ne participe pas à la relance de l’économie.</p>
<p><a href="http://www.lesechos.fr/idees-debats/editos-analyses/0204173981400-cloud-souverain-un-gachis-a-la-francaise-1096130.php">http://www.lesechos.fr/idees-debats/editos-analyses/0204173981400-cloud-souverain-un-gachis-a-la-francaise-1096130.php</a></p>
<p>Si le projet démarre de zéro Numerama à estimé le coût à 1 milliard d’euros. Ce qui me parait sous-estimé compte tenu de la complexité de l’opération.</p>
<p><a href="http://www.numerama.com/business/139709-developper-un-os-souverain-combien-cela-coute.html">http://www.numerama.com/business/139709-developper-un-os-souverain-combien-cela-coute.html</a></p>
<p>Même si à priori la volonté serait de se baser sur un Linux. Mais quel intérêt face à l’existant ?</p>
<p>Certains diront que pour le moment on engage peu de dépense vu que ce n’est qu’un rapport. Mais cela aura déjà un coût pour la société et le rapport pourrait déboucher sur un nouveau fiasco.</p>
<h1 id="mais-alors-on-peut-faire-quoi">Mais alors on peut faire quoi?</h1>
<p>A ma modeste échelle j’ai trois propositions.</p>
<p>Tout d’abord, on priorise le logiciel libre qui est une solution déjà existante et peu couteuse économiquement. Et l’on a la capacité de les auditer pour vérifier qu’il n’existe pas de portes dérobées au profit des USA.</p>
<p>Cela passe d’abord par l’administration, en effet comment parler de souveraineté quand l’éducation nationale signe des accords avec Microsoft pour utiliser ses services de clouds.
<a href="http://www.education.gouv.fr/cid96030/numerique-a-l-ecole-partenariat-entre-le-ministere-de-l-education-nationale-et-microsoft.html">http://www.education.gouv.fr/cid96030/numerique-a-l-ecole-partenariat-entre-le-ministere-de-l-education-nationale-et-microsoft.html</a></p>
<p>Ou l’assemblée nationale qui utilise Microsoft Exchange pour ses emails: <a href="http://www2.assemblee-nationale.fr/decouvrir-l-assemblee/role-et-pouvoirs-de-l-assemblee-nationale/l-administration-de-l-assemblee-nationale/l-informatique-a-l-assemblee-nationale">http://www2.assemblee-nationale.fr/decouvrir-l-assemblee/role-et-pouvoirs-de-l-assemblee-nationale/l-administration-de-l-assemblee-nationale/l-informatique-a-l-assemblee-nationale</a></p>
<p>Mais cela l’assemblée l’a refusé malgré le fait que c’était la proposition la plus soutenue lors de la consultation publique.
<a href="https://www.april.org/les-debats-ne-font-que-commencer-autour-de-la-priorite-au-logiciel-libre-dans-la-loi">https://www.april.org/les-debats-ne-font-que-commencer-autour-de-la-priorite-au-logiciel-libre-dans-la-loi</a></p>
<p>Deuxièment la CNIL doit sanctionner ceux qui viole la vie privée et là-dessus la loi république numérique va dans le bon sens en augmentant le pouvoir de sanction de la CNIL.</p>
<p>Troisièment, on mène des actions d’abus de position dominante au niveau européen pour que les géants ne puissent plus imposer arbitrairement leurs règles. Le système des stores pose notamment des problèmes de libre concurrence.</p>
<h1 id="mais-pourquoi-perdre-du-temps-à-écrire-là-dessus">Mais pourquoi perdre du temps à écrire là dessus?</h1>
<p>Lors de la création du cloud souverain, on a rigolé, mais au final c’est passé et 150 millions
d’euros se sont évaporés et les copains des dirigeants qui se sont enrichis. On doit être méfiant
pour éviter un nouveau Cloud Watt.</p>
<h1 id="pour-continuer">Pour continuer</h1>
<p>L’excellent article de monsieur Bortzmeyer <a href="http://www.bortzmeyer.org/os-souverain.html">http://www.bortzmeyer.org/os-souverain.html</a></p>
<p><a href="/politique/un-os-souverain-mais-pourquoi">Un système d'exploitation souverain mais pourquoi?</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on January 24, 2016.</p>
/development/why-sourceforge-should-not-die-today
/development/why-sourceforge-should-not-die-today2015-07-19T00:00:00+02:002015-07-19T00:00:00+02:00Julien Duponchellejulien@duponchelle.info<p>With the <a href="http://sourceforge.net/blog/sourceforge-infrastructure-and-service-restoration/">recent downtime of SourceForge</a> we can read comment like:</p>
<ul>
<li>Sourceforge should die</li>
<li>Someone still use sourceforge?</li>
<li>Sourceforge is a place with only malware</li>
<li>All active projects are already on Github</li>
<li>Nobody will notice if Sourceforge disapear</li>
</ul>
<p>It’s wrong. If sourceforge disapear the transition will be annoying.</p>
<p>Sourceforge exist since a long time and even if we don’t know
a lot of project still use it especially for the download mirror service.
Some are actively maintain and can move, but some are abandoned and
will be lost forever even if they still have users.</p>
<p>You disagree with me?</p>
<p>Take a look on where Homebrew formula download their source code or patches.</p>
<ul>
<li>We have 3157 formula</li>
<li>527 formulas use downloads.sourceforge.net (<code>grep ".*url.*downloads.sourceforge.net" * | cut -d":" -f1|sort|uniq|wc -l</code>)</li>
<li>888 use Github (<code>grep ".*url.*https://github.com/" * | cut -d":" -f1|sort|uniq|wc -l</code>)</li>
<li>113 for google code (<code>grep ".*url.*googlecode.com" * | cut -d":" -f1|sort|uniq|wc -l</code>)</li>
</ul>
<p>Even if it’s not the majority we can’t say we can just ignore it.</p>
<p>But it’s only dead and unused project.</p>
<p>If we have a quick look on the list of this minor/dead project. We can found some pretty common software:</p>
<ul>
<li>avidemux</li>
<li>boost</li>
<li>clamav</li>
<li>gnuplot</li>
<li>lame</li>
<li>netcat</li>
<li>pngcrush</li>
<li>proguard</li>
<li>privoxy</li>
<li>pwgen</li>
<li>swig</li>
<li>w3m</li>
<li>wxpython</li>
<li>zsh</li>
</ul>
<p>And homebrew contain only project working on OSX and where someone has taken the time to package it.</p>
<p>We can survive to a lost of sourceforge website for the downloads, thanks to large number a sourceforge mirror. But for source repository, mailling list archive all of this can be lost. If SourceForge die for financial issues a risk exists that the investors will try to sell this archives instead of transferring for free to a foundation like Apache or Mozilla.</p>
<p>Also if tomorrow sourceforge die, how can you be sure that the github repository of a sourceforge project
is made by the same team?</p>
<p>We need to prepare a smooth transition from Sourceforge. Why the parent compagnie of Sourceforge should continue to put money on a dying website? They are a for profit organization. In my mind the best solution is transfering a read only version to a non profit organisation. And because the same issue could happen with GitHub we need to work to decentralize free software hosting. It’s critical for the Free Software world, but also for all compagnies using this technologies.</p>
<p>Photo: <a href="https://www.flickr.com/photos/g205/441858611/in/photolist-F3DaV-56Qisy-kppUf-8RnjyQ-doCT9D-5Wdgfv-e21zdE-ay5H9m-kuycE-d7Ls2-qvN7uu-9tbfi4-a2WeSj-74UGdA-8sCFkr-dAqPou-oQXGDW-7C6y7P-dox9yH-7oRKgP-ayqvZp-eTfAR3-5pfbYE-8Pq6hV-5nLjQG-8Pgsna-4XrDYP-7aahLv-9UNwi2-cfpwVU-8KU8Mq-5YmvbW-qxEjEf-69uCzG-87TeE-8PjYNs-qxEiX3-aZkBGa-kppiR-aByh3A-aMzXCe-8ES8fo-vMw7w-6mBdsA-5jWuRm-8A66LN-6ize3M-ikeMty-8FCLy5-pxRmgG">Mark Lobo Licence CC BY-NC-ND 2.0</a></p>
<p><a href="/development/why-sourceforge-should-not-die-today">Why SourceForge should not die today</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on July 19, 2015.</p>
/development/reverse-on-osx
/development/reverse-on-osx2015-05-11T00:00:00+02:002015-05-11T00:00:00+02:00Julien Duponchellejulien@duponchelle.info<p>This articles is a simple collection of programm I use
for understanding how a third party programm interact with
the system.</p>
<h1 id="list-symbols-of-a-binary">List symbols of a binary</h1>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>nm<span class="w"> </span>-g<span class="w"> </span>/bin/ls
<span class="w"> </span>U<span class="w"> </span>__DefaultRuneLocale
<span class="w"> </span>U<span class="w"> </span>___assert_rtn
<span class="w"> </span>U<span class="w"> </span>___bzero
<span class="w"> </span>U<span class="w"> </span>___error
<span class="w"> </span>U<span class="w"> </span>___maskrune
<span class="w"> </span>U<span class="w"> </span>___snprintf_chk
<span class="w"> </span>U<span class="w"> </span>___stack_chk_fail
<span class="w"> </span>U<span class="w"> </span>___stack_chk_guard</code></pre></figure>
<p># Show shared libraries used by a programm</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>otool<span class="w"> </span>-L<span class="w"> </span>/bin/ls
/bin/ls:
<span class="w"> </span>/usr/lib/libutil.dylib<span class="w"> </span><span class="o">(</span>compatibility<span class="w"> </span>version<span class="w"> </span><span class="m">1</span>.0.0,<span class="w"> </span>current<span class="w"> </span>version<span class="w"> </span><span class="m">1</span>.0.0<span class="o">)</span>
<span class="w"> </span>/usr/lib/libncurses.5.4.dylib<span class="w"> </span><span class="o">(</span>compatibility<span class="w"> </span>version<span class="w"> </span><span class="m">5</span>.4.0,<span class="w"> </span>current<span class="w"> </span>version<span class="w"> </span><span class="m">5</span>.4.0<span class="o">)</span>
<span class="w"> </span>/usr/lib/libSystem.B.dylib<span class="w"> </span><span class="o">(</span>compatibility<span class="w"> </span>version<span class="w"> </span><span class="m">1</span>.0.0,<span class="w"> </span>current<span class="w"> </span>version<span class="w"> </span><span class="m">1213</span>.0.0<span class="o">)</span></code></pre></figure>
<h1 id="get-asm-code">Get asm code</h1>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>otool<span class="w"> </span>-vt<span class="w"> </span>/bin/ls</code></pre></figure>
<h1 id="list-open-file-and-network-connections">List open file and network connections</h1>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>lsof
COMMAND<span class="w"> </span>PID<span class="w"> </span>USER<span class="w"> </span>FD<span class="w"> </span>TYPE<span class="w"> </span>DEVICE<span class="w"> </span>SIZE/OFF<span class="w"> </span>NODE<span class="w"> </span>NAME
launchd<span class="w"> </span><span class="m">1</span><span class="w"> </span>root<span class="w"> </span>cwd<span class="w"> </span>DIR<span class="w"> </span><span class="m">1</span>,2<span class="w"> </span><span class="m">1224</span><span class="w"> </span><span class="m">2</span><span class="w"> </span>/
launchd<span class="w"> </span><span class="m">1</span><span class="w"> </span>root<span class="w"> </span>txt<span class="w"> </span>REG<span class="w"> </span><span class="m">1</span>,2<span class="w"> </span><span class="m">304240</span><span class="w"> </span><span class="m">21153870</span><span class="w"> </span>/sbin/launchd</code></pre></figure>
<h1 id="based-on-dtrace">Based on Dtrace</h1>
<p>dtrace is a powerfull tools for reverse engineer</p>
<h2 id="iosnoop">iosnoop</h2>
<p>iosnoop is a live trace of disk/io</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>sudo<span class="w"> </span>iosnoop
<span class="w"> </span>UID<span class="w"> </span>PID<span class="w"> </span>D<span class="w"> </span>BLOCK<span class="w"> </span>SIZE<span class="w"> </span>COMM<span class="w"> </span>PATHNAME
<span class="w"> </span><span class="m">501</span><span class="w"> </span><span class="m">88892</span><span class="w"> </span>R<span class="w"> </span><span class="m">440836400</span><span class="w"> </span><span class="m">4096</span><span class="w"> </span>Google<span class="w"> </span>Chrome<span class="w"> </span>??/Cache/data_2
<span class="w"> </span><span class="m">501</span><span class="w"> </span><span class="m">88892</span><span class="w"> </span>R<span class="w"> </span><span class="m">420909232</span><span class="w"> </span><span class="m">4096</span><span class="w"> </span>Google<span class="w"> </span>Chrome<span class="w"> </span>??/Cache/data_0
<span class="w"> </span><span class="m">501</span><span class="w"> </span><span class="m">88892</span><span class="w"> </span>R<span class="w"> </span><span class="m">439174816</span><span class="w"> </span><span class="m">4096</span><span class="w"> </span>Google<span class="w"> </span>Chrome<span class="w"> </span>??/Cache/data_2</code></pre></figure>
<p>## opensnoop</p>
<p>Live trace file opening</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>sudo<span class="w"> </span>opensnoop<span class="w"> </span>-ve
STRTIME<span class="w"> </span>UID<span class="w"> </span>PID<span class="w"> </span>COMM<span class="w"> </span>FD<span class="w"> </span>ERR<span class="w"> </span>PATH
<span class="m">2015</span><span class="w"> </span>May<span class="w"> </span><span class="m">11</span><span class="w"> </span><span class="m">13</span>:51:00<span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="m">99</span><span class="w"> </span>DisplayLinkMana<span class="w"> </span><span class="m">6</span><span class="w"> </span><span class="m">0</span><span class="w"> </span>/Library/Application<span class="w"> </span>Support/DisplayLink/.dl.xml
<span class="m">2015</span><span class="w"> </span>May<span class="w"> </span><span class="m">11</span><span class="w"> </span><span class="m">13</span>:51:00<span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="m">99</span><span class="w"> </span>DisplayLinkMana<span class="w"> </span><span class="m">6</span><span class="w"> </span><span class="m">0</span><span class="w"> </span>/Library/Application<span class="w"> </span>Support/DisplayLink/.dl.xml</code></pre></figure>
<p>## execsnoop</p>
<p>Live trace program execution</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>sudo<span class="w"> </span>execsnoop
<span class="w"> </span>UID<span class="w"> </span>PID<span class="w"> </span>PPID<span class="w"> </span>ARGS
<span class="w"> </span><span class="m">501</span><span class="w"> </span><span class="m">52098</span><span class="w"> </span><span class="m">48099</span><span class="w"> </span>sudo</code></pre></figure>
<p>## druss</p>
<p>dtruss allow you to show all system calls. You can filter by binary with the -n options.</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>sudo<span class="w"> </span>dtruss<span class="w"> </span>-n<span class="w"> </span>ls
<span class="w"> </span>PID/THRD<span class="w"> </span>SYSCALL<span class="o">(</span>args<span class="o">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">return</span>
<span class="m">52383</span>/0x1e98b4:<span class="w"> </span>thread_selfid<span class="o">(</span>0x7FFF5B281460,<span class="w"> </span>0x7F93C18013F0,<span class="w"> </span>0x7F93C060A7D0<span class="o">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2005172</span><span class="w"> </span><span class="m">0</span>
<span class="m">52383</span>/0x1e98b4:<span class="w"> </span>csops<span class="o">(</span>0x0,<span class="w"> </span>0x0,<span class="w"> </span>0x7FFF5BF4FA08<span class="o">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="m">0</span>
<span class="m">52383</span>/0x1e98b4:<span class="w"> </span>issetugid<span class="o">(</span>0x0,<span class="w"> </span>0x0,<span class="w"> </span>0x7FFF5BF4FA08<span class="o">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="m">0</span></code></pre></figure>
<h2 id="errinfo">errinfo</h2>
<p>Show system calls errors</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>sudo<span class="w"> </span>errinfo
<span class="w"> </span>EXEC<span class="w"> </span>SYSCALL<span class="w"> </span>ERR<span class="w"> </span>DESC
<span class="w"> </span>iTerm<span class="w"> </span><span class="nb">read</span><span class="w"> </span><span class="m">35</span><span class="w"> </span>Resource<span class="w"> </span>temporarily<span class="w"> </span>unavailable
<span class="w"> </span>iTerm<span class="w"> </span><span class="nb">read</span><span class="w"> </span><span class="m">35</span><span class="w"> </span>Resource<span class="w"> </span>temporarily<span class="w"> </span>unavailable
<span class="w"> </span>iTerm<span class="w"> </span><span class="nb">read</span><span class="w"> </span><span class="m">35</span><span class="w"> </span>Resource<span class="w"> </span>temporarily<span class="w"> </span>unavailable</code></pre></figure>
<p><a href="/development/reverse-on-osx">Reverse on OSX</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on May 11, 2015.</p>
/python/migration-from-pyqt4-to-pyqt5
/python/migration-from-pyqt4-to-pyqt52015-04-28T00:00:00+02:002015-04-28T00:00:00+02:00Julien Duponchellejulien@duponchelle.info<p>The current <a href="http://www.gns3.com">GNS3</a> GUI interface use PyQT4. In order
to support the retina display we choose to move to PyQT5.</p>
<p>The move was not too complicated with the help of a small script.</p>
<p>You can see the complete list of PyQT4 / PyQT5 differences here: <a href="http://pyqt.sourceforge.net/Docs/PyQt5/pyqt4_differences.html">http://pyqt.sourceforge.net/Docs/PyQt5/pyqt4_differences.html</a></p>
<p>Actually most of recent distributions support PyQT5:</p>
<ul>
<li>Debian Jessie</li>
<li>Ubuntu 14.04 and later</li>
<li>Arch linux</li>
<li>Gentoo</li>
<li>Fedora 21 and later</li>
</ul>
<p>In all our code we already not directly include the PyQT4 module but our own qt module responsible of all the imports this save us the need to patch every files for changing the module.</p>
<p>An annoying point was the move from QtGui to QtWidgets of a lot of element. That’s
why we wrote a script finding all the call to QtGui and checking if the module as not move to QtWidgets. The clean syntax of Python allow us to write a naive script.</p>
<p>It’s very easy with this apply to each line of the file:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span></span><span class="k">if</span> <span class="s2">"QtGui."</span> <span class="ow">in</span> <span class="n">line</span><span class="p">:</span>
<span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">inspect</span><span class="o">.</span><span class="n">getmembers</span><span class="p">(</span><span class="n">QtWidgets</span><span class="p">):</span>
<span class="n">line</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"QtGui."</span> <span class="o">+</span> <span class="n">name</span><span class="p">,</span> <span class="s2">"QtWidgets."</span> <span class="o">+</span> <span class="n">name</span><span class="p">)</span></code></pre></figure>
<p>After that you need to import also QtWidgets. All our imports was like:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span></span><span class="kn">from</span> <span class="nn">.qt</span> <span class="kn">import</span> <span class="n">QtGui</span></code></pre></figure>
<p>It’s easy to patch it by code:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span></span><span class="k">if</span> <span class="n">line</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">"from "</span><span class="p">)</span> <span class="ow">and</span> <span class="s2">"import"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span> <span class="ow">and</span> <span class="s2">"QtGui"</span> <span class="ow">in</span> <span class="n">line</span> <span class="ow">and</span> <span class="ow">not</span> <span class="s2">"QtWidgets"</span> <span class="ow">in</span> <span class="n">line</span><span class="p">:</span>
<span class="n">line</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="o">+</span> <span class="s2">", QtWidgets</span><span class="se">\n</span><span class="s2">"</span></code></pre></figure>
<p>Thanks to the previous move to Python 3 fixing the call to parent classe was easy because we can replace:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span></span><span class="n">QtGui</span><span class="o">.</span><span class="n">QWidget</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span></code></pre></figure>
<p>By:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span></span><span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span></code></pre></figure>
<p>Our script detect the name of parent classes and replace it by super.</p>
<p>Thanks to the script most of our code was working after this. We just need to check
the script behavior by using git diff.</p>
<p>Also when using the app we have detected some issue. You need to know that method deprecated in QT5 are totaly removed in PyQT5. For us it was only a few calls.</p>
<p>Our patch script it’s specific for our code but can be a source of inspiration, if you want to use it you need to replace gns3 by your module. It’s also check if you haven’t a double <strong>init</strong> call:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span></span><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">inspect</span>
<span class="kn">from</span> <span class="nn">PyQt5</span> <span class="kn">import</span> <span class="n">QtWidgets</span>
<span class="k">class</span> <span class="nc">FilePatcher</span><span class="p">:</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">path</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_path</span> <span class="o">=</span> <span class="n">path</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_line_number</span> <span class="o">=</span> <span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_previous_line</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_line</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_parent_classes</span> <span class="o">=</span> <span class="p">[]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_qtwidgets_imported</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">def</span> <span class="nf">error</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"ERROR: </span><span class="si">{}</span><span class="s2">:</span><span class="si">{}</span><span class="s2"> </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_path</span><span class="p">,</span><span class="bp">self</span><span class="o">.</span><span class="n">_line_number</span><span class="p">,</span> <span class="n">msg</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">info</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span> <span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">):</span>
<span class="n">msg</span> <span class="o">=</span> <span class="n">msg</span> <span class="o">+</span> <span class="s2">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"INFO: </span><span class="si">{}</span><span class="s2">:</span><span class="si">{}</span><span class="s2"> </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_path</span><span class="p">,</span><span class="bp">self</span><span class="o">.</span><span class="n">_line_number</span><span class="p">,</span> <span class="n">msg</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">patch</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">out</span> <span class="o">=</span> <span class="s2">""</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_path</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">previous_line</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">for</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span> <span class="ow">in</span> <span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">():</span>
<span class="bp">self</span><span class="o">.</span><span class="n">fix_object_inheritance</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">get_parent_class</span><span class="p">()</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_previous_line</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">error_double_init</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">fix_qt_widgets</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">fix_init_with_self</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">fix_super_with_argument</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">fix_call_without_super</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">error_import_missing</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_line_number</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_previous_line</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span>
<span class="n">out</span> <span class="o">+=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_path</span><span class="p">,</span> <span class="s1">'w+'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">out</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">get_parent_class</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Extract parent class to self._parent_classes var"""</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">"class "</span><span class="p">):</span>
<span class="n">l</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s2">".*\((.*)\):"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">)</span>
<span class="k">if</span> <span class="n">l</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_parent_classes</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="bp">cls</span> <span class="ow">in</span> <span class="n">l</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">","</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_parent_classes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>
<span class="k">def</span> <span class="nf">fix_object_inheritance</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""In Python3 you no longer need to inherit from object"""</span>
<span class="k">if</span> <span class="s2">"(object):"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_line</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">"\(object\)"</span><span class="p">,</span> <span class="s2">""</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">error_double_init</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Detect double call to init and raise an error</span>
<span class="sd"> """</span>
<span class="k">if</span> <span class="s2">".__init__"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_previous_line</span> <span class="ow">and</span> <span class="s2">".__init__"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"Double init is no longer allowed"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">fix_super_with_argument</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Thanks to Python 3 now we can call super() instead of super(MyClassParent)</span>
<span class="sd"> """</span>
<span class="k">if</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s2">".*super\([^)].*"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_line</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">"super\([^)]+\)"</span><span class="p">,</span> <span class="s2">"super()"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"Fix "</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>
<span class="k">def</span> <span class="nf">fix_init_with_self</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> In some part of the code we have MyClassParent.__init__(self</span>
<span class="sd"> Now we can use super().__init__</span>
<span class="sd"> """</span>
<span class="k">if</span> <span class="s2">".__init__(self"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_line</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">"([A-Z\.a-z0-9_-]+)\.__init__\(self,? ?"</span><span class="p">,</span> <span class="s2">"super().__init__("</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">fix_call_without_super</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> We need to call parent with super instead of class name in order to avoid issues</span>
<span class="sd"> """</span>
<span class="k">for</span> <span class="bp">cls</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_parent_classes</span><span class="p">:</span>
<span class="n">m</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s2">"(.*)(</span><span class="si">{}</span><span class="s2">)\.([a-zA-Z]+)\((self, ? ?)(.*)"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">cls</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">)</span>
<span class="k">if</span> <span class="n">m</span><span class="p">:</span>
<span class="n">fixed</span> <span class="o">=</span> <span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="s2">"super()."</span> <span class="o">+</span> <span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="o">+</span> <span class="s2">"("</span> <span class="o">+</span> <span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="o">+</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_line</span> <span class="o">=</span> <span class="n">fixed</span>
<span class="k">def</span> <span class="nf">fix_qt_widgets</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Replace QtGui by QtWidgets when require</span>
<span class="sd"> """</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">"from "</span><span class="p">)</span> <span class="ow">and</span> <span class="s2">"import"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span> <span class="ow">and</span> <span class="s2">"QtGui"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span> <span class="ow">and</span> <span class="ow">not</span> <span class="s2">"QtWidgets"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_line</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="o">+</span> <span class="s2">", QtWidgets</span><span class="se">\n</span><span class="s2">"</span>
<span class="k">if</span> <span class="s2">"QtGui."</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">:</span>
<span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">inspect</span><span class="o">.</span><span class="n">getmembers</span><span class="p">(</span><span class="n">QtWidgets</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_line</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"QtGui."</span> <span class="o">+</span> <span class="n">name</span><span class="p">,</span> <span class="s2">"QtWidgets."</span> <span class="o">+</span> <span class="n">name</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">error_import_missing</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Check if we use QtWidgets without QtGui</span>
<span class="sd"> """</span>
<span class="k">if</span> <span class="s2">"QtWidgets"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">:</span>
<span class="k">if</span> <span class="s2">" import "</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_line</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_qtwidgets_imported</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_qtwidgets_imported</span> <span class="ow">is</span> <span class="kc">False</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"QtWidgets import missing"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">root</span><span class="p">,</span> <span class="n">dirs</span><span class="p">,</span> <span class="n">files</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="s1">'gns3'</span><span class="p">):</span>
<span class="k">for</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">files</span><span class="p">:</span>
<span class="k">if</span> <span class="n">file</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">'.py'</span><span class="p">):</span>
<span class="n">FilePatcher</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">file</span><span class="p">))</span><span class="o">.</span><span class="n">patch</span><span class="p">()</span>
</code></pre></figure>
<p><a href="/python/migration-from-pyqt4-to-pyqt5">Migration from PyQT4 to PyQT5 at GNS3</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on April 28, 2015.</p>
/lettre-%C3%A0-mon-d%C3%A9put%C3%A9
/lettre-à-mon-député2015-04-23T00:00:00+02:002015-04-23T00:00:00+02:00Julien Duponchellejulien@duponchelle.info<p>Monsieur le Député,</p>
<p>Suite à la lecture de votre article sur le projet de loi sur le renseignement: <a href="http://www.jeanluclaurent.fr/Liberticide_a423.html">http://www.jeanluclaurent.fr/Liberticide_a423.html</a></p>
<p>Je tenais à vous faire part de mes inquiétudes concernant ce texte et de mes désaccords.</p>
<p>En premier lieu, vous indiquez que vous ne légiférez pas dans l’urgence. Cette affirmation est fausse. En effet, le Gouvernement utilise la procédure accélérée réduisant la possibilité pour vous d’effectuer votre travail de parlementaire dans de bonnes conditions, en particulier sur un texte aussi technique.</p>
<p>En deuxième lieu, dans votre article vous affirmez que ce projet est précis. Or il y a un point sur lequel il y a un manque de précision, et ce de manière cruciale et que je formulerai sous forme de question : Quels sont les motifs de mise en place d’une surveillance ?</p>
<p>En effet le texte prévoit que les techniques de renseignements pourront être mises en oeuvre pour les motifs suivants:</p>
<p>• « 1° La sécurité nationale ;</p>
<p>• « 2° Les intérêts essentiels de la politique étrangère et l’exécution des engagements européens et internationaux de la France ;</p>
<p>• « 3° Les intérêts économiques et scientifiques essentiels de la France ;</p>
<p>• « 4° La prévention du terrorisme ;</p>
<p>• « 5° La prévention de la reconstitution ou du maintien de groupement dissous en application de l’article L. 212-1 ;</p>
<p>• « 6° La prévention de la criminalité et de la délinquance organisées ;</p>
<p>• « 7° La prévention des violences collectives de nature à porter gravement atteinte à la paix publique.</p>
<p>Si l’on peut être d’accord avec certains motifs, d’autres sont sujets à interrogations.</p>
<p>À titre d’illustration, d’après le point numéro deux, s’engager à l’encontre des engagements européens constituerait un motif valable de mise sous surveillance. Cela concernerait donc votre propre parti lorsque vous appelez à boycotter les élections européennes: <a href="http://www.mrc-france.org/Parlement-europeen-cette-election-derisoire-se-fera-sans-nous_a602.html">http://www.mrc-france.org/Parlement-europeen-cette-election-derisoire-se-fera-sans-nous_a602.html</a></p>
<p>Concernant le point numéro 3, nous pouvons légitimement nous poser la question de savoir en quoi les intérêts économiques de la France constituent un motif valable de mise sous surveillance. Ainsi, un militant, qui s’opposerait aux intérêts d’une grande multinationale française, pourrait être légalement surveillé.</p>
<p>Le point numéro 7 apparaît beaucoup trop flou, car toutes les manifestations politiques pourraient tomber sous ce motif.</p>
<p>Je n’affirme pas que ce gouvernement met en place une Police politique. Cependant, en manquant cruellement de précision, le législateur laisse aux Gouvernements suivants la possibilité d’utiliser la loi dans leurs propres intérêts. L’affaire des écoutes de l’Élysée démontre que ce risque est réel.</p>
<p>En troisième et dernier lieu, concernant la surveillance généralisée, puisque c’est bien de cela dont il est question, comme vous le soulignez, cela n’est pas efficace. Les fameuses boites noires vont concrètement surveiller tout le trafic sur le réseau pour identifier les comportements suspects.</p>
<p>Affirmer le contraire est soit un mensonge du gouvernement soit un aveu d’inefficacité. Le Gouvernement joue sur les mots en utilisant le terme de “meta données”. En effet, si l’algorithme secret défense du gouvernement ne lira effectivement pas notre email, en revanche, il saura avec qui et quand l’on communique, ainsi que les pages web que l’on consulte. Ce système livre déjà de façon systématique aux autorités des pans entiers de notre vie.</p>
<p>Aussi, je vous invite à ne pas me croire sur parole, mais à vous adresser aux milliers d’étudiants en informatique présents dans votre circonscription.</p>
<p>Par ailleurs, un tel système n’aurait permis d’éviter les évènements tragiques de janvier, où le problème n’était pas les moyens de renseignement disponibles ou le repérage de la menace, mais un manque de moyens humains des services. En outre, les terroristes sont déjà formés à contourner cette surveillance.</p>
<p>Enfin, je ne conteste pas que le citoyen pourra saisir le Conseil d’État en cas de dérive. Mais comment le pourrait-il, car il sera impossible pour lui de savoir que l’on a fait l’objet d’une surveillance particulière qui est par nature secrète ?</p>
<p>Et que risque un agent qui aurait abusé de son pouvoir ? La question demeure sans réponse.</p>
<p>L’impact économique sur votre circonscription est déjà là. L’hébergeur Gandi dont le siège est à 300 mètres d’Ivry à indiquer que dans ces conditions il se développerait à l’étranger.
<a href="http://fr.gandi.press/100409-loi-sur-le-renseignement-gandi-reste-mobilise">http://fr.gandi.press/100409-loi-sur-le-renseignement-gandi-reste-mobilise</a></p>
<p>L’année dernière, la ville du Kremlin-Bicêtre accueillait une exposition sur Jean Jaurès. Souvenez-vous de son combat contre les lois scélérates qui furent déjà en leur temps prises pour protéger les citoyens de leurs mauvaises pensées.</p>
<p>Veuillez agréer, Monsieur le Député, l’expression de mes sentiments respectueux.</p>
<p>Julien Duponchelle<br />
123 avenue de fontainebleau<br />
Le Kremlin-Bicêtre</p>
<p>Mise à jours le 25/04/2015:
Réponse de Monsieur Jean-Luc Laurent:
<a href="http://www.jeanluclaurent.fr/Loi-Renseignement-parlons-en_a432.html">http://www.jeanluclaurent.fr/Loi-Renseignement-parlons-en_a432.html</a></p>
<p><a href="/lettre-%C3%A0-mon-d%C3%A9put%C3%A9">Lettre à mon Député</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on April 23, 2015.</p>
/robot/developper-pour-jumping-sumo-parrot
/robot/developper-pour-jumping-sumo-parrot2015-02-25T00:00:00+01:002015-02-25T00:00:00+01:00Julien Duponchellejulien@duponchelle.info<p>Le Jumping Sumo de Parrot est un petit robot qui roule et peut sauter jusquà 80 cm de haut. Il est aussi
équipé d’une Webcam.</p>
<p><img src="/images/parrot/sumo.jpg" alt="Jumping Sumo" /></p>
<p>Voir sur amazon (lien d’affiliation):
<a href="http://www.amazon.fr/gp/product/B00KQPPH7A/ref=as_li_tl?ie=UTF8&camp=1642&creative=19458&creativeASIN=B00KQPPH7A&linkCode=as2&tag=julienduponc-21&linkId=X2MCB3ZDXTIBWKJJ">Parrot MiniDrone Jumping Sumo Noir</a><img src="http://ir-fr.amazon-adsystem.com/e/ir?t=julienduponc-21&l=as2&o=8&a=B00KQPPH7A" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p>J’en ai reçu un en décembre et après avoir un peu joué avec l’appli android avec j’ai décidé de jouer avec le SDK fournis
par Parrot.</p>
<p>Le SDK est en C, ce qui le rend assez facilement portable.</p>
<h1 id="installation-du-sdk">Installation du SDK</h1>
<p>Le SDK est disponible sur Github</p>
<pre><code>git clone https://github.com/ARDroneSDK3/ARSDKBuildUtils.git
</code></pre>
<p>Ensuite on va le compiler pour MacOS (des version IOS et Android sont disponible aussi, les instructions Mac devrait marcher sous Linux)</p>
<pre><code>./SDK3Build.py -t Unix
</code></pre>
<p>Cette commande va télécharger tous les dépots nécessaire au bon fonctionemment du SDK
et compiler ce dernier.</p>
<h1 id="compilation-des-examples">Compilation des examples</h1>
<h2 id="faire-bouger-le-jumping-sumo">Faire bouger le jumping sumo</h2>
<p>Un deuxième dépot avec des exemples est fournis:</p>
<pre><code>git clone https://github.com/ARDroneSDK3/Samples
</code></pre>
<p>Le premier avec lequel on va jouer: <em>Unix/JumpingSumoChangePosture</em>.</p>
<p>On va donc dans le répertoire et on va compiler avec l’aide Make</p>
<pre><code>make
</code></pre>
<p>Puis on se connecte en Wifi du Jumping Sumo
<img src="/images/parrot/wifi.png" alt="Jumping Sumo Wifi" /></p>
<p>On peut enfin lancer le programme que nous venons de compiler:</p>
<pre><code># ./JumpingSumoChangePosture
[INF] JumpingSumoChangePosture | 13:16:35:579 | main:134 - -- Jumping Sumo Change Posture --
[INF] JumpingSumoChangePosture | 13:16:35:580 | ardiscoveryConnect:195 - - ARDiscovery Connection
[INF] JumpingSumoChangePosture | 13:16:35:622 | startNetwork:227 - - Start ARNetwork
[INF] JumpingSumoChangePosture | 13:16:35:624 | sendPilotingPosture:341 - - Send Piloting Posture 2
[INF] JumpingSumoChangePosture | 13:16:37:624 | sendPilotingPosture:341 - - Send Piloting Posture 1
[INF] JumpingSumoChangePosture | 13:16:39:626 | stopNetwork:296 - - Stop ARNetwork
[INF] JumpingSumoChangePosture | 13:16:39:643 | main:186 - -- END --
</code></pre>
<p>Votre programme devrait localiser automatiquement votre Jumping Sumo sur le Wifi
et le faire bouger.</p>
<h2 id="récupérer-la-caméra">Récupérer la caméra</h2>
<p>Un deuxième exemple fournis pour le Jumping Sumo est la récupération du flux
de la caméra. Il se trouve dans le répertoire <em>JumpingSumoReceiveStream</em>.</p>
<p>De nouveau vous pouvez le compiler avec make:</p>
<pre><code>make
</code></pre>
<p>Pour afficher le flux il vous faut la commande ffplay ffplay:</p>
<pre><code>brew install ffmpeg --with-ffplay
</code></pre>
<p>De nouveau vous pouvez lancer le programme est vous admirer à travers
les yeux du Sumo.</p>
<p><img src="/images/parrot/camera.png" alt="Jumping Sumo Camera" /></p>
<h2 id="piloter-le-jumping-sumo">Piloter le Jumping Sumo</h2>
<p>Le dernier exemple permet de piloter le Jumping Sumo via une interface très
minimaliste en curses.</p>
<p><img src="/images/parrot/curses.png" alt="Jumping Sumo Curses" /></p>
<p>Avec cela combiné vous avez tout ce qu’il vous faut pour jouer sans être
olbiger d’utiliser les applis smartphone.</p>
<h1 id="la-documentation">La documentation</h1>
<p>Un dépot avec de la documentation existe:</p>
<pre><code>git clone https://github.com/ARDroneSDK3/Docs
</code></pre>
<p>Pour la liste des commandes disponibles vous pouvez regarder le fichier <em>ARSDKBuildUtils/Targets/Unix/Install/include/libARCommands/ARCOMMANDS_Types.h</em></p>
<h1 id="conclusion">Conclusion</h1>
<p>Parrot a fait du bon boulot pour la mise en oeuvre du SDK. A aucun moment je n’ai
été bloqué. Et après avoir lu tous les exemples on a tout ce qu’il faut pour créer.
Après on regrettera peut être que tous soit balancé sur Github et qu’on
ne ressente du coup pas l’envie d’en faire quelque chose de vraiment communautaire
(un site dédié à la documentation par exemple serait un plus).</p>
<p><a href="/robot/developper-pour-jumping-sumo-parrot">Développer pour le Jumping Sumo de Parrot sous Mac</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on February 25, 2015.</p>
/python/PEP8-Pre-Commit-Hook
/python/PEP8-Pre-Commit-Hook2015-01-26T00:00:00+01:002015-01-26T00:00:00+01:00Julien Duponchellejulien@duponchelle.info<p>This pre commit hook will check the PEP8 syntax of your Python files
and ask you if you want to continue the commit process.</p>
<p>In your project directory create a file: <em>.git/hooks/pre-commit</em> and
add the execution permission on it.</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="ch">#!/bin/bash</span>
<span class="nb">echo</span><span class="w"> </span><span class="s2">"Pre-commit started"</span>
<span class="nb">echo</span><span class="w"> </span><span class="s2">"PEP 8 check"</span>
git<span class="w"> </span>diff<span class="w"> </span>--cached<span class="w"> </span>--name-only<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>.py<span class="w"> </span><span class="p">|</span><span class="w"> </span>xargs<span class="w"> </span>pep8
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="nv">$?</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="o">]</span>
<span class="k">then</span>
<span class="w"> </span><span class="nb">exit</span><span class="w"> </span><span class="m">0</span>
<span class="k">fi</span>
<span class="c1"># Allows us to read user input below, assigns stdin to keyboard</span>
<span class="nb">exec</span><span class="w"> </span><<span class="w"> </span>/dev/tty
<span class="nb">echo</span><span class="w"> </span><span class="s2">"Do you want to ignore warning?"</span>
<span class="k">select</span><span class="w"> </span>yn<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="s2">"Yes"</span><span class="w"> </span><span class="s2">"No"</span><span class="p">;</span><span class="w"> </span><span class="k">do</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="nv">$yn</span><span class="w"> </span><span class="k">in</span>
<span class="w"> </span>Yes<span class="w"> </span><span class="o">)</span><span class="w"> </span><span class="nb">exit</span><span class="w"> </span><span class="m">0</span><span class="p">;;</span>
<span class="w"> </span>No<span class="w"> </span><span class="o">)</span><span class="w"> </span><span class="nb">exit</span><span class="w"> </span><span class="m">1</span><span class="p">;;</span>
<span class="w"> </span><span class="k">esac</span>
<span class="k">done</span></code></pre></figure>
<p><a href="/python/PEP8-Pre-Commit-Hook">PEP 8 Git pre commit hook</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on January 26, 2015.</p>
/python/Blocking-code-with-asyncio
/python/Blocking-code-with-asyncio2015-01-26T00:00:00+01:002015-01-26T00:00:00+01:00Julien Duponchellejulien@duponchelle.info<p>Asyncio is greats piece of software. But all Python code
is not compatible. In the following example we will see
how to run blocking code from your asyncio code.</p>
<p>We will by a simple asyncio application:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span></span><span class="kn">import</span> <span class="nn">asyncio</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="nd">@asyncio</span><span class="o">.</span><span class="n">coroutine</span>
<span class="k">def</span> <span class="nf">clock</span><span class="p">():</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Current time from asynchronous code: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())))</span>
<span class="k">yield from</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">loop</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span>
<span class="n">asyncio</span><span class="o">.</span><span class="k">async</span><span class="p">(</span><span class="n">clock</span><span class="p">())</span>
<span class="n">loop</span><span class="o">.</span><span class="n">run_forever</span><span class="p">()</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></code></pre></figure>
<p>The output is:</p>
<pre><code>Current time from asynchronous code: 1422265105
Current time from asynchronous code: 1422265106
</code></pre>
<p>And add blocking code:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span></span><span class="kn">import</span> <span class="nn">asyncio</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="nd">@asyncio</span><span class="o">.</span><span class="n">coroutine</span>
<span class="k">def</span> <span class="nf">clock</span><span class="p">():</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Current time from asynchronous code: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())))</span>
<span class="k">yield from</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">blocking</span><span class="p">():</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Current time from blocking code: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())))</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">loop</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span>
<span class="n">blocking</span><span class="p">()</span>
<span class="n">asyncio</span><span class="o">.</span><span class="k">async</span><span class="p">(</span><span class="n">clock</span><span class="p">())</span>
<span class="n">loop</span><span class="o">.</span><span class="n">run_forever</span><span class="p">()</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></code></pre></figure>
<p>The output is:</p>
<pre><code>Current time from blocking code: 1422265410
Current time from blocking code: 1422265411
Current time from blocking code: 1422265412
</code></pre>
<p>If you want to run blocking code in your asynchronous code you need
to run it in a different thread. Hopefully asyncio provide <a href="https://docs.python.org/3.4/library/asyncio-eventloop.html#asyncio.BaseEventLoop.run_in_executor">BaseEventLoop.run_in_executor</a> where you can execute code in a different executor. You can pass None in order to execute your code in the default executor: ThreadPoolExecutor.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span></span><span class="kn">import</span> <span class="nn">asyncio</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="nd">@asyncio</span><span class="o">.</span><span class="n">coroutine</span>
<span class="k">def</span> <span class="nf">clock</span><span class="p">():</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Current time from asynchronous code: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())))</span>
<span class="k">yield from</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">blocking</span><span class="p">():</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Current time from blocking code: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())))</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">loop</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span>
<span class="n">loop</span><span class="o">.</span><span class="n">run_in_executor</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">blocking</span><span class="p">)</span>
<span class="n">asyncio</span><span class="o">.</span><span class="k">async</span><span class="p">(</span><span class="n">clock</span><span class="p">())</span>
<span class="n">loop</span><span class="o">.</span><span class="n">run_forever</span><span class="p">()</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></code></pre></figure>
<p>The output is:</p>
<pre><code>Current time from blocking code: 1422265601
Current time from asynchronous code: 1422265601
Current time from blocking code: 1422265602
Current time from asynchronous code: 1422265602
Current time from blocking code: 1422265603
</code></pre>
<p>run_in_executor return a future and if an exception is raise your code
is not stopped you need to check the future. A dummy sample code for
stopping your code when something arrive:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span></span><span class="kn">import</span> <span class="nn">asyncio</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">concurrent</span>
<span class="nd">@asyncio</span><span class="o">.</span><span class="n">coroutine</span>
<span class="k">def</span> <span class="nf">clock</span><span class="p">():</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Current time from asynchronous code: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())))</span>
<span class="k">yield from</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">blocking</span><span class="p">():</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Current time from blocking code: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())))</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s2">"Test"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">loop</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span>
<span class="n">block</span> <span class="o">=</span> <span class="n">loop</span><span class="o">.</span><span class="n">run_in_executor</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">blocking</span><span class="p">)</span>
<span class="k">async</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="k">async</span><span class="p">(</span><span class="n">clock</span><span class="p">())</span>
<span class="n">loop</span><span class="o">.</span><span class="n">run_until_complete</span><span class="p">(</span><span class="n">asyncio</span><span class="o">.</span><span class="n">wait</span><span class="p">([</span><span class="n">block</span><span class="p">,</span> <span class="k">async</span><span class="p">],</span> <span class="n">return_when</span><span class="o">=</span><span class="n">concurrent</span><span class="o">.</span><span class="n">futures</span><span class="o">.</span><span class="n">FIRST_COMPLETED</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="n">block</span><span class="o">.</span><span class="n">exception</span><span class="p">())</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></code></pre></figure>
<p><a href="/python/Blocking-code-with-asyncio">Asyncio blocking code</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on January 26, 2015.</p>
/premier-jour-go
/premier-jour-go2014-05-31T00:00:00+02:002014-05-31T00:00:00+02:00Julien Duponchellejulien@duponchelle.info<p>Afin d’améliorer ma culture de développeur, j’ai décidé d’apprendre le GO,
qu’on voit de plus en plus pour des backend demandant de la performance.</p>
<p>Pour comprendre mon avis, il faut savoir que j’ai un profil de développeur backend
pour des startups. Je code en Ruby (y compris avec EventMachine) au travail depuis
plusieurs années, dans mes loisirs je fais du Python. J’ai pas mal joué avec Node.js
y a un an, mais je n’étais totalement satisfait par l’aspect déploiement et la stabilité.
J’ai aussi un bon background en C grâce à mes études à <a href="http://www.epitech.net">EPITECH</a>.</p>
<p>Voilà donc mes premiers retours après une journée de GO. J’ai choisi d’écrire pour
faire mes tests une application très simple qui va vérifier le DNS d’un grand nombre
de domaines en même temps.</p>
<p>Je retrouve le slogan de Python “fourni avec les piles”. En effet de base les développeurs
de GO fournissent pas mal d’outils de base pour la doc, les tests, le formatage du code,
gestion des dépendances…</p>
<p>#La syntaxe</p>
<p>La syntaxe contient quelques bizarreries pour nos esprits formatés, mais rien d’insurmontable.</p>
<p>Par exemple la déclaration d’une fonction:</p>
<figure class="highlight"><pre><code class="language-go" data-lang="go"><span></span><span class="kd">func</span><span class="w"> </span><span class="nx">TestDomain</span><span class="p">(</span><span class="nx">domain</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span>
<span class="p">}</span></code></pre></figure>
<p>Cela nous donne une fonction TestDomain qui prend en argument un domain de type string et
on retourne un bool.</p>
<p>Autre point qui parait bizarre au premier abord:</p>
<figure class="highlight"><pre><code class="language-go" data-lang="go"><span></span><span class="nx">a</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">1</span>
<span class="nx">a</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">2</span></code></pre></figure>
<p>L’opérateur <em>:=</em> est un raccourci pour déclarer et affecter une variable. En effet le compilateur
ne vous laisse pas utiliser une variable non déclarée.</p>
<p>On pourrait l’écrire ainsi:</p>
<figure class="highlight"><pre><code class="language-go" data-lang="go"><span></span><span class="kd">var</span><span class="w"> </span><span class="nx">a</span><span class="p">;</span>
<span class="nx">a</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">1</span>
<span class="nx">a</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">2</span></code></pre></figure>
<p>Point très positif pour moi, une commande <em>gofmt</em> est fournie avec le langage. Cela va reformater
votre code selon les normes en vigueur dans le monde du GO. Cela coupe court au débat sur l’indentation,
la place des parenthèses… Et on retrouve donc le confort de Python où deux codes sont formatés de la
même manière.</p>
<h1 id="vim">VIM</h1>
<p>Pas de problème de ce côté là j’ai installé <a href="https://github.com/fatih/vim-go">VIM-GO</a> qui fait le job:</p>
<ul>
<li>coloration syntaxique</li>
<li>vérification des erreurs de syntaxe</li>
<li>reformatage du code lorsqu’on sauvegarde avec gofmt</li>
</ul>
<p># Gestion de modules</p>
<p>Fournis de base avec le système vous pouvez téléchargez des modules (souvent hébergé sur Github).</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>go<span class="w"> </span>get<span class="w"> </span>github.com/noplay/madep</code></pre></figure>
<p>Dans votre code vous pouvez ensuite référencer le code en utilisant le même nom:</p>
<figure class="highlight"><pre><code class="language-go" data-lang="go"><span></span><span class="kn">package</span><span class="w"> </span><span class="nx">main</span>
<span class="kn">import</span><span class="w"> </span><span class="p">(</span>
<span class="w"> </span><span class="s">"github.com/noplay/madep"</span>
<span class="w"> </span><span class="s">"github.com/miekg/dns"</span>
<span class="p">)</span></code></pre></figure>
<p>Je trouve cela assez pratique, car on retrouve très facilement le site d’où vient un module.</p>
<h1 id="la-documentation">La documentation</h1>
<p>Pour le moment tous les modules que j’ai utilisés étaient bien documentés avec généralement un readme
qui explique bien l’utilisation du module.</p>
<p>Une commande <em>godoc</em> vous permet d’afficher la documentation et via:</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>godoc<span class="w"> </span>-http<span class="o">=</span>:6060</code></pre></figure>
<p>Vous avez un serveur de documentation un local.</p>
<h1 id="les-goroutines">Les Goroutines</h1>
<p>L’un des éléments qui rend le GO pratique pour la programmation concurrente est
le concept des Goroutines. En effet pour lancer un traitement de tâches de fond
il suffit de rajouté le mot-clef go devant l’appel. La fonction sera lancée en tâche
de fond et votre code continuera son exécution.</p>
<figure class="highlight"><pre><code class="language-go" data-lang="go"><span></span><span class="k">go</span><span class="w"> </span><span class="nx">long_traitement</span><span class="p">()</span></code></pre></figure>
<p>C’est une sorte de thread léger.</p>
<h1 id="les-channels">Les channels</h1>
<p>Pouvoir lancer des tâches de fond c’est bien, mais encore faut il communiquer avec. C’est là
qu’entre en oeuvre le concept de channels. Basiquement c’est un tube dans lequel on écrit d’un
côté et on a une lecture bloquante de l’autre côté.</p>
<figure class="highlight"><pre><code class="language-go" data-lang="go"><span></span><span class="nx">messages</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">chan</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span>
<span class="k">go</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">messages</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s">"hello"</span><span class="w"> </span><span class="p">}()</span>
<span class="nx">msg</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="o"><-</span><span class="nx">messages</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">msg</span><span class="p">)</span></code></pre></figure>
<p>C’est un système simple et qui s’avère efficace à l’usage.</p>
<h1 id="ce-quil-me-reste-à-voir">Ce qu’il me reste à voir</h1>
<p>Je n’ai pas encore testé le déploiement et c’est un point qui peut devenir compliqué
sous Mac OS vu que cela implique de la cross compilation. Il y a aussi un framework de
test fourni que je n’ai pas regardé.</p>
<h1 id="conclusion">Conclusion</h1>
<p>Pour le moment j’ai une très bonne première impression sur GO. Le langage semble robuste
et relativement simple de prise en main. Les concepts pour la programmation concurrente
sont faciles à mettre en oeuvre. Par contre, cela ne remplacera par Ruby ou Python qui ont
du sucre syntaxique qui rend certaines taches plus agréables (l’intégration des regex dans
ruby par exemple).</p>
<p>Le fait de déployer juste un binaire en production me semble une bonne idée quand on voit les
cauchemars dans lesquels on tombe vite lorsqu’on déploie du Ruby, du Python ou du Node.</p>
<p>La syntaxe me plait beaucoup plus que celle du C++ qui offre trop de possibilités ce qui fait qu’on
se retrouve avec autant de C++ que d’endroit où l’on fait du C++.</p>
<p><a href="/premier-jour-go">Premier jour avec GO</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on May 31, 2014.</p>
/blog/nouveau-blog
/blog/nouveau-blog2014-05-10T00:00:00+02:002014-05-10T00:00:00+02:00Julien Duponchellejulien@duponchelle.info<p>Voilà j’ai enfin pris le temps de troquer mon vieux blog sous SPIP avec un nouveau sous Jekyll.
C’est l’occasion d’un gros redesign.</p>
<p>On oublie donc le vieux squelette:
<img src="/images/old.julien.duponchelle.info.png" alt="" /></p>
<p>Pour un thème dérivé du thème HMFAYSAL OMEGA avec un look plus moderne. Et a moi le plaisir de blogguer en statique.</p>
<p>J’ai surement cassé plein de truc au passage lors de la migration et je vais réparer au et à mesure.</p>
<p><a href="/blog/nouveau-blog">Nouveau blog</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on May 10, 2014.</p>
/cassandra/mysql/Cassandra-MariaDB-Virtual-Box-images
/cassandra/mysql/Cassandra-MariaDB-Virtual-Box-images2012-10-06T00:00:00+02:002012-10-06T00:00:00+02:00Julien Duponchellejulien@duponchelle.info<p>I made a Virtual Machine images for testing Cassandra integration in MariaDB. This Virtual machine is based on Ubuntu 12.04 with Datastax Cassandra 1.1 version and prebuilt version of MariaDB 5.5.27 + Cassandra from <a href="https://kb.askmonty.org/en/cassandra-storage-engine/">here</a>.</p>
<p>You can get it by using <a href="http://www.vagrantup.com/">Vagrant</a>.</p>
<p>After that run this commands:</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>vagrant<span class="w"> </span>init<span class="w"> </span>cassandramariadb<span class="w"> </span><span class="s2">"http://noplay.net/~noplay/cassandramariadb.box"</span>
vagrant<span class="w"> </span>up
vagrant<span class="w"> </span>ssh</code></pre></figure>
<p>After that:</p>
<p>For loading the sample data:</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>vagrant@mariadb-cassandra:~$<span class="w"> </span>cat<span class="w"> </span>create_keyspace.cql<span class="w"> </span><span class="p">|</span>cqlsh<span class="w"> </span>
vagrant@mariadb-cassandra:~$<span class="w"> </span>cat<span class="w"> </span>create_database.sql<span class="w"> </span><span class="p">|</span>mysql<span class="w"> </span>-uroot</code></pre></figure>
<p>Show the data in MySQL:</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>vagrant@mariadb-cassandra:~$<span class="w"> </span>mysql<span class="w"> </span>-u<span class="w"> </span>root
use<span class="w"> </span>blog<span class="p">;</span>
SELECT<span class="w"> </span>posts.message,users.name<span class="w"> </span>FROM<span class="w"> </span>posts,users<span class="w"> </span>WHERE<span class="w"> </span>posts.user<span class="w"> </span><span class="o">=</span><span class="w"> </span>users.id<span class="p">;</span></code></pre></figure>
<p>Show the data in Cassandra:</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>vagrant@mariadb-cassandra:~$<span class="w"> </span>cqlsh<span class="w"> </span>
cqlsh><span class="w"> </span>use<span class="w"> </span>blog<span class="p">;</span>
cqlsh:blog><span class="w"> </span>SELECT<span class="w"> </span>*<span class="w"> </span>FROM<span class="w"> </span>posts<span class="p">;</span></code></pre></figure>
<p>And voilà :)</p>
<p><a href="/cassandra/mysql/Cassandra-MariaDB-Virtual-Box-images">Cassandra MariaDB Virtual Box images</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on October 06, 2012.</p>
/d%C3%A9veloppement/Trouver-la-sitemap-d-un-site
/d%C3%A9veloppement/Trouver-la-sitemap-d-un-site2011-09-25T00:00:00+02:002011-09-25T00:00:00+02:00Julien Duponchellejulien@duponchelle.info<p>Lorsqu’on veut indexer un site il peut être utile de partir de la sitemap du site qui est justement faite pour cela.</p>
<p>Tout d’abord vous pouvez regarder dans le fichier robots.txt si il y a une section sitemap:</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>Sitemap:<span class="w"> </span>http://example.com/sitemap.xml</code></pre></figure>
<p>Si la sitemap n’est pas référencé il vous reste une chance. Il est possible que le webmaster ai soumis la sitemap à google. Vous pouvez le savoir en tapant cette requête:</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>site:example.com<span class="w"> </span>filetype:xml<span class="w"> </span>OR<span class="w"> </span>filetype:gz</code></pre></figure>
<p><a href="/d%C3%A9veloppement/Trouver-la-sitemap-d-un-site">Trouver la sitemap d'un site</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on September 25, 2011.</p>
/android/Intercepter-les-touches-de-volumes
/android/Intercepter-les-touches-de-volumes2010-12-01T00:00:00+01:002010-12-01T00:00:00+01:00Julien Duponchellejulien@duponchelle.info<p>Si vous souhaitez changer le comportement des touches de volumes de votre téléphone android. Vous pouvez implémenter les méthodes onKeyDown et onKeyUp dans votre activité.</p>
<p>Il faut surcharger les deux méthodes. onKeyDown empêchera le changement de volume et onKeyUp empêchera les sons de notifications de changement du volume.</p>
<p>Le return true dans ces deux méthodes permet de dire que vous avez intercepté l’événement.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span></span><span class="nd">@Override</span>
<span class="kd">public</span><span class="w"> </span><span class="kt">boolean</span><span class="w"> </span><span class="nf">onKeyDown</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">keyCode</span><span class="p">,</span><span class="w"> </span><span class="n">KeyEvent</span><span class="w"> </span><span class="n">event</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">keyCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">KeyEvent</span><span class="p">.</span><span class="na">KEYCODE_VOLUME_DOWN</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">true</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">keyCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">KeyEvent</span><span class="p">.</span><span class="na">KEYCODE_VOLUME_UP</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">true</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kd">super</span><span class="p">.</span><span class="na">onKeyDown</span><span class="p">(</span><span class="n">keyCode</span><span class="p">,</span><span class="w"> </span><span class="n">event</span><span class="p">);</span>
<span class="p">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span><span class="w"> </span><span class="kt">boolean</span><span class="w"> </span><span class="nf">onKeyUp</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">keyCode</span><span class="p">,</span><span class="w"> </span><span class="n">KeyEvent</span><span class="w"> </span><span class="n">event</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">keyCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">KeyEvent</span><span class="p">.</span><span class="na">KEYCODE_VOLUME_DOWN</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">true</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">keyCode</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">KeyEvent</span><span class="p">.</span><span class="na">KEYCODE_VOLUME_UP</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">true</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kd">super</span><span class="p">.</span><span class="na">onKeyUp</span><span class="p">(</span><span class="n">keyCode</span><span class="p">,</span><span class="w"> </span><span class="n">event</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p><a href="/android/Intercepter-les-touches-de-volumes">Intercepter les touches de volumes </a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on December 01, 2010.</p>
/android/Detecter-si-une-application-android-tourne-dans-l-emulateur
/android/Detecter-si-une-application-android-tourne-dans-l-emulateur2010-11-28T00:00:00+01:002010-11-28T00:00:00+01:00Julien Duponchellejulien@duponchelle.info<p>Parfois, il est nécessaire de détecter si on se trouve dans l’émulateur. Cela permet par exemple de contourner les limitations réseau de l’émulateur.</p>
<p>Vous pouvez faire cela à l’aide du code suivant:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span></span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="s">"sdk"</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">android</span><span class="p">.</span><span class="na">os</span><span class="p">.</span><span class="na">Build</span><span class="p">.</span><span class="na">PRODUCT</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="c1">//Dans l'émulateur</span>
<span class="p">}</span></code></pre></figure>
<p><a href="/android/Detecter-si-une-application-android-tourne-dans-l-emulateur">Détecter si une application android tourne dans l'émulateur</a> was originally published by Julien Duponchelle at <a href="">Julien Duponchelle</a> on November 28, 2010.</p>